URI: 
        _______               __                   _______
       |   |   |.---.-..----.|  |--..-----..----. |    |  |.-----..--.--.--..-----.
       |       ||  _  ||  __||    < |  -__||   _| |       ||  -__||  |  |  ||__ --|
       |___|___||___._||____||__|__||_____||__|   |__|____||_____||________||_____|
                                                             on Gopher (inofficial)
  HTML Visit Hacker News on the Web
       
       
       COMMENT PAGE FOR:
  HTML   Rust's Block Pattern
       
       
        atq2119 wrote 50 min ago:
        Not mentioned in the article but kinda neat: you can label such a block
        and break out of it, too! The break takes an argument that becomes the
        value of the block that is broken out of.
       
          the__alchemist wrote 20 min ago:
          I just learned this one, and am gradually starting to use it! It
          applies for loops too. I saw it in ChatGPT code, and had to stop and
          look it up. Rust is a big language, for worse and for better.
       
        skipants wrote 1 hour 10 min ago:
        I often employ this pattern in Ruby using `.tap` or a `begin` block.
        
        It barely adds any functionality but it's useful for readability
        because of the same reasons in the OP.
        
        It helps because I've been bitten by code that did this:
        
          setup_a = some_stuff
          setup_b = some_more_stuff
          i_think_this_is_setup = even_more_stuff
          the_thing = run_setup(setup_a, setup_b, i_think_this_is_setup)
        
        That's all fine until later on, probably in some obscure loop,
        `i_think_this_is_setup` is used without you noticing.
        
        Instead doing something like this tells the reader that it will be used
        again:
        
          i_think_this_is_setup = even_more_stuff
          
          the_thing = begin
            setup_a = some_stuff
            setup_b = some_more_stuff
            run_setup(setup_a, setup_b, i_think_this_is_setup)
          end
        
        I now don't mentally have to keep track of what `setup_a` or `setup_b`
        are anymore and, since the writer made a conscious effort not to put it
        in the block, you will take an extra look for it in the outer scope.
       
          gleenn wrote 1 hour 1 min ago:
          Clojure also has the threading macro -> and ->> which are great at
          converting exactly the same type of code into a stream of
          modifications instead of breaking out everything into variables.
          Naming things can be very useful sometimes but sometimes it is
          entirely gratuitous and distracting to have
          
          let input = read_input();
          let trimmed_input = input.trim();
          let trimmed_uppercase_input = trimmed_input.uppercase();
          
          ...
          
          The extra variable names are almost completely boilerplate and make
          it also annoying to reorder things.
          
          In Clojure you can do
          
          (-> (read-input) string/trim string/upcase)
          
          And I find that so much more readable and refactorable.
       
        ngruhn wrote 1 hour 27 min ago:
        Reminds of Brian Wills OOP rant video from 2016. He advocates exactly
        for this pattern:
        
  HTML  [1]: https://www.youtube.com/watch?v=QM1iUe6IofM&t=2235s
       
        etyp wrote 1 hour 36 min ago:
        This is one of those natural consequences of "everything is an
        expression" languages that I really like! I like more explicit syntax
        like Zig's labelled blocks, but any of these are cool.
        
        Try this out, you can actually (technically) assign a variable to
        `continue` like:
        
        let x = continue;
        
        Funnily enough, one of the few things that are definitely always a
        statement are `let` statements! Except, you also have `let`
        expressions, which are technically different, so I guess that's not
        really a difference at all.
       
        esafak wrote 1 hour 51 min ago:
        Block expression [1] Also in Kotlin, Scala, and nim.
        
  HTML  [1]: https://doc.rust-lang.org/reference/expressions/block-expr.htm...
       
        keybored wrote 1 hour 56 min ago:
        Obligatory use: it’s a block I guess
        
        Voluntary use: I know this one. It’s a pattern now.
       
        emtel wrote 2 hours 0 min ago:
        There are some situations with tricky lifetime issues that are almost
        impossible to write without this pattern. Trying to break code out into
        functions would force you to name all the types (not even possible for
        closures) or use generics (which can lead to difficulties specifying
        all required trait bounds), and `drop()` on its own is of no use since
        it doesn't effect the lexical lifetimes.
       
        bryanlarsen wrote 2 hours 4 min ago:
        More significantly the new variables x and y in the block are Drop'd at
        the end of the block rather than at the end of the function.   This can
        be significant if:
        
        - Drop does something, like close a file or release a lock, or
        
        - x and y don't have Send and/or Sync, and you have an await point in
        the function or are doing multi-threaded stuff
        
        This is why you should almost always use std::sync::Mutex rather than
        tokio::sync::Mutex.   std's Mutex isn't Sync/Send, so the compiler will
        complain if you hold it across an await.   Usually you don't want
        mutex's held across an await.
       
          defen wrote 43 min ago:
          Can this also affect stack usage? Like if `x` gets dropped before `y`
          is introduced, can `y` reuse `x`'s stack space (let's assume they are
          same size/alignment). Or does the compiler already do that if it can
          see that one is not used after the other is introduced?
       
          bryanlarsen wrote 1 hour 0 min ago:
          oops:    Of course the Mutex is Sync/Send, that's the whole point of a
          Mutex.     It's the std::sync::MutexGuard that's not.
       
        ibgeek wrote 2 hours 5 min ago:
        This seems like a great way to group semantically-related statements,
        reduce variable leakage, and reduce the potential to silently introduce
        additional dependencies on variables.  Seems lighter weight (especially
        from a cognitive load perspective) than lambdas.  Appropriate for when
        there is a single user of the block -- avoids polluting the namespace
        with additional functions.  Can be easily turned into a separate
        function once there are multiple users.
       
        lights0123 wrote 2 hours 23 min ago:
        GCC adds similar syntax as an extension to C: [1] It's used all
        throughout the Linux kernel and useful for macros.
        
  HTML  [1]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
       
        bobbylarrybobby wrote 2 hours 24 min ago:
        You can also de-mut-ify a variable by simply shadowing it with an
        immutable version of itself:
        
        let mut data = foo();
        data.mutate();
        let data = data;
        
        May be preferable for short snippets where adding braces, the yielded
        expression, and indentation is more noise than it's worth.
       
        koakuma-chan wrote 2 hours 28 min ago:
        I have one better: the try block pattern.
        
  HTML  [1]: https://doc.rust-lang.org/beta/unstable-book/language-features...
       
          tayo42 wrote 8 min ago:
          Why does this need special syntax? Couldn't blocks do this if the
          expression returns a result in the end?
       
            koakuma-chan wrote 6 min ago:
            One reason is that would be a breaking change.
       
          Sytten wrote 50 min ago:
          I want that stabilized so bad but it's not been really moving
          forward.
       
            koakuma-chan wrote 8 min ago:
            #![feature(try_blocks)]
            
            You only live once.
       
            mmastrac wrote 26 min ago:
            I was not a fan when I first saw it but I'm becoming desperate to
            have it the more Rust I write.
       
          oniony wrote 1 hour 50 min ago:
          Now that is pretty cool.
       
        lenkite wrote 4 hours 39 min ago:
        The first example given is not at all convincing. Its is clear as the
        sky that loading the config file should be be a separate function of
        its own. Coupling sending HTTP requests with it makes no sense.
        
        The second example "erasure of mutability" makes more sense. But this
        effectively makes it a Rust-specific pattern.
       
          dtdynasty wrote 1 hour 27 min ago:
          It's essentially an inline function with only 1 client. Can be a
          preference for inline readability and automatically enforces there
          are no other clients of the "function".
       
        aabdelhafez wrote 7 hours 41 min ago:
        It's idiomatic in Kotlin as well!
        
  HTML  [1]: https://kotlinlang.org/docs/scope-functions.html
       
          zaphirplane wrote 2 hours 25 min ago:
          So many options why oh why. let run with also apply
       
          simon_void wrote 4 hours 54 min ago:
          I agree, i started with (scope) blocks in Rust, but keep the habit in
          Kotlin win the run - scope-function. Since run takes no arguments, it
          feels like the closest equivalent to Rust scopes (compared to other
          Korlin scope functions, which also keep their local variables from
          polluting the rest of the function body).
       
        nadinengland wrote 9 hours 29 min ago:
        I love that this is part of the syntax.
        
        I typically use closures to do this in other languages, but the syntax
        is always so cumbersome. You get the "dog balls" that Douglas Crockford
        always called them:
        
        ```
        const config = (() => {
          const raw_data = ...
        
          ...
        
          return compiled;
        })()'
        
        const result = config.whatever;
        
        // carry on
        
        return result;
        ```
        
        Really wish block were expressions in more languages.
       
          charleszw wrote 2 min ago:
          Yes, I constantly use this pattern in C++/JavaScript, although I
          haven't tested how performant it is in the former (what does the
          compiler even do with such an expression?)
       
       
   DIR <- back to front page