Switch Case Construct

Ok, So I have played with the idea of “case structures” in tiddlywiki and as I suspected it really depends on what you want to achieve, display something, return something, transclude something, deal with else cases, return only one value etc…

I can see us documenting a range of case structures without necessarily developing a separate widget, in part because it would be hard to write one that can cater for the large number of possible uses. Here is a simple example;

\define case(input:"d")
<$set name=input filter="[[$input$]uppercase[]]">
<$list filter="[<input>match[A]then[Another]]" template="true"></$list>
<$list filter="[<input>match[B]then[Best]]" template="true"></$list>
<$list filter="[<input>match[C]then[Caught]]" template="true"></$list>
<$list filter="[<input>match[D]then[Default]]" template="true"></$list>
\end

<<case "A">>

Where “true” is a tiddler that displays the current tiddler.

  • The condition ensures one and only one value is returned
  • However every test is made, with a nestable if-then-else structure this could be designed better.
  • To use the result of <<case "A">> other than to display, it must be wikified/evaluated.

I can already imagine a dozen ways to do this, the question is how do we focus on the idea of a Generic Case Statement?

2 Likes

Another example, call macro according to case;

  • With default and error message
  • Case insensitive
  • Should only call the matching macro and exit.
  • The “valid-cases” could be sorted to most likely first if there were a lot of cases.
\define valid-cases() A B C D
\define case(input:"d")
<$set name=input filter="[[$input$]uppercase[]]">
   <$list filter="[enlist<valid-cases>] +[match<input>addsuffix[-case]]" variable=case-macro emptyMessage="Invalid input! (case macro)">
       <$macrocall $name=<<case-macro>> />
   </$list>
</$set>
\end

\define A-case()
A-case
\end
\define B-case()
B-case
\end
\define C-case()
C-case
\end
\define D-case()
D-case
\end


<<case "q">>

I just found Old GG thread https://groups.google.com/g/tiddlywiki/c/wGP5yGWoKgk

2 Likes

Thank you @TW_Tones, very inspiring examples! The first example which uses template gives a lot of flexibility

2 Likes

Your welcome,

What was a use case you had?

While playing with this I saw a lot of alternative possibilities, I suspect one or more will be the most general in nature.

Observations

  • SImple case switches can be hidden away in a macro and simple return a value.
  • More complex case structures that may utilise different wikitext for different inputs will most likely spread through the body of wikitext to make use of inline wikitext when a condition is true or the emptyMessage
  • Filters contain a whole suite of if then and if then else like statements within, in fact the list template (or its content) is if/true and empty message else/false as well.
    • I think this is why the possibility of nested if then else and end-if structures have being neglected somewhat.

In conclusion if we had a way to represent;

nested if then else and end-if structures

It would be easier to represent clearly quite a few other coding or logical structures, and use them in various contexts.

Look at this example;

<$list filter="condition" template="""
If true
"""
emptyMessage="""
else
""">>

If the template parameter permitted a “literal/inline” and had a alias “then”, and emptyMessage an alias of “else” we could write this;

<$list filter="condition" then="""
Do this
"""
else="""
otherwise this
""">>

or
<$list filter="condition" then="Do this" else="otherwise this">>

Allso nest

<$list filter="condition" then="""
Do this
"""
else="""
   <$list filter="condition" then="""
      Do this now
   """
   else="""
      otherwise this default
   """>>
""">>

My thought would be a widget very similar to list ideally called <$if and closed by </$if> which reads as end-if. Change template to then, and emptyMessage to else and leave all other features intact.

To clarify, I do not think that we need new widgets for if/then/else or switch/case; as @TW_Tones has shown, the required logic can be performed with the list widget. I am interested in exploring new wikitext syntax that acts a shortcut for those widgets.

As a simple example:

\if [<currentTiddler>match[yes]]
{{Foo}}
\else
{{Bar}}
\endif

Or:

\switch [<currentTiddler>]
\case "something"
{{Foo}}
\case "else"
{{Bar}}
\endswitch
2 Likes

Hi @jeremyruston
What you have have proposed is a clear and concise syntax and very semantic!
This makes branching and decision making constructs for complex logic quite simple and easy to maintain in Tiddlywiki!

I am eager to see this in the next release!

I’m excited about these ideas but I “fear” one thing:

If the user is to define and use these constructs similar to how local macro pragmas are defined and used, then this presumably means that they must be placed in the top of the text field… which must then be called in the subsequent code, right? IMO this risks “detouring” the code and make things more difficult to read. Here is another example of this problem.

Constructs like “if-then” seem too primitive to need to be invoked - or do I misunderstand the intention here? Maybe you’re only talking about a “core implementation” of these constructs that the user would somehow use it like any system macro by just providing arguments?

Thank you for this @Mohammad and @TW_Tones . Concise, clear explanations, multiple, complete, real world examples and pointers relating the solution to well known programming constructs. Beginners and long term beginners like me salute you!

Best
Watt

If/else-if/else is a solved problem by Evan Balster’s condition plugin:

As I remember it, Evan’s plugin provides widgets for if/then/else, not the wikitext route I am proposing.

Correct. And don’t get me wrong, taken at face value, I like the pragma approach.

Can you please explain more in light of @twMat’s concerns (which I share)?

The example I gave above assumes another potential improvement: that we allow pragmas to appear anywhere in a tiddler, with only some pragmas needing to be at the top of the tiddler (notably the \rules pragma). The restriction on only using \import or \define at the start of a tiddler has always been rather unnecessary.

2 Likes

Sometimes adding a :heart: to a post almost trivializes what’s being said – but that statement (i.e. the proposal) is pure gold and a joy to hear. Thanks.

And yes, I noticed \whitepspace being used like that somewhere on TW .com and started using it – good stuff.

You’ve probably seen \whitespace used within a macro definition - the content of the macro is a new parsing context, and so it allows pragmas, but still only at the top.

So this…

Answers this…

Pulling the jigsaw pieces together…

\define my-macro(...)
\if [<currentTiddler>match[yes]]
  <!-- do stuff -->
\else
  <!-- do other stuff -->
\endif
<span> do always </span>
\if <== Error: no can do here
...
\end

It’s “okay” but not as composable as $if widgets (I’m 100% certain you know that, so #just-sayin).

Thanks for clarification @jeremyruston


The jigsaw pieces you’re pulling together is for how pragmas currently work, yes, but Jeremy notes a new take on this, i.e

…that we allow pragmas to appear anywhere in a tiddler, with only some pragmas needing to be at the top of the tiddler

Sounds very good.

Indeed. I gave the syntax above as an example of a wikitext syntax for these things, not as a finished proposal. One could come up with an inline-able variant, but it would be likely to be more verbose.

Likely. But write up some pseudocode and let’s see how you see it working (and have Jeremy confirm it). It’s hard impractical to comment on commentary without a worked example to rip apart. :wink:

All,

I can see value in a pragma style if then else, it makes writing macro style solutions nice but for many structures we are likely to have case where we want the if then else structures throughout the wiki text.

It seems to me the quickest path is to provide the following; one could reuse the list widget code or simply provide an alias;

  • Alias for $list of $if (may actually use the exact same code as $list)
  • Allow the “template” parameter to have an alias “then” and accept inline text or a variable/macro name eg then=<<macro>>
  • Allow the “emptyMessage” to have an alias “else” - it already accepts litterals, templates or macros.

For example in the following example which is already a reasonable case structure.

Using $if would look like this;

<$set name=input filter="[<input>]uppercase[]]">
<$if filter="[<input>match[A]then[Another]]" then="true"></$if>
<$if filter="[<input>match[B]then[Best]]" then="true"></$if>
<$if filter="[<input>match[C]then[Caught]]" then="true"></$if>
<$if filter="[<input>match[D]then[Default]]" then="true"></$if>
</$set>

However the advantage if reusing the $list widget is we gain a lot more we can code “inline”

Or a more complete nested if

<$if filter="[<input>match[A]then[Another]]" then="""
A true wikitext"""
else="""
   Not A Wiki text
   <$if filter="[<input>match[B]then[Best]]" then={{btrue}} else="Not A or B"></$if>
"""
></$if>

But the key features of this solution are

  • It permits nesting via literal, variable or transclusion
  • You can display intermediate results eg: “Not A Wiki text”
  • You can have multiple $if throughout the wikitext without needing to follow macro definitions.
  • $if implies the result is true or false, however we could code “if any” and “if for each”
    • A designer approach to use $if when the result is intended to be true false would help readability eg;
<$if filter="[{$:/config/debug-mode}match[yes]]" then="Show in debug mode"/>
OR
<$if filter="[{$:/config/debug-mode}match[yes]]">
Show in debug mode
</$if>
OR
<$if filter="[{$:/config/debug-mode}match[yes]]" else=<<toggle-debug>> >
Show in debug mode
</$if>

The above is quicker and clearer when using filters in what would be the list widget simply to display conditional content. This is because the result is true or false not a list, the $if suggests it is not a list, although we have available the full $list widget features.