Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Case/Switch


  • Please log in to reply
44 replies to this topic
ComradeF
  • Members
  • 42 posts
  • Last active: Dec 23 2005 12:44 AM
  • Joined: 16 May 2005

A simple select/switch/case structure as an alternative to a series of ""else if"" statements. This might also help with the lack of support for the OR conjunction.

When do you think you'll get around to this?? :shock:
Windows XP SP2

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
I think you're right that this is important. I'll try to get it done within the next 30 days.

It will probably be of the following syntax unless someone has a better idea:
switch MainExpression
{
case expression1:   ; i.e. if MainExpression matches this, its commands will run.
     ...commands...
     break
case expression2:
     ...commands...
     break
default:   ; If MainExpression doesn't match any of the above cases, this happens.
     ...commands... 
}


ComradeF
  • Members
  • 42 posts
  • Last active: Dec 23 2005 12:44 AM
  • Joined: 16 May 2005
Looks great to me!
Windows XP SP2

Nemroth
  • Members
  • 278 posts
  • Last active: Dec 31 2011 10:53 PM
  • Joined: 07 Sep 2004
Glad to see that this feature will be implemented soon. Thanks a lot Chris.

ComradeF
  • Members
  • 42 posts
  • Last active: Dec 23 2005 12:44 AM
  • Joined: 16 May 2005
You might want to allow us brackets for the cases, as well. It feels cleaner sometimes.

case "a":
{
	commands...
	Break
}

Windows XP SP2

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Thanks. Hopefully that will work automatically because blocks/braces can already be used anywhere, even if there is no if/else/loop/function above them.

JBensimon
  • Members
  • 167 posts
  • Last active: May 08 2017 10:25 PM
  • Joined: 16 Nov 2004

It will probably be of the following syntax unless someone has a better idea:

switch MainExpression 
{ 
case expression1:   ; i.e. if MainExpression matches this, its commands will run. 
     ...commands... 
     break 
case expression2: 
     ...commands... 
     break 
default:   ; If MainExpression doesn't match any of the above cases, this happens. 
     ...commands... 
}

For the sake of syntactic symmetry, you may want to consider providing a variable (e.g. A_CaseValue) that reflects the result of "MainExpression" so that, among other possible uses, you can do away with the special label
default:
in favor of
case A_CaseValue:
Unrelated to the above, a question: I assume the use of "Break" in the sample syntax means that command execution will otherwise "fall through" from one case to the next. In this scenario, would the intervening case expressions be evaluated or would they be skipped (which matters if they involve functions with side effects)?

Jacques.

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004

For the sake of syntactic symmetry, you may want to consider providing a variable (e.g. A_CaseValue) that reflects the result of "MainExpression" so that, among other possible uses, you can do away with the special label

default:
in favor of
case A_CaseValue:

That is great. There have been numerous times when I have to scroll back up to the top of a long switch() to find out what it was switching on so that I can write a sub-switch or an if/then involving the switch's main expression. The word "default" might still be more readable than "case A_CaseValue", but perhaps both can be supported.

I assume the use of "Break" in the sample syntax means that command execution will otherwise "fall through" from one case to the next. In this scenario, would the intervening case expressions be evaluated or would they be skipped (which matters if they involve functions with side effects)?

That's a very good point. Clearly for performance reasons they should be skipped. If it's not to difficult, I'll try to ensure that this happens.

Another thing that might be quite nice is to entirely get rid of "break" within the switch(). This is because although the "fall through" behavior sounds nice in principle, I think it is hardly ever used except with cases that are immediately adjacent to each other. If this is done, adjacent cases would have to become a special exception that is recognized as a "conglomerate case". One problem with this idea is how to have a case that does nothing as a means to avoid the default section. Perhaps an empty pair of braces would serve.

Another advantage of avoiding "break" is that a switch() could use "break" to exit any loop that encloses it.

Do you see any problems with avoiding "break"?

ComradeF
  • Members
  • 42 posts
  • Last active: Dec 23 2005 12:44 AM
  • Joined: 16 May 2005
MAYBE you could add both case AND switch... and they could do different things.

One of them could utilize breaks, and the other could skip them. I was trying to think of a reason to NOT avoid using 'break', but I couldn't think of one because the entire point of this case/switch is to choose ONE condition, perform its results, and be done. But other languages require the 'break' in there because the script will keep performing all the conditions that follow unless you add breaks. It's sort of an inversed if-else chain -- a weird concept I guess, but perhaps it could be useful sometime.

I have no idea. Just brainstorming. But if you're only going to add it one way, I don't think we really need required breaks. It's implied.
Windows XP SP2

JBensimon
  • Members
  • 167 posts
  • Last active: May 08 2017 10:25 PM
  • Joined: 16 Nov 2004

Another thing that might be quite nice is to entirely get rid of "break" within the switch().

I tend to agree: on the one hand, eliminating "fall-through" removes a capability from the language, but on the other hand (1) the capability in question is rarely useful, (2) the syntax is simplified, and (3) it makes the "switch" feature more intuitive for beginners (I think people would tend to forget about the need for "break"). Members of these forums may have other thoughts however: there might be some popular algorithms out there that rely on fall-through behavior. Maybe you could decide based on whichever seems most efficient (or easiest) from an implementation standpoint...

One problem with this idea is how to have a case that does nothing as a means to avoid the default section.

I'm not sure I understand: in the absence of fall-through, wouldn't a "case expressionX:" followed immediately by another have the effect of doing nothing for that case? ... or were you planning to interpret consecutive "case expression:" lines as a sort of "OR construct" applying to the same set of commands? If so (which by the way is a special case of fall-through behavior), a do-nothing case could still be achieved either with your empty braces idea (the empty statement) or with other do-almost-nothing commands like "Sleep, 0".

Another advantage of avoiding "break" is that a switch() could use "break" to exit any loop that encloses it.

Very true. It's actually always bothered me somewhat (in all structured languages that offer some sort of break feature) that it is capable only of escaping from the innermost "structure" in which it is found. Couldn't "break" (theoretically) take a numeric parameter indicating the number of structures from which to escape? (i.e. "Break, 1" would be equivalent to "Break", "Break, 2" would mean "Break then Break again", etc.) Not that I personally mind using "GoTo" all that much... :-)

Later,

Jacques.

JBensimon
  • Members
  • 167 posts
  • Last active: May 08 2017 10:25 PM
  • Joined: 16 Nov 2004

A_CaseValue

That was a poor naming suggestion. Since the overall construct is a Switch (not Case) statement, I should have suggested "A_SwitchValue" (or something else with "switch" rather than "case" in the name).

Jacques.

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004

...or were you planning to interpret consecutive "case expression:" lines as a sort of "OR construct" applying to the same set of commands?

Yes, that's it.

By the way, although the lack of a need for "break" has the big advantages mentioned above, it also has one fairly serious drawback: Anyone used to programming in C-like languages will find themselves using "break" automatically. This will cause script bugs that might be hard to detect whenever a switch() is enclosed in a Loop (since the break would exit the loop rather than the switch).

Couldn't "break" (theoretically) take a numeric parameter indicating the number of structures from which to escape?

This idea is already on the to-do list. It's might be a little complicated to implement, but I think it would be worthwhile.

Thanks.

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
The more I think of it, the more I find it redundant and obsolete...
Obviously, IF expressions became more powerful with expressions since the time the topic was created: we have OR, AND, NOT, etc.

Using Switch/Case may please those coming from C and related languages, but if it is necessary and performant in C (optimized machine code jumping to right location), it is probably inefficient for interpreted languages.

A similar discussion was raised in the Lua list, and many shown that this can be done natively within the language. AutoHokey doesn't have functions as first class citizen (Lua can put functions in tables, pass them as parameter and return value, etc.), but has powerful IF expressions that can do something similar, or even more flexible. Remember that C switches are limited to numbers, only one of them per case. Pascal allows ranges. Better, not perfect.

JSLover shown that you can do that in pure AHK, keeping the switch syntax for those hooked to it.

AutoHotkey allows cases to have multiple values, sub-strings and values in a range:
a = Droopy
a = Foobar
a = flat iron

If a in Snoopy,Doopey
	MsgBox One
Else If a contains Foo,Bar
	MsgBox Two
Else If a = Droopy
	MsgBox Three
Else If a between anvil and hammer
	MsgBox Four
Else
	MsgBox Other
I even didn't used expressions...
For those still wanting such a command, what would it provides beyond that? The only problem is the repetition of the variable. But if the variable name is long, you can make a temporary shorter one.
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

Demokos
  • Members
  • 105 posts
  • Last active: Jan 20 2011 06:28 PM
  • Joined: 28 Dec 2005

A simple select/switch/case structure as an alternative to a series of ""else if"" statements. This might also help with the lack of support for the OR conjunction.

I'm agree it isn't a necessity nor an high priority, but I think it makes the code more readable, witch is a good thing.

I prefer to see :
a = flat iron

Select a
Case in Snoopy,Doopey
	MsgBox One
Case contains Foo,Bar
	MsgBox Two
Case = Droopy
	MsgBox Three
Case between anvil and hammer
	MsgBox Four
Default
	MsgBox Other
rather than

a = flat iron

If a in Snoopy,Doopey
	MsgBox One
Else If a contains Foo,Bar
	MsgBox Two
Else If a = Droopy
	MsgBox Three
Else If a between anvil and hammer
	MsgBox Four
Else
	MsgBox Other

I think it is a more concise and readable notation.

And probably internaly it is not someting very complicated to do, as may be (a part of) the code used for the If ... Else If structure may be used for the case one. May be I'm wrong...

For the JSlover "solution", I think it's, as we say in our beautifull country, "un emplâtre sur une jambe de bois" !!!! (a plaster on a wooden leg) (Sorry JSLover, absolutely no offense !!!)

I can't see how

switch(test)
	if case(1)
		...
	else if case(2)
     ....

can be more readable than
switch a
	Case = 1
		...
	case = 2
     ....
But again for me it isn't a necessity nor a priority. Just something more readable.

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
Mmm, that's a matter of taste, so arguing over it is probably a waste of time :-P

Some remarks:
- Your proposal make sense (if switch is to be implemented) and is (more or less) consistent with current syntax: there is no real need for the colons (end of line marks the end of the case, unlike in C where you can stack the whole switch on one line...); but marking the scope of the switch with braces seems sensible.
- I prefer Case Droopy instead of Case = Droopy
- There is no break, so no fallthrough. I think this is better: if some code is common to several cases, you can put it in a function or a Gosub target.
- The advantage isn't paramount, unless the variable name is very long, but you can take a shorter (temporary) name for the construct
- A similar shortening could be achieved with a ElseIf or Elif keyword.
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")