Language Design: Unified Condition Expressions
Introduction
Published on 2018-01-21. Last updated on 2024-04-01
    Idea
Replace the different syntactic forms of
- ifstatements/expressions
- switchon values
- matchon patterns and pattern guards
- if-- letconstructs
with a single, unified condition expression that scales from simple one-liners to complex pattern matches.
Motivation
- Cut the different syntax options down to a single one that is still easily recognizable by users.
- Allow the design to scale seamlessly from simple cases to complicated ones.
Minimizing the number of keywords or turning condition syntax into method calls (like Smalltalk) are non-goals.
Considerations
- Ternary expressions and ifstatements can be fully subsumed byifexpressions.
- The difference between switchandif…- switchhas a fixed part – whose value is compared using an equality relation against a set of individual values
- ifsupports arbitrary conditions – it allows more than two branches only by chaining- ifto an- else
 
- Splitting conditions into a shared, common part and individual condition continuations requires doing away with mandatory parentheses around conditions.
 Demarcating the place …- where the shared part of condition ends and the individual continuations starts, as well as
- where a branch ends and the next individual condition starts
 … requires either … - mandatory braces around the branch, or
- a start keyword like thenand- either end keyword like endor,
- or indentation-sensitive syntax
 
- either end keyword like 
 … to ensure unambiguous parsing. 
- Alternative keyword choices to ifandthenarematch,switch,caseorwhen.
- Though not strictly required, ...may be used to make the division between the shared part and the individual case more apparent to the reader.
Examples
For the code examples, a hypothetical language with indentation-sensitive syntax and the keywords if and then has been chosen.
simple if expression
if x == 1.0                         /* same as */
then "a"                            if x == 1.0 then "a" else "z"
else "z"
one comparison operator on multiple targets
if x ==       /* same as */    if x             /* same as */       
  1.0 then "a"                   == 1.0 then "a"       if x == 1.0      then "a"
  2.0 then "b"                   == 2.0 then "b"       else if x == 2.0 then "b"
      else "z"                          else "z"       else                  "z"
different comparison operators, equality and identity
if x                                /* same as */
  ==  1.0 then "a"                  if x == 1.0       then "a"
  === NaN then "n"                  else if x === NaN then "b"
          else "z"                  else                   "z"
method calls
if xs                               /* same as */
  .isEmpty       then "e"           if xs.isEmpty            then "e"
  .contains(0.0) then "n"           else if xs.contains(0.0) then "n"      
                 else "z"           else                          "z"
pattern matching (is), introducing bindings, flow typing
if person
  .age < 18                 then 18
  is Person("Alice", _)     then person.age
  is Person("Bob", let age) then age
                            else -1
pattern matching using “if-let”12
if person is Person("Alice", let age) then age else -1
wildcards (_) and pattern guards
if person                            /* same as */      if person is
  is Person("Alice", _)              then "alice"         Person("Alice", _)              then "alice"
  is Person(_, let age) && age >= 18 then "adult"         Person(_, let age) && age >= 18 then "adult"
                                     else "minor"                                         else "minor"
Related Work
- Haskell – multi-way if-expressions
- CommonLisp – cond and case