Language Design: Unified Condition Expressions
Introduction
Published on 2018-01-21. Last updated on 2026-05-28
Idea
Replace the different syntactic forms of
ifstatements/expressionsswitchon valuesmatchon patterns and pattern guardsif-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.
Observations
- Ternary expressions and
ifstatements can be fully subsumed byifexpressions. switchhas a fixed part whose value is compared using an equality relation against a set of branch-specific values.ifsupports arbitrary conditions, but allows more than two branches only by chainingifto anelse.- Splitting conditions into a shared, common part and individual condition continuations conflicts with mandatory parentheses around conditions.
- To ensure unambiguous parsing …
- the place where the shared part of condition ends and the individual continuations starts
requires either braces around the branch, or a start keyword like
then. - the place where a branch ends and the next individual condition starts requires either braces
around the branch, a keyword like
end, or punctuation like,or;. - Indentation-sensitive syntax can be an alternative to both, but may or may not fit into the target language’s desired overall look and feel.
- the place where the shared part of condition ends and the individual continuations starts
requires either braces around the branch, or a start keyword like
Considerations
- Alternative keyword choices to
ifarematch,switch, orwhen.
The keyword choice has no impact on the ideas presented. - Though not strictly required,
...may be used to make the division between the shared part of the condition and the individual condition continuation 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"
a shared comparison operator for multiple condition continuations
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 for each condition continuation
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)
While is (being “just another” binary operator) is not strictly related to unified condition expressions,
its use in unified condition expressions unlocks support for additional functionality often found in languages with
switch or match keywords, such as binding values, wildcards (_) and guards.
binding values
if person
.age < 18 then 18
is Person("Alice", _) then person.age
is Person("Bob", let age) then age
else -1
flow typing
if pet /* same as */ if pet is
is Cat(_) then cat.meow() Cat(_) then cat.meow()
is Dog(_) then dog.bark() Dog(_) then dog.bark()
pattern guards
if person
is Person("Alice", _) then "alice"
is Person(_, let age) && age >= 18 then "adult"
else "minor"
replacement for “if-let”
if person is Person("Alice", let age) then age else -1
Related Work
- SQL (SQL:2003)
- "extended case" of case-when expression
- CommonLisp
- cond macro and case macro
- Haskell (language extension)
- multi-way if-expressions
- Rust
- if-let syntax
- Swift
- Optional chaining