The below is structured as a proposal, but at the moment I just want to gather 
opinions and also see if this a non-starter or not. It includes options for 
adopting this in version 2 or the theoretical version 3. Putting dev effort 
aside for the time being, is this a reasonable thing to address and does it 
align with the desired approach?


## Summary ##

Enhance the switch directive to not force fall-through behavior. Using switch 
is currently clunky and the available alternatives have their own compromises. 
It should not exist in its current form in the next major release.

## History ##

The FreeMarker switch directive mimics the Java switch statement. It supports 
fall-through and this is the control flow unless break is encountered. The 
manual recommends against this directive due to this error-prone behavior. 
Later, the switch built-in was added which does not have the concept of 
fall-through.

## Goals ##

* Avoid unnecessary syntactic noise caused by having to use the break directive

* Avoid accidental fall-through by making it explicit when needed

## Motivation ##

* Avoid the potential for repetition due to elseif as a replacement

* Offer increased syntactic clarity compared to the built-in

* Avoid the pitfalls of the current switch directive


## Description ##

The basis of this proposal is inspired by the switch statement in the Go 
language (see https://yourbasic.org/golang/switch-statement/). Rather than the 
default being to fall-through and you have to use the break keyword to avoid 
it, instead the default is to not fall-through and you have to use the 
fallthrough keyword to get that behavior. Having explicit fall-through stops it 
being a pitfall whilst allowing the feature to be used if required. Go has 
avoided repeating the mistake of previous languages and presents a solution 
that seems obvious in hindsight.

Approaches for adopting this could be:

* Replace the switch directive in the next major version with the explicit 
fall-through version

* Introduce a new switch directive with a new name

* Have a global setting for which switch directive is used / available to 
templates

* Add an optional parameter to the switch directive for whether it should 
fall-through or not; its default would be a config setting. If we did this 
perhaps we should consider in future being able to parse the switch's value 
parameter as optional (defaulting to true), taking further inspiration from Go.

If we want fall-through to be explicit, it makes sense to add a fallthrough 
directive to act as the inverse of the break directive. The user would then use 
the break directive (as required) when using the current mode/directive for 
fall-through and the fallthrough directive (as required) when using the new 
mode/directive. For what should happen when using break in the new 
mode/directive and fallthrough in the old mode/directive: it could either be an 
error, or break will still break and fallthrough will do nothing (or perhaps go 
to the next case).


## Alternatives ##

* Remove the switch directive altogether

* Completely disallow fall-through and the break directive (have neither 
implicit nor explicit fall-through)

* Add a more powerful match directive that supports pattern matching and takes 
inspiration from e.g. Java's switch expressions or Rust's pattern syntax

## Future work ##

Reinstating switch as a first-class directive would open the door to allowing 
enhancements to it again.

One (low hanging?) example: for a case directive's value parameter to be an 
expression it sometimes requires wrapping the expression in brackets (e.g. it 
doesn't for an equality comparison, but does for a greater than comparison); 
the parser could be enhanced to remove this requirement.


---
Best regards,
Simon Hartley

Reply via email to