Settings

Theme

Rust Additions for GCC 15 Bring Support for If-Let Statements

phoronix.com

27 points by Corrado 9 months ago · 26 comments

Reader

CorradoOP 9 months ago

This sounds like good progress for getting Rust into more places. I had no idea that this type of thing was not supported in Rust-GCC.

BTW: Here's a good reference to the differences between "if" and "if let" - https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/sh...

  • Vurdentium 9 months ago

    Do they deliberately make Rust so difficult to read or is it an unfortunate consequence of its complexity?

    • maggit 9 months ago

      It's more a matter of your personal preference and previous exposure to different languages. The way Rust reads is one of its super strengths in my book. I also really enjoyed Standard ML in university, and Rust picks up some of that (via OCaml).

    • dontlaugh 9 months ago

      It’s just familiarity. I find it much easier to read than C++.

    • baq 9 months ago

      Rust is a low-level ML variant with curly braces syntactically.

    • rowanG077 9 months ago

      No doubt there are some things that are hard to read in Rust. In the link posted everything seems very straightforward and should make sense if you know a c-like language.

    • timeon 9 months ago

      Which part in that link are you finding difficult to read?

      First example with `match` seems to me already more readable than `switch` statement with breaks.

    • wruza 9 months ago

      >Option<T> option

      >match option

      >if option.is_some()

      >Neither of these options is particularly appealing.

      There’s the answer. The new syntax is just particularly appealing.

      Does “if let some of x be assigned an option:” make better sense and sound greater than “match option, some of x:” and “if option is some:”?

      • Defletter 9 months ago

        It's certainly cleaner, but my immediate thought when reading was "that's a compile error" because it looks like it's declaring a variable with a type mismatch. This is where, in other languages, the "case" keyword (or similar) comes in handy (eg: Dart's if-case syntax[1]), except Rust doesn't have that because of its headlong pursuit of 'conciseness'.

        - [1] https://github.com/dart-lang/language/issues/2181

        • tialaramex 9 months ago

          I think the fact you had to re-consider it shows you're not thinking in patterns. Rust is a language which always had pattern matching so in Rust it feels natural to, for example:

            while let Some(work) = inbox.pop() { /* ... */ }
          
          [edited: thanks HN, of course since this is code I don't need to escape the asterisks, unless I do]
          • Defletter 9 months ago

            > you're not thinking in patterns

            It's not that... well, it might be, but I use pattern matching fairly regularly in a number of languages. But Rust has hijacked the variable syntax and changed it beyond recognition: there's no matching operator being used; the same code does different things based on its surroundings:

                // This causes a compilation error
                let Some(work) = inbox.pop()
                
                // But putting it 1:1 within a while statement is fine?
                while let Some(work) = inbox.pop() { /* ... */ }
                
            
            Whereas, with Java's pattern matching:

                while (inbox.poll() instanceof final Work work) { /* ... */ }
            
            It borrows the variable declaration syntax too, which can be extracted fine without issue, but there's an operator being used to express that pattern matching is happening.

            Different languages have different uses, histories, and quirks, yes, and this is by no means to suggest that Java is a better language or that it doesn't have its own flaws. But Rust coopting of that syntax makes the language harder to learn and harder to comprehend at a glance, in my opinion. It seems to be like one of those situations where, once you learn it, it's fine, but that's my point.

            • whytevuhuni 9 months ago

              First of all, you're right, it does indeed do different things. The stand-alone variant only accepts irrefutable patterns, hence why it needs an "else" branch.

              But just for fun, let's make it compile!

                  enum Result<T> {
                      Some(T),
                  }
                  
                  use Result::Some;
                  
                  fn pop() -> Result<u32> {
                      Some(42)
                  }
                  
                  fn main() {
                      // This doesn't cause a compilation error
                      let Some(work) = pop();
                  }
            • afdbcreid 9 months ago

              I will argue that it's not different, it's exactly the same thing. In both cases you are matching a pattern. The only difference is that in `if` and `while`, because they are conditional, the pattern is allowed to not match (refutable), while in bare `let` it must match (irrefutable).

            • tialaramex 9 months ago

              > // This causes a compilation error

              I'll assume you know you missed a semi-colon, so we'll fix that, which still gets us a compiler error, but specifically the diagnostic says: pattern `None` not covered and it suggests:

                 let Some(work) = index.pop() else { todo!() };
              
              You seemed puzzled by the fact we can use this pattern for let while, but of course when our pattern doesn't match (for None) the loop ends, that's what a while-let loop does, the if expression which may not match needs a clause for the case where it doesn't match, the suggestion is an else clause.

              Remember Rust is a statically typed expression language so Python type situations where maybe the pattern matched or maybe it didn't and something will happen but the language doesn't promise what, those aren't OK because we have static typing, what is the type of "Eh, I don't know, whatever" ?

              Edited:: Aha, I realised you wrote "1:1 within a while statement" and now I think I see the problem. That's not a while statement, Rust doesn't have those - it does have while loop expressions - but this isn't one of those either, this is while let, it's different.

              This isn't a while loop where the while condition happens to be a variable assignment, Rust doesn't have that. There's a reason while let has a whole separate entry in the book. This is syntax for a loop which repeatedly performs a pattern match and always exits when it fails.

              • Defletter 9 months ago

                This is honestly a pretty perfect example of why criticising programming languages can be so frustrating: people are completely unwilling to meet you where you're at. You're response here is to say that of course while-let does that, because that's what while-let does, that's how while-let looks. I'm not being critical of Rust having pattern matching as the while-loop condition, but of how this is expressed in code, specifically with how it looks exactly like an ordinary variable definition, but doesn't at all function like one, and how that can be confusing to a non-zero amount of people. That's the extent of my complaint. I'm ganna go now.

          • CorradoOP 9 months ago

            I think that's one of the things I struggle with in Rust; pattern matching is integral and I'm not thinking in patterns (yet). When I see "while let" I don't think about patterns at all, my brain goes straight to variable assignment.

    • survirtual 9 months ago

      Short answer: It is difficult because you aren't familiar with it, and your brain is still wired for memory-unsafe or GCed languages. But it is actually easier to read than most other languages when you understand it and how to navigate it.

      When I first started learning Rust several years ago, I shared your viewpoint. With a heavy preference for C++ syntax, I thought Rust looked atrocious.

      Then I learned it. I got good with it. I got comfortable with it. I switched from VS Code based IDEs to vim, then to IDEs with vim bindings (trying Zed now). Now, Rust reads like a dream -- aside from lifetime specifiers, which I think could be much smarter than they are now.

      Anyway, it has superior pattern matching and code searching. snake_case is easier to navigate than camelCase or PascalCase. Keywords are short and easily recognizable. Branching logic is much, much easier to follow. Error handling is explicit and also easier to follow (and I started out really missing try-catch). Code gen with macros eliminates a lot of headaches. A 1st class package manager that is fast & can be easily inspected, that seamlessly integrates into the code...the list goes on.

      The point is, it is a paradigm shift that doesn't hide much of anything away. When you consider there is no GC and you are in full control of memory, that there are strict syntax and styling rules that make the global Rust codebase universally accessible, once you switch to it you find yourself wishing everything was written in Rust. That is why people using it want to rewrite everything, even well established packages. A Rust-only codebase is buttery smooth.

      • jamincan 9 months ago

        In general, I find Rust very readable. The areas I do find I struggle are generics and lifetimes, and I don't think it's a feature of Rust syntax that makes me struggle and is instead the fact that people tend to use non-descriptive names for lifetimes or generics. It's hard to pick apart a trait that has four generics name T, U, V, and W, or lifetimes 'a, 'b, and 'c.

        Usually people will try to make it the first letter of something meaningful, but it is still much harder to parse.

        My own preference is to use more descriptive names except in trivial cases. Having the lifetime mirror a struct member name or a parameter name is really helpful for understanding them, in my opinion.

        • tialaramex 9 months ago

          Yeah, I think it's non-obvious that you can name a lifetime 'frame not 'f - yes the compiler won't know you named it that because it's only supposed to live for one frame, but that's also true for your variable named timeout, Rust can see it's a Duration, so it has appropriate affordances, but it can't know you meant to call set_timeout(timeout) and not just store it somewhere.

          I have a backlog item to find Rust docs which use a concise lifetime name but could value a better one, however there aren't actually that many cases other than the scoped threads which do indeed name the scopes 'scope and 'env showing that we can give these meaningful names.

      • weakfish 9 months ago

        Although I disagree with your point made, I appreciate you taking the time to write a well-thought out reply.

      • juped 9 months ago

        Painfully realistic satire, but the end lays it on a bit too thick.

    • juped 9 months ago

      Somewhere in between. There actually is a level of demand for languages which are annoying to use; whether this is annoying syntax or annoying semantics isn't much of a distinction, they dovetail. But more than that, there's demand for ML clones (but with curly braces), and neither ML nor generic-curly-brace is the strongest foundation to build readability on, unfortunately.

pjmlp 9 months ago

On a side note, gccgo seems to be on the route to follow gcj footsteps removal from GCC, left to stagnate on 1.18 version without any clear roadmap if it will ever be touched again other than minor bug fixes.

Kind of ironic now with Cobol being added in GCC 15, joining Modula-2, D, Rust, Fortran, Ada, C, C++ collection of frontends.

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection