Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

It might help you to think of 'if let' as an extension of 'let' rather than an extension of 'if'. That is, 'let' by itself supports irrefutable patterns. e.g.,

    let std::ops::Range { start, end } = 5..10;
So the 'if' is "just" allowing you to also write refutable patterns.


That is a useful way to think about it for sure, I’m mostly using it as an illustration of what is probably a philosophical difference between myself and the Rust maintainers; in other words, I don’t see why we need if let when we already have match with _ wildcards. It’s the sort of syntactic shortcut that gives authors of code relatively little benefit (save a few keystrokes) and readers of code yet one more syntactic variation to contend with.

I guess another way of putting it is that I think Rust has a lot of sugar that’s confusing.

Kotlin is an example of a language that has a lot of similar syntactic shortcuts and functional underpinnings that implements them in a more readable and consistent fashion imo.


I could live without 'if let'. I'm not a huge fan of it either, although I do use it.

Its most compelling benefit to me is not that it saves a few keystrokes, but that it avoids an extra indentation level. Compare (taking from a real example[1]):

    if let Some(quits) = args.value_of_lossy("quit") {
        for ch in quits.chars() {
            if !ch.is_ascii() {
                anyhow::bail!("quit bytes must be ASCII");
            }
            // FIXME(MSRV): use the 'TryFrom<char> for u8' impl once we are
            // at Rust 1.59+.
            c = c.quit(u8::try_from(u32::from(ch)).unwrap(), true);
        }
    }
with:

    match args.value_of_lossy("quit") {
        None => {}
        Some(quits) => {
            for ch in quits.chars() {
                if !ch.is_ascii() {
                    anyhow::bail!("quit bytes must be ASCII");
                }
                // FIXME(MSRV): use the 'TryFrom<char> for u8' impl once we are
                // at Rust 1.59+.
                c = c.quit(u8::try_from(u32::from(ch)).unwrap(), true);
            }
        }
    }
The 'for' loop is indented one extra level in the latter case. With that said, I do also use 'if let' because it saves some keystrokes. Taking from another real example[2], compare:

    if let Some(name) = get_name(group_index) {
        write!(buf, "/{}", name).unwrap();
    }
with

    match get_name(group_index) {
        None => {}
        Some(name) => {
            write!(buf, "/{}", name).unwrap();
        }
    }
(I could use '_ => {}' instead of 'None' to save a few more.)

I do find the 'if let' variant to be a bit easier to read. It's optimizing for a particular and somewhat common case, so it does of course overlap with 'match'. But I don't find this particular overlap to be too bad. It's usually pretty clear when to use one vs the other.

But like I said, I could live without 'if let'. It is not a major quality of life enhancement to me. Neither will its impending extensions. i.e., 'if let pattern = foo && some_booolean_condition {'.

[1]: https://github.com/BurntSushi/regex-automata/blob/fbae906823...

[2]: https://github.com/BurntSushi/regex-automata/blob/fbae906823...


I don't code in Rust--and thereby might be expected to not know all of these patterns and want to have to learn fewer bits--and yet I agree with you. I feel like removing this "if let" variant would be similar to saying we don't need if statements as they are equivalent to a loop that ends in break. I actually even will say the if let is much easier to read as with the match I have to check why it is a match and verify it has the None case--similar to checking if a loop is really going to loop or if it always ends in break--whereas I can skip all that work if I see the "if".


That's fine but it's nonintuitive.


It is to me.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: