Posts: 4,607
Threads: 543
Joined: Dec 2009
09-24-2018, 02:28 AM
(This post was last modified: 09-24-2018, 02:30 AM by kyonides.)
Sometimes we want to do things the hard way because we either ignore what we are doing or somebody is hiding something from us or because nobody was thinking out of the box. I bring you an example on C++ and Ruby.
Here's the first part of our C++ code that will enable our IDE or stuff that makes the compiling and linking needs badly.
Code: #include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
I won't enter into details up there for a good reason.
Let's try to make a number print the month we picked
Code: const char* int2month(int month)
{
cout << month << " or ";
const char* pointer_value;
switch(month)
{
case 1: pointer_value = "January";
break;
case 2: pointer_value = "February";
break;
case 3: pointer_value = "March";
break;
case 4: pointer_value = "April";
break;
case 5: pointer_value = "May";
break;
case 6: pointer_value = "June";
break;
case 7: pointer_value = "July";
break;
case 8: pointer_value = "August";
break;
case 9: pointer_value = "September";
break;
case 10: pointer_value = "October";
break;
case 11: pointer_value = "November";
break;
case 12: pointer_value = "December";
break;
default: pointer_value = "Invalid value!";
}
return pointer_value;
}
Then you should just make some int main function to include the call to this function of ours and display the result on our console alias CMD (MSDOS shell) or Konsole (if using KDE based GUI for Linux distros).
Code: int main()
{
cout << "Current Month is " << int2month(9) << "." << endl;
}
Then you would a text telling you "Current Month is (number) or (month name)."
[rant]Obviously including the break statements after each case is a pain you know where![/rant]
Then somebody tells you there's an easy way to deal with it... Really? Then why didn't you tell us about it from the very beginning!?
Code: const char* int2month(int month)
{
cout << month << " or ";
const char *const months[] = {
"invalid",
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
};
if (month < 1 || month > 12)
{
return "invalid";
}
return months[month];
}
But why would we make things that complicated? Use a ternary condition instead!
Code: const char* int2month(int month)
{
cout << month << " or ";
const char *const months[] = {
"invalid",
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
};
return (month < 1 || month > 12) ? months[0] : months[month];
}
Really, whoever can't see the beauty of ternary conditions is dead meat already!
Here's the same code in Ruby:
Code: def int_month(month)
current_month = case month
when 1 then "January"
when 2 then "February"
when 3 then "March"
when 4 then "April"
when 5 then "May"
when 6 then "June"
when 7 then "July"
when 8 then "August"
when 9 then "September"
when 10 then "October"
when 11 then "November"
when 12 then "December"
else "invalid"
end
puts "Current Month is #{month} or better known as #{current_month}."
end
int_month(9)
It would print out...
"Current Month is 9 or better known as September."
Again there's an easy way to deal with this...
Code: def int_month(month)
months = ["invalid",
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"]
month_name = month.between?(1, 12)? months[month] : months[0]
puts "Current Month is #{month} or better known as #{month_name}."
end
int_month(9)
And you would get the very same output as in the example above. And yeah, Ruby is a cutie!
Nope, you wulfo, I'm not talking about some Texan TV animated series at all!
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9
Maranatha!
The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.
My Original Stories (available in English and Spanish)
List of Compiled Binary Executables I have published...
HiddenChest & Roole
Give me a free copy of your completed game if you include at least 3 of my scripts!
Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Posts: 11,235
Threads: 650
Joined: May 2009
09-24-2018, 04:31 PM
(This post was last modified: 09-24-2018, 04:40 PM by DerVVulfman.)
There's doing things the hard way, and doing things the error-free way.
While you may feel the ternary condition would be easier, it can generate errors if incorrect data was passed into the method. As such, a command of "int_month('Fred')" would crash the system as your system as you would generate a data comparison error that wasn't accounted for.
However, your earlier case...end method is safer. Using the script call "int_month('Fred')" would return the 'Invalid' month message of "Current Month is Fred or better known as invalid." The case method doesn't necessarily require data to be of one format or another, so it can return the invalid response if incorrect data was passed.
However, you could add a mere single line to fix this issue, one that ensures the data passed is an integer. In the example below, I added the statement of "month_int = month.to_i" which takes your passed data and converts it before pushing it into 'month_int' ... or month-as-integer.
Code: def int_month(month)
month_int = month.to_i
months = ["invalid",
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"]
month_name = month_int.between?(1, 12)? months[month] : months[0]
puts "Current Month is #{month} or better known as #{month_name}."
end
Of course, I also had to change the later 'month_name = ...' statement to accommodate the new value. However, the new statement prevents the method from breaking.
Error detection and prevention is certainly top priority. There can always be different ways to write a piece of code, and 'truthfullly", the ternary method can always expand what data can be passed if the array of months (in this example) had more months pushed into it. The case...end method is more rigid and wouldn't let you test any more data than what is coded in comparison. However, the ternary method in your example does requires that the data being tested must be integer in nature.
EDIT: For those unaware, 'puts' is an actual statement in the IO (input/output) class for file processing. You could use 'p' if you just want it shown on the screen.
Up is down, left is right and sideways is straight ahead. - Cord "Circle of Iron", 1978 (written by Bruce Lee and James Coburn... really...)
Above are clickable links
Posts: 2,507
Threads: 75
Joined: Dec 2010
Soaking this all up. Not my current language but the method makes sense.
Gotta learn that sweet coder logic.
Any other examples, you guys? This was really interesting.
Posts: 11,235
Threads: 650
Joined: May 2009
Back in the earlier days of programming, coders developed ways to break up a program into smaller units. Back then, they were called 'functions' and 'subroutines'. The differences were that 'functions' returned some value with the data given, while subroutines merely performed a job. Within some languages such as Visual Basic, they had to be actively defined as a function or subroutine. But that is not the case with RUBY where we define them when written with the 'def' (as in define) statement.
Now that THAT is out of the way....
If you have a method (or function, subroutine, code-sammich, whatever), do you have everything in it within a single IF...then block of code? Why? Just look at this section from GAME_MAP. And pardon the indenting....
Code: #--------------------------------------------------------------------------
# * Refresh
#--------------------------------------------------------------------------
def refresh
# If map ID is effective
if @map_id > 0
# Refresh all map events
for event in @events.values
event.refresh
end
# Refresh all common events
for common_event in @common_events.values
common_event.refresh
end
end
# Clear refresh request flag
@need_refresh = false
end
Other than the line with @need_refresh, everything else is in an IF... block. True, it works and works well. But less elegant and kind of sloppy. Instead of performing everything in the method if the condition is true, why not just exit out of the method if it isn't? Of course, the statement of @need_refresh = false must execute either way.
Code: #--------------------------------------------------------------------------
# * Refresh
#--------------------------------------------------------------------------
def refresh
# Clear refresh request flag
@need_refresh = false
# If map ID is effective
return unless @map_id > 0
# Refresh all map events
for event in @events.values
event.refresh
end
# Refresh all common events
for common_event in @common_events.values
common_event.refresh
end
end
Though it reduces the method by merely one line, all the content now requires less indenting which could make the code easier to read.
Up is down, left is right and sideways is straight ahead. - Cord "Circle of Iron", 1978 (written by Bruce Lee and James Coburn... really...)
Above are clickable links
Posts: 4,607
Threads: 543
Joined: Dec 2009
Actually I disagree with your previous correction, wulfo. It's true one should make sure that a method will work as expected, BUT that doesn't mean we should always do things like turning a "Fred" string into a an integer.
The actual way coders work with non web based stuff, where you can get a 404 error message if the webpage could not be found, would be raising an error by calling the raise Kernel method and posting a descriptive error message on screen. It would not be necessary if Ruby were strong typed as C and C++ are, but being weak typed forces Ruby coders to add conditions or raising errors whenever it's needed.
raise would be the best way to tell the coder or game developer that they should go fix the error found in a given line. The backtrace feature was implemented for that very same reason. I hope you already knew about those features and used them accordingly. Otherwise you would have been "stealing" the coder the chance to debug his or her game or code.
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9
Maranatha!
The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.
My Original Stories (available in English and Spanish)
List of Compiled Binary Executables I have published...
HiddenChest & Roole
Give me a free copy of your completed game if you include at least 3 of my scripts!
Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Posts: 11,235
Threads: 650
Joined: May 2009
One wouldn't expect fred would be the accepted data in place of an integer. I used that as a substitute. More likely, the value of 'nil' could be accidentally passed into the method, and the more likely means to create an error.
While you say that some non-web-based programmers were taught to raise an error, others were taught to put safeguards in place to prevent them from occurring. One should merely ensure illegal data doesn't allow the method or function to break the software.
Some should take heed to ensure that such safeguards were put into place. While you suggest the use of raise within the software to report an error, I would suggest that the software be written with safeguards to prevent the errors from even appearing. I am witness to such crashes within the past few months because of a lack of safeguards.
Up is down, left is right and sideways is straight ahead. - Cord "Circle of Iron", 1978 (written by Bruce Lee and James Coburn... really...)
Above are clickable links
Posts: 4,607
Threads: 543
Joined: Dec 2009
The problem with said safeguards is that it doesn't teach the game developer or the scripter what kind of errors they are currently making. What would they get from displaying an invalid month? Nothing plus they wouldn't know where the error is being hidden by the safeguard.
If we were talking about stuff like a disposed bitmap in RGSS that will be soon recreated, safeguards wouldn't be a bad idea for it would skip something that's become unnecessary in that specific case. Passing wrong arguments is a serious mistake and should be treated "harshly" by calling raise. When you add safeguards in let's say C-like code is because you know there will be times where you don't expect the code to find a value worth processing. It's be like and else statement for cases when an actor did not pick a special skill listed in a series of if or case when statements. Then a safeguard would be justified for they should exist too many other skills that don't trigger any special handling like extra animations or attacks.
One of the problems of developing RGSS scripts is that we aren't used to making test units to "programmatically" define if our scripts work as expected without abusing of the overheaded payload of our code while executing. We could say we're still coding empirically sadly.
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9
Maranatha!
The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.
My Original Stories (available in English and Spanish)
List of Compiled Binary Executables I have published...
HiddenChest & Roole
Give me a free copy of your completed game if you include at least 3 of my scripts!
Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Posts: 11,235
Threads: 650
Joined: May 2009
That is not the way I was taught in regards of programming. Then again, I was taught structured languages such as Cobol which is used for business programming.
One should teach a programmer to include safeguards to prevent errors from occurring, not teach them to forego errors so they appear. And whilst my revision of your calendar month code has a safeguard, it still replies with an 'invalid' heading. It doesn't cause a downfall and sudden crash of the program, and still allows the user to see the month title as such. Then again, your code too includes a line ( "invalid",) in the event of an invalid value. Just throw a command of int_month(0) into the system. A month of 0 is invalid, correct?
One should always strive for error-free code, and all functions/methods should be expected to perform with proper data, or recognize data that is invalid and have a way to handle such. Certainly safeguards should be put into place to handle the testing of bitmaps before they are disposed. And of functions and methods receiving values unexpected or not worth processing, one should always account for such events.
I think you should recognize that programming is a mixture of both the logical and empirical. When we study, we observe and run tests for both observation and practice. When we develop a system, we do so with the understanding and logic of how the systems work as our foundation. I would suggest that merely those learning are those coding empirically. However, those that continue will develop their own guidelines and theories how to code based upon such study.
The hard way to code is where one allows errors to constantly creep up because one does not plan ahead. This forces one to repeatedly hunt for the error unseen and constantly make fix after fix. Typos not withstanding.
Up is down, left is right and sideways is straight ahead. - Cord "Circle of Iron", 1978 (written by Bruce Lee and James Coburn... really...)
Above are clickable links
Posts: 4,607
Threads: 543
Joined: Dec 2009
The test units are there to get to those parts that still include errors that desperately need fixes. If we were used to include them, even in RGSS scripting, as coders always recommend, we would be able to properly prevent users to get those weird error messages. Take in consideration that RM game developers aren't scripters usually, that makes scripters get prepared in advance to prevent errors from appearing due to some user's silly mistake or misunderstanding of its actual features.
Safeguards that prevent them from correctly learning how to use script calls or setup a window, etc. would not let them understand why they should get some "Fred" or nil or "---" or "invalid" message on screen while they were expecting some month name or anything else. Since the user would not get the corresponding error message, he or she will come back telling you that YOU should look for the exact line(s) where things go wrong. That would be a difficult task for anybody if you have to check every single place where the player called that scene or method. The error message and its backtrace lets you get there faster than in the previous case.
Why do I keep saying that? Because there's also a custom among coders like those that publish rubygems that makes a script call raise if some user passes some string as a x or y coordinate or as width or height. (That example was taken from gems that let you create custom PNG files!) Coders include their custom Error classes that inherit from StandardError (or some other class depending on their very specific case). Perhaps in compiled languages like C it might look good to include error messages, but you gotta do it in interpreted or precompiled languages like Ruby and RGSS. Those safeguards you're defending here, actually hide defects that lead to incorrect user behavior (based on lack of knowledge or proper instructions).
People, please recall that in strict typed languages, the programmer is capable of troubleshooting his or her own code thanks to built in features in compilers. In those languages the need for raising errors is kind of minimal indeed. (Unless wulfo now prefers to say that a programmer should hide the fact some user was trying to divide a number by zero ) In Ruby we either make things complicated by including too many safeguards or we just implement raise error messages / classes. You might think it's a matter of taste, but I have seen the usefulness of the raised error messages while coding non RGSS stuff. I hope other people get interested in thinking out of the (RM) box and implement them wherever they might help you prevent people from misusing your code. (Especially if they come back telling you that YOU made a mistake not them - without actual evidence of it!)
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9
Maranatha!
The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.
My Original Stories (available in English and Spanish)
List of Compiled Binary Executables I have published...
HiddenChest & Roole
Give me a free copy of your completed game if you include at least 3 of my scripts!
Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Posts: 11,235
Threads: 650
Joined: May 2009
10-03-2018, 03:36 AM
(This post was last modified: 10-03-2018, 03:40 AM by DerVVulfman.)
I think the point you are trying to suggest is that software needs fixing after it is written, and that it is up to the end-users to report where the errors appear. However, it should be up to the software developer to ensure that no bugs appear, no fixes are needed, and no end-users have need to report bugs to the author. Of the third party, an end-user reporting bugs, I have been one to make countless bug reports to a fellow scripter, one that doesn't even test his own work.
Since when are safeguards meant to prevent one from learning how to perform a script call? I think that this notion against safeguards is ill conceived. As I pointed out juet a few hours ago, one could pass improper data into your first ruby terniary example and receive the phrase 'illegal' as a temporary safeguard of its own. Yes, it is helpful to receive pertinent data from the end user if an error appears, but it is up to you as the coder to ensure that no error exists. As to silly mistakes from an end user, it could be that the user erred in using the code. However, proper documentation which I know you loathe is vital. It too is one of the things that I was taught in regards of programming. Instructions should be concise and clear.
I do not argue that the raise system does not have its uses. I too use it for testing the validity of cached graphics. However, my usage of the raise command is to create a safeguard to prevent missing-file crashes. I do not expect nor desire that the end-user be burdened with errors and include the fact that such a feature is in place in these instances. And I would correct you that incorrect user behavior as you call it is based solely on improper instructions and not safeguards. Safeguards would have nothing to do with a user not following instructions, nor lack of proper instructions from the software creator.
I would actually suggest that any coder worth his salt should be able to test his or her own code, regardless of the code being a compiled language like C++ or an interpreted language such as Basic or Ruby. Division by zero is kind of a longshot. However, if a routine or method is put into place where the divisor eventually goes down to a zero value, a safeguard should be crafted to ensure no such error appears and the best-closest value is generated without the need of generating a raise error message. No such raise error message should even be needed. I would look to the programmer for failing to take the time to troubleshoot his own code if countless errors appear.
Up is down, left is right and sideways is straight ahead. - Cord "Circle of Iron", 1978 (written by Bruce Lee and James Coburn... really...)
Above are clickable links
|