Feature Proposal: Create mechanism for switch statements
Motivation
The IF macro is inconvenient for building if / else ladders. Additionally, there should be a convenient mechanism for evaluating an expression and testing it against multiple different values.
Description and Documentation
More complicated conditional processing.
Compare an expression against multiple values (Java / C type select statement)
%SWITCH{"expression_to_test"
equals1="first value checked"
result1="result if equals1 matches"
equals2="second value checked"
result2="result if equals2 matches"
...
default="result if none match"}%
Evaluate conditional statements sequentially (if / elsif ladder)
%SWITCH{""
if1="first if statement"
result1="result if if1 is true"
if2="second if statement"
result2="result if if2 is true"
...
default="result if none match"}%
Mix of the above
%SWITCH{"expression_to_test"
if1="first if statement using $switch"
result1="result if if1 is true"
equals2="second value to check"
result2="result if if2 is true"
...
default="result if none match"}%
Examples
| %SWITCH{"%QUERY{"'%BASEWEB%.%BASETOPIC%'/META:RSVP[name='%PLAYER%'].playing"}%"
if1=" '$switch' = 'YesIf' AND '%BASEWEB%.%BASETOPIC%'/META:RSVP[name='%PLAYER%'].GettingRideFrom != 'Nobody' "
result1="Yes"
equals2="YesIf"
result2="Needs a ride"}% \
| %SWITCH{"%QUERY{"'%BASEWEB%.%BASETOPIC%'/META:RSVP[name='%PLAYER%'].driving"}%"
equals1="CanPickup"
result1="$percentINCLUDE{\"%TOPIC%\" section=\"tablerow_canpickup\" PLAYER=\"$percentPLAYER$percent\"}$percent"
equals2="NeedsRide"
result2="$percentINCLUDE{\"%TOPIC%\" section=\"tablerow_needsride\" PLAYER=\"$percentPLAYER$percent\"}$percent"
default=""}% \
|
Impact
Implementation
--
Contributors: KipLubliner - 05 Feb 2012
Discussion
Fantastic to see this finally implemented
I'd like to see
QuerySearch expressions in the
equalsN
params, but I guess we can add that later as a
query1
,
query2
, etc. equivalent (I wonder what it should if both
queryN
and
equalsN
are supplied?)
--
PaulHarvey - 05 Feb 2012
I am not that comfortable with the n syntax. Wouldn't this be possible using guards? Expressions could be checked sequentially:
%CASE{
"'X'"
"ingroup 'Y'" then="'X' is in group 'Y'"
"ingroup 'Z'" then="'X' is in group 'Z'"
otherwise="'X' is in neither group"
}%
This is more or less in line with
IF
statements, and it should. Switch/case is syntactic sugar after all.
So this would be equal to:
%IF{
"'X' ingroup 'Y'"
then="'X' is in group 'Y'"
else="%IF{
"'X' ingroup 'Z'"
then="'X' is in group 'Z'"
else="'X' is in neither group"
}%"
}%
--
ArthurClemens - 05 Feb 2012
Kip, +1 for tackling this one. It's been a-begging for years.
Paul, it's using the %IF parser so I can't see why you think it doesn't implement query expressions already (since %IF does).
I agree with Arthur that the syntax is a bit clumsy. We have always resisted making macros support multiple attribute values for the same named attribute, but the reason is weak; sheer laziness. There is no API on the Foswiki::Attrs class to support it, and one would have to be added. If we did this, and mandated ordered evaluation of said attributes, then I can't see why we need a new macro; %IF could be extended. For example,
%IF{
"Field=1"
then="One"
elsif="Field=2"
then="Two"
elsif="Field=3"
then="Three"
else="More"
}%
Simpler than case/switch, and much more perlish.
--
CrawfordCurrie - 06 Feb 2012
After an enlightening chat with
PaulHarvey and
SvenDowideit I came to the realization that the if/elsif/else ladder
was at the heart of my proposal, and it probably does make sense to ... put it in the %IF macro. However, this does miss something quite nice with my switch statement: the idea that you can do a verbose calculation
once, and then re-use that value in subsequent conditional checks. Here is an idea about how that could be done cleanly by introducing a new macro called LET:
%LET{a="%QUERY{ .... }%" b="%QUERY{ ... }%"
"%IF{
"$a=1"
then="One"
elsif="$a=2 and $b ~ 'New York Football Giants'"
then="Two"
elsif="$a=3"
then="$b"
else="More"
}%"}%
This would also have another
sorely needed use-case, assigning variables for re-use:
%LET{aaaa="%CALC{ ... }%" bbbb="%QUERY{ ... }%"
"
... many lines of TML that use $aaaa and $bbbb (you better pick nice long names in this scenario) ....
"}%
--
KipLubliner - 06 Feb 2012
Instead of %LET there's already a %SET being accepted but not yet implemented as proposed in
SettingAndGettingVariablesUsingMacros
--
MichaelDaum - 06 Feb 2012
%SET will address the second use-case of %LET, but not the first. %LET explicitly limits the scope of the variable, so it is well suited for "quickee" temp variables to be subject to conditionals. I think that both are needed.
--
KipLubliner - 06 Feb 2012
Argh, let's keep this focused (on the switch/if-tree case) please, and discuss %LET elsewhere.
Your argument for the switch statement is a good one, I hadn't thought of the single-evaluation optimisation. I'd still prefer the if-elsif-tree in %IF if it was a case of one or t'other, though. %SWITCH is really just making a special case of the "equals" test in %IF, and could be expressed differently e.g.:
%IF{"FieldName" eq="1" then="One" elseq="2" then="Two" elseq="3" then="Three" }%
--
CrawfordCurrie - 06 Feb 2012
Hm, %SET
is indeed for quick temp variables, not for persistent preference settings. Values of a %SET are stored while parsing TML top down.
Not sure what the first and second use case of %LET is (am I too lazy/dumb to read the above conversation correctly?).
About SWITCH being unperlish: doesn't Moderl Perl have an explicit switch-case construct?
--
MichaelDaum - 06 Feb 2012
Perl has
given/when, FWIW. 5.10+
--
PaulHarvey - 07 Feb 2012
Michael: My point is that the proposed %LET macro explicitly limits the scope - the new variable names are only accessible within the default parameter. In comparison, %SET has scope for all subsequent TML following the %SET.
I will update the proposal to only contain the enhancement to %IF to allow elsif. This discussion has led me to the conclusion that my original idea about %SWITCH had too much stuff jumbled together. The %LET macro should have a separate proposal.
--
KipLubliner - 07 Feb 2012
I made a brainstorming topic with my thoughts - see
OptionsForEnhanceIfStatementsAndAttrsParsing.
--
KipLubliner - 11 Feb 2012
I Parked this proposal. See new proposal at
EnhanceIfStatementsAndAttrsParsing
--
KipLubliner - 17 Feb 2012