if-else chains considered harmful
As always, I have some strong opinions on things I probably shouldn’t have opinions on. This time I want to tell you why I think if-else chains are syntactically harmful.
I think that the syntax for if-else chains that are used in most imperative languages, including Rust, is bad.
if something.something() {
    do_something()
} else if let Some(x) = get_x() {
    use_x(x);
} else if mutliline {
    a();
    b();
    c();
} else {
    scream("aaaaaaaaaaaaaaaaaaaaaaa")?;
}
It’s hard to read:
- 
conditions are mixed with if/else/letkeyword-noise[else] if letin Rust allows pattern-matching behaviour inifstatements
- 
conditions are indented more than expressions 
- 
conditions are indented inconsistently between the first branch ( if) and the following ones (else if)
- 
one-liners take a lot of lines 
- 
etc. 
Singular ifs are fine I guess, it’s the else if chains that make all of this particularly bad
I think that a much better way to model the same thing is when from Kotlin or pattern guards/multi-way-if from Haskell.
Kotlin and Haskell examples
when {
    x.isOdd() -> print("x is odd")
    y.isEven() -> print("y is even")
    else -> print("x+y is odd")
}
case () of _
    | condition1 -> expr1
    | condition2 -> expr2
    | condition3 -> expr3
    | otherwise  -> default
if | condition1 -> expr1
    | condition2 -> expr2
    | condition3 -> expr3
    | otherwise  -> default
In Rust this can be simulated via match on unit with pattern guards (Boxy style):
match () {
    _ if something.something() => do_something(),
    _ if let Some(x) = get_x() => use_x(x),
    _ if multiline => {
        a();
        b();
        c();
    }
    _ => scream("aaaaaaaaaaaaaaaaaaaaaaa")?,
}
But this is still messy, if let guards are unstable and the repeated ifs are still there.
This is why I created kiam (#shamelessplug?) — a crate that provides a simple macro that makes these chains a lot nicer:
when! {
    something.something() => do_something(),
    let Some(x) = get_x() => use_x(x),
    multiline => {
        a();
        b();
        c();
    }
    _ => scream("aaaaaaaaaaaaaaaaaaaaaaa")?,
}
I’ve explained kiam with memes on twitter dot com
One of the only downsides of when! is IDE and tooling (rustfmt) support (or rather the absence of it). I wish this was part of the language or std…
Soooo yeah, there isn’t much to add here. If-else chains are bad for humans, macros are bad for IDEs, I have a cool crate.
Bye.