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

%WHATDOESITAFFECT%
edit

Implementation

-- Contributors: KipLubliner - 05 Feb 2012

Discussion

Fantastic to see this finally implemented smile

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

 
Topic revision: r14 - 17 Feb 2012, KipLubliner
The copyright of the content on this website is held by the contributing authors, except where stated elsewhere. See Copyright Statement. Creative Commons License    Legal Imprint    Privacy Policy