A few tidbits about ifs and gotos and errors

*bug, rather than *goto error, is the way you might do that in ChoiceScript. I use it all the time; it’s really handy.

2 Likes

What happens when you use *bug?

Does it show whatever text you entered there? like

*bug Whoops, that didn't work

?
as if one would have gone with this:

*goto error

*label error
Whoops, that didn't work

?

*bug will make Quicktest stop and tell you what line the “bug” was on. There’s no functional difference between that and your goto/label error. I guess you can tailor-make your own error messages that way, but I usually know what’s up when I get to the line in question.

1 Like

What’s up with all the *line_breaks?

I prefer giving them in examples when I want to have a text look a certain way in the end ^^;
Just in case.

You could use a tailor-made error message to tell you the exact value of the variable you’re checking, or all your variables, so you know what value it was unexpectedly set to, but yeah, the line number is usually going to be most useful for testing. So probably use *bug to start with, then switch to the other method if you can’t figure out the problem.

“Look a certain way,” is right, since standard lineation (i.e., paragraph breaks) would generally be necessary. Sorry, I’m sensitive about this because I’ve had more than one author turn in a first draft with double *line_breaks for every paragraph break (which I think stems from a misreading of the wiki…). *line_break should never been seen in a CoG unless it’s for a list, a signature on a letter, or weird (like Rent-A-Vice).

1 Like

Or verse–I use a lot of *line_breaks for song lyrics and verse. Maybe that falls under “weird.”

1 Like

Ah, good that you mention it:

Word of caution:
Using two *line_break instead of a free line (with appropriate indentation) causes screenreader to stumble iirc

Yes, or verse.

It would be nice if we could get the wiki edited to indicate that:

  • Double *line_break is not how you should try to get a completely blank line, generally. That paragraph breaks should be done with two hard returns.
  • Double *line_break breaks screen readers.
3 Likes

While big chains of *ifs can be used, *elseif and *else are better suited for more complex examples and since they can achieve the same as chains of *ifs anyway, they are generally regarded as a better practice. Note how I’m saying it is considered a better practice, not a rule. This practice can be disregarded, but let me explain why I stick to it.

Let’s try to do the same thing with both methods, using *if only and using *elseif/*else.


We are gonna shop for computer mice, but we will take a few considerations for our spending.

If they are red we will buy 10;
otherwise if they cost less than 50, we buy 8;
otherwise we buy only 4.

(For clarity, I have removed unecessary *gotos and *labels from the following examples.)


Example A:

*if (mouse_color = red)
	*set items_bought + 10
*elseif (mouse_price < 50)
	*set items_bought + 8
*else
	*set items_bought + 4

If you wanted to do this just using multiple *ifs, things would be more complicated to read because you would need to negate the previous conditions manually.

Example B:

*if (mouse_color = red)
	*set items_bought + 10

*if (mouse_color != red) and (mouse_price < 50)
	*set items_bought + 8

*if (mouse_color != red) and (mouse_price >= 50)
	*set items_bought + 4

Due to the logic structure of *elseif, it is not necessary to include the negatives of the previous conditions since these checks are only reached when these negatives are achieved. With more complex logic the negative conditions we’d have to manually input could cascade quickly.

A second consideration is that due to the way the rest of the chain is skipped once one condition is reached, it leads to better efficiency. With the *if example it will check all the conditions regardless. Since computers are so fast this difference is not noticeable to us (unless its a really, really big chain) so this is usually disconsidered.


So, even for simpler codes, like:

Example C:

*if (items_bought >= 5)
	You bought quite a lot of things today.
*else
	You didn't bought that many things today.

Example D:

*if (items_bought >= 5)
	You bought quite a lot of things today.
*if (items_bought < 5) 
	You didn't bought that many things today.

The use of *elseif/*else is still more efficient for two reasons:

  1. Processing efficiency; the second check won’t even be considered, so the code will progress faster (imperceptible for a human, but it’s there).
  2. Easier for the coder; they would need to manually enter the negative of the first condition, possibly even typing the wrong one. With *else that is handled automatically.

However, ChoiceScript in particular does include one negative in using example C:

  • Regardless of branching or not, the coder is required to create an extra *label and *goto right after the usage of *else.

So a lot of people use example D instead of C simply to avoid this. This particularity can be removed by the use of the Implicit Control Flow modification; if that is done, I don’t see any reason to use example D instead of C.

Further documentation on this optional feature is available below:


Good idea, I’ll see if I can include that. When I was starting out I had no idea that double *line_breaks broke screen readers, so I agree that this is important to add.

In fact I do use double *line_breaks if I’m inside an indent (such as inside an *if or *choice) due to the way I’m used to seeing blank lines as something that it’s still incomplete (I used to compact my code in Java to remove blank lines); a second reason being to easily see if the line is indented properly or not. But I intend to remove that from my whole game’s code soon by using search and replace.

5 Likes
Pot of Greed (coding example)
*temp yugioh 1

*label memeloop

*if (yugioh >= 22)
 "But what does Pot of Greed do?"
 *ending

*if (yugioh >= 21)
 "I activate my Pot of Greed magic card. Now I can draw two more cards from my deck!

*if (yugioh >= 20)
 "I play Pot of Greed. You know what that means, don't you? I can draw two additional cards from my deck."

*if (yugioh >= 19)
 "First I'll play a magic card known as Pot of Greed, so I draw two cards!"

*if (yugioh >= 18)
 "I'll begin by activating my Pot of Greed. This lets me draw two more cards."

*if (yugioh >= 17)
 "First, I'll play my Pot of Greed magic card letting me draw twice."

*if (yugioh >= 16)
 "Then I'll activate my Pot of Greed! This lets me draw two cards."

*if (yugioh >= 15)
 "Now, I activate my Pot of Greed magic card so I can draw two cards."

*if (yugioh >= 14)
 "Next, I activate the magic card Pot of Greed! Now I can draw two more cards."

*if (yugioh >= 13)
 "Pot of Greed lets me draw two cards from my deck."

*if (yugioh >= 12)
 "I'll play a magic card; my Pot of Greed. It lets me draw two cards."

*if (yugioh >= 11)
 "This could be exactly what I needed! Now I activate Pot of Greed which lets me draw two cards. I just hope these two cards can help me out."

*if (yugioh >= 10)
 "I activate the magic card Pot of Greed! It allows me to draw two more cards."

*if (yugioh >= 9)
 "Excellent. I play this: Pot of Greed! It allows me to draw two new cards to refresh my hand."

*if (yugioh >= 8)
 "Now I'll play the magic card Pot of Greed, allowing me to draw two more cards."

*if (yugioh >= 7)
 "I think my luck is beginning to change now. Pot of Greed lets me draw two cards."

*if (yugioh >= 6)
 "I play my Pot of Greed card."

*if (yugioh >= 5)
 "I'll play this. My Pot of Greed. A magic card that allows me to draw two more cards from my deck."

*if (yugioh >= 4)
 "The magic card Pot of Greed. Thanks to this card I can now draw two new cards from my deck."

*if (yugioh >= 3)
 "I play the magic card Pot of Greed. It allows me to draw two cards from my deck."

*if (yugioh >= 2)
 "I activate Pot of Greed. This card allows me to draw two new cards. Greed is good."

*if (yugioh >= 1)
 [b]- Pot of Greed -[/b]

*label advance
*set yugioh +1
*page_break
*goto memeloop

GS. Icf and how discouraging it can be is one of the other reasons I made this thread.

I see you and other’s jump into threads so often going “use icf” without any/much in terms of explaining why the user got an error and stuff, left alone offering an alternativd thus likely making a user feel stupid and discouraging them from coding further.

I made it clear this is not a rule and explained why I use it this way.

I did plenty of explanation above, please don’t go after me and go after what I wrote instead.

About pros, cons, errors and alternatives please check the documentation link I provided, your concerns are listed there.

I edited my post, kindly take that into account.

Edit: when i see the threads though I usually get the sense that you try to drive people from usibg other methods.
Also, I’m not very keen on the “here’s this solution, why it works is elsewhere” approach this strikes me as.

What I’d like to do here is show why the code does a thing it does… or why it doesn’t do so when it should.
(Not to mention the wiki can be hella confusing AND a number of entries are lacking examples)

If not for people like fiogan and others I know I would not be able to code a lot of the stuff I did so far.

The short of it is that ICF more-or-less tells the computer to put in gotos(well, it ends up more-or-less the same by the time you launch the game) for you. This means you don’t have to write them yourself, but it also means that the computer isn’t going to tell you that you forgot one that’s supposed to go somewhere besides where the computer automatically puts it

The other thing is that it’s generally not advised to use gotos directly because it makes it hard to be sure any particular thing has happened prior to reaching the label, which can end very badly. So modern languages have various complex ways to restrict where you can go to a specific block of code from, thus making it easier to ensure things like “X is an integer between 1 and 4” when you reach a location. Most basically there’s Break and Continue, which are basically just gotos with very tight rules about where they can be used and where they go to (also they have a default label). They can still be trouble, but are relatively easy to keep track of, and are used in Switch statements for basically the scenario of “X is one of these values and we want to do something different for each one”.

There are definitely fans of ICF and fans of not-ICF here, and we must all live together in peace and harmony, banding together against the larger forces of darkness that beset us.

8 Likes

This is what I’m so upset about (sorry about getting so worked up about this).

I see it often that people had trouble with if-elseif trees and the goto-solution (no pun intended) was to say ‘use icf’ instead of saying
‘At this spot you should put a goto (too) to tell the code where it should go’
or similar

On that note, and looking back at GS’ example:

Does

*if not (var)

fulfill the same purpose as *else there?

@Gower I can’t be the only one getting A:TLA flashbacks here.

1 Like

I think that if you do

*if var
*if not (var)

sometimes Quicktest will throw an error because it doesn’t always realize that A and not A covers all cases. So *else will prevent that. Logically it should be the same, I think, I find *else prevents Quicktest freaking out at times.

2 Likes