[HN Gopher] Nibbles of Rust - Restructuring Patterns
       ___________________________________________________________________
        
       Nibbles of Rust - Restructuring Patterns
        
       Author : g0xA52A2A
       Score  : 111 points
       Date   : 2023-04-16 08:21 UTC (14 hours ago)
        
 (HTM) web link (www.catmonad.xyz)
 (TXT) w3m dump (www.catmonad.xyz)
        
       | pflanze wrote:
       | The author talks about adding structure, and I've been puzzled
       | about what they are talking about until realizing that they
       | apparently mean that a reference to something is "more" than the
       | something hence it "adds structure". That doesn't make sense to
       | me. More structure is if there are more elements in the data
       | (more fields in a struct, or more alternatives in an enum),
       | whereas a reference is just an indirection of access.
       | 
       | Or am I missing something?
        
         | clord wrote:
         | &T, &mut T, and T are all different types in a sense. Hence ref
         | is transmuting types during restructuring.
         | 
         | Really, they are adding a new view, so perhaps this is like
         | Haskell lenses, where you can make views with a different type
         | that acts on underlying data
        
         | fkcgnad wrote:
         | [dead]
        
         | bobbylarrybobby wrote:
         | I think it's "more" in the same sense that Some(x) is more than
         | x. You can destructure &x in exactly the same way.
        
         | cstrahan wrote:
         | The set of all &T is larger than the set of T.
         | 
         | Let's consider the case where T is u8. There are 256
         | inhabitants of the u8 type (0u8-255u8).
         | 
         | Now consider &u8. Each u8 referent is still some value between
         | 0 and 255, but the number of references you could have is
         | dependent on the pointer width of your target system -- let's
         | say 64 bits. So that's 2^8 possible u8 values times 2^64
         | possible references, or 2^72 inhabitants. Well, minus one to
         | account for null, and I'm probably missing other details, but
         | you get the idea.
         | 
         | So going from T to &T introduces structure in the same sense
         | that going from T to (T, U) does; and going from &T to T
         | destructures in the same sense that going from (T, U) to T
         | does. That structure may not be directly observable (as in the
         | case of a reference: you'd have to go out of your way to
         | observe the underlying address), but conceptually the structure
         | is there nonetheless.
         | 
         | Edit:
         | 
         | Another way to look at it is this:
         | 
         | Consider a Rust "newtype", like struct Days(u8).
         | 
         | If you pattern match on that to obtain the inner u8, we call
         | that destructuring. Destructuring is to reduce or break down
         | the structure of a thing, so the opposite must be building up
         | structure, or "restructuring". Therefore going in the opposite
         | direction -- stuffing a u8 value in a Days - must be
         | restructuring. In this case both types have the same number of
         | inhabitants (256); regardless, one direction is destructuring
         | and the other direction is restructuring.
        
       | juancampa wrote:
       | I don't understand why go through the complication of giving this
       | a new name (i.e. "Restructuring Pattern") where the second
       | explanation seems more intuitive and correct.
       | 
       | "Restructuring Pattern" sounds like you can put back together a
       | struct from its constituents, but that's done by normal struct
       | instantiation.
        
         | fkcgnad wrote:
         | The author is talking about restructuring syntax in the
         | destructing match.
         | 
         | Rust Has this with "match" but only via a single ref.
         | 
         | You would have to make alternative restructuring syntax to go
         | into the match expression if you want it to work.
         | 
         | Hypothetically:                  fn g(v: Option<i32>) ->
         | Option<Option<i32>> {                  match v {
         | Some(_Some(_Some(x))),                 None(_None)
         | }         }
         | 
         | Any character with an underscore is a "restructuring" syntax
         | here. Rust only does restructuring with references via the ref
         | keyword and it only does it once per var per expression. The
         | syntax I presented here is hypothetical of course.
         | 
         | I would say it's more syntactic sugar as you can do the
         | restructuring on the right side of the match expression. You
         | can make up an entire functional language using this technique
         | and eliminate the => and everything after it.
         | 
         | I largely agree with you that it's not exactly necessary to do
         | this. Arguably it makes things harder to read.
        
       | fmiras wrote:
       | nice reading!
        
       | rtpg wrote:
       | Nice tip.
       | 
       | I honestly am a bit frustrated with Rusts pattern matching
       | ergonomics, cuz it ends up requiring me to introduce indentation
       | in places where I don't want it, mainly to futz around with
       | unwrapping structures or the like.
       | 
       | Lots of helper methods exist on standard library enumerations but
       | I really want there to be some nice built in macros to just give
       | me the innards when I need it, and have a control flow block for
       | when I _cant_ pattern match (and thus want to do an early return
       | or blow up). Maybe this already exists!
       | 
       | Too much indentation makes languages unfun (see every lisp
       | struggle with this with name binding)
        
         | spease wrote:
         | You mean like 'matches!'?
         | 
         | https://doc.rust-lang.org/std/macro.matches.html
        
           | rtpg wrote:
           | What I want is..
           | 
           | let MyEnum(foo, bar, baz) = input but otherwise { do some
           | stuff return some value }
           | 
           | Point being I don't have to check for MyEnum-ness twice (like
           | with matches! + if let) and the indented code is for the
           | exception (no match) not the norm.
           | 
           | Tho I ... guess !matches(MyEnum{ .. }) is not the worst...
           | but it's annoying to have this pattern all over my code
           | instead of as some encoded concept we all use
        
             | ljsb wrote:
             | You were pretty close with your hypothetical syntax! You
             | can write:                 let Some(y) = x else {
             | do_stuff(); return };
             | 
             | I think it was a fairly recent addition to Rust.
        
               | metadat wrote:
               | What determines whether `let Some(y) = x` evaluates to
               | boolean true?
        
               | asherah wrote:
               | if x is `Some`, then `y` is set to the inner value and
               | the following block occurs. you can also use this with
               | other enums - i don't remember off the top of my head if
               | it works for all enums, but you can at least also use it
               | with `Result`
        
               | jeffdn wrote:
               | It absolutely works for all patterns!
        
               | bombela wrote:
               | The fact that the pattern matches.
               | 
               | Here the type being matched is:                   enum
               | Option<T> {             None,             Some(T)
               | }              let x = Some(42);         let Some(y) = x
               | else { panic!("None") };
        
               | rtpg wrote:
               | Thank dog for that. I feel like I even read the release
               | notes for that but it was while I hadn't been touching a
               | specific codebase with loads of early returns. Thanks for
               | pointing this out!
        
               | chrismorgan wrote:
               | let-else was stabilised in 1.65.0, released 2022-11-03.
        
         | e-dant wrote:
         | Use combinators!
        
       | lloydatkinson wrote:
       | I think there needs to be a "center the page" browser extension
       | because this is just absurd: https://imgur.com/a/HZqaA4V
        
         | muattiyah wrote:
         | I always thought it was weird when people have websites like
         | this, anyways, for those phased away and want to read this
         | article while centered, execute in the console:
         | document.getElementsByTagName('body')[0].children[0].style.marg
         | in = '0 auto';
        
           | lloydatkinson wrote:
           | That's a good tip! I also think its just as weird when sites
           | have zero links to their home page. On what planet is "go to
           | the address bar and delete the last part of the url and hit
           | enter to go to the index" good user experience?
        
             | Monadic-Cat wrote:
             | Agreed. It was a good tip.
             | 
             | My goal in leaving out the link to my home page was to make
             | the Writing Gaggle home page more prominent than my
             | personal blog. (I manage hosting both, see.) I only added
             | my blog index page as an afterthought when I saw a ton of
             | 404 errors on my server a few months ago because people
             | were manually navigating to it.
             | 
             | I'll consider adding actual navigation to my page template
             | though, so maybe you'll be less annoyed ;)
        
           | Monadic-Cat wrote:
           | I'll go ahead and promise to leave the '#wrapper' id on that
           | element in my blog template, so this can be shortened to:
           | document.getElementById('wrapper').style.margin = '0 auto';
           | 
           | Though if you're in the habit of customizing sites you read,
           | I'd personally recommend using a browser extension like
           | Stylus (https://add0n.com/stylus.html) to do CSS, so you
           | could write it like this:                 #wrapper {
           | margin: 0 auto;       }
        
         | kibwen wrote:
         | Ctrl+Shift+K for the web console, then
         | `document.body.style.display = "flex";
         | document.body.style.justifyContent = "center";`.
        
         | kps wrote:
         | Text becomes hard to read when lines are much over 70
         | characters. I don't know that there's a universally preferred
         | solution. Personally, I only use movie-shaped windows for
         | movies, and page-shaped windows for everything else.
        
         | avtar wrote:
         | Firefox has built-in reader view, and whatever the Chrome
         | equivalent is.
        
       | ebresafegaga wrote:
       | This sounds like view patterns in Haskell / active patterns in F#
        
       | cinericius wrote:
       | Since the author mentions at the end that they were motivated to
       | write and publish this as a part of a writing group, I'd like to
       | say that this was a very pleasant read. Tightly-scoped but
       | insightful and informative!
        
         | Monadic-Cat wrote:
         | Thanks! (Post author. I made an HN account to reply here,
         | haha.)
        
       ___________________________________________________________________
       (page generated 2023-04-16 23:02 UTC)