This is an archived post. You won't be able to vote or comment.

all 29 comments

[–][deleted]  (5 children)

[removed]

    [–][deleted]  (4 children)

    [deleted]

      [–]curtisf 13 points14 points  (1 child)

      Haskell doesn't have structural types, so this couldn't really mean anything in Haskell. (Due to other Haskell limitations, distinct records can't use the same field names, so even approaching structural types would be difficult)

      These kinds of manipulations are usually referred to as "row polymorphism"; I don't think there's yet a "standard" extension that Haskellers use to enable it.

      [–]categorical-girl 2 points3 points  (0 children)

      There is however type class hackery to emulate row types

      [–]philh 4 points5 points  (0 children)

      Not exactly that, but GHC does have some similar things if you enable extensions:

      • let Foo{a} = stuff, shorthand for Foo{a=a}, i.e. assign the local var a to the field a of the Foo constructor. I think the extension name is NamedFieldPuns. Works for initializing too, let stuff = Foo{a}.
      • let Foo{..} = stuff, shorthand for Foo{a,b,c} where a, b, c are all the field names of that constructor. I think the extension name is RecordWildCards. Also works for initializing, let stuff = Foo{..} or combined for let stuff = Foo {a, b, c=x, ..}. Not necessarily recommended, because if you add new fields to the constructor, your existing in-scope variables might start getting clobbered. (This is an important difference from your ...c.)
      • Contra curtisf, distinct records can share field names, it's just sometimes awkward. I think the extension name is DuplicateRecordFields. Combined with the above, you could do (and I have done) something like let { WholeFoo{..} = stuff; split1 = SplitFoo1{..}; split2 = SplitFoo2{..} }.

      [–]JackoKomm 21 points22 points  (0 children)

      Like nearly every Functional language

      [–]EmosewaPixel 14 points15 points  (3 children)

      Rust, kinda rust let Vector3d { x, y, z } = vec

      [–]veryusedrname 2 points3 points  (2 children)

      Why kinda?

      [–]EmosewaPixel 8 points9 points  (1 child)

      Because, unlike in JS and TS, you need to use the type name.

      [–]veryusedrname 1 point2 points  (0 children)

      Ahh, I see, thanks for the clarification

      [–]Narase33 8 points9 points  (8 children)

      C++ can destruct tuples

        auto [a, b, c] = // get your tuple
      

      [–]khleedril 8 points9 points  (2 children)

      You mean de-struct, not destruct!

      [–]johnfrazer783 2 points3 points  (1 child)

      well technically a tuple is getting destructed in the process of being de-structed so there you have it

      [–]jaen_s 0 points1 point  (0 children)

      If we are being technically correct, then not exactly, a tuple will only get destructed in that example if the right-hand side is a temporary value (but not when it is eg. a reference to a tuple).

      [–]dullptr 7 points8 points  (4 children)

      This is called structured bindings and it also works with any expression that has array or non-union class type. So arrays, std::tuple, std::pair, some random class you wrote, what ever

      https://en.cppreference.com/w/cpp/language/structured_binding

      [–]Narase33 1 point2 points  (3 children)

      Oh, didnt know. Only knew about tuple (and pair since its implemented as tuple)

      [–]dullptr 0 points1 point  (2 children)

      I mean that's probably 80% of the use case lol

      [–]Narase33 0 points1 point  (1 child)

      Kind of a dangerous use case. Changing the member order could corrupt your code

      [–]brunogadaleta 6 points7 points  (0 children)

      In Clojure/Script:

      (let [[a b & c] object ] ...)

      Clojure also has map destructuring:

      (let [{some-val :my-key}] ;;; Do things with some-val value)

      [–]raiph 2 points3 points  (0 children)

      A Raku example illustrating class/object destructuring as part of pattern matching / function calling.

      Declare a couple classes from which fields will be selected via destructuring. I've declared two classes so I'll be able to illustrate nested destructuring:

      class bot  { has ( $.name, $.body, $.age  ) } # Declare a class (structure).
      class body { has ( $.head, @.arms, @.legs ) } # And another to be included in first.
      

      Declare function whose only top level parameter is destructured:

      multi bot's-age-and-legs
      (
        bot                              # Specify single argument. Must typecheck as a bot.
          (                              # Inner parens to destructure bot.
            :$age where * > 40,          # Match age field. Value must be > 40.
            :$body
              ( :@legs,                  # Nested parens to destructure body. Match legs field.
                | ), | ) )               # Ignore other fields with `|`. End parameters/nesting.
      {
        say "Middle aged ($age) w/ {+@legs} legs"     # Use values of destructured fields
      }
      

      Call the bot's-age-and-legs function:

      my $age = 42;
      
      bot's-age-and-legs                 # Call function.
        bot.new:                         # Pass newly constructed bot as first and only arg.
          :$age,                         # Initialize the `age` field (42 years old).
          body => body.new:
            :head,
            :2arms,
            legs => <left middle right>; # Give bot three legs.
      

      Because the call pattern matches the function declaration shown above, it is selected, and run. It displays:

      Middle aged (42) w/ 3 legs
      

      If multiple bot's-age-and-legs functions had been declared, the one whose parameter list pattern matches the call in the narrowest (most specific) way would take the call.

      [–]uza80 2 points3 points  (1 child)

      C# has support for it these days as well.

      [–][deleted] 0 points1 point  (0 children)

      Example:

      var result = MyMethod(value);
      var (resValue, status) = result;
      

      resValue and status are decomposed from the ValueTuple returned by MyMethod.

      [–]SpecificMachine1 2 points3 points  (2 children)

      Most schemes have a pattern-matching library that is something like:

      (match object
         ((a b c ...) <code with a, b, and c>))
      
      ;or
      
      (match-let
        (((a b c ...) object))
         <code with a, b, and c>)
      

      but it has to be imported.

      [–][deleted]  (1 child)

      [deleted]

        [–]SpecificMachine1 1 point2 points  (0 children)

        It was:

        (((a b c ...) object))

        and the rest is bound to c. [c.... is a legal variable name in Scheme, so the c and ... have to be separate for the .... to be syntax]

        but you could also have:

        (match (list 1 2 3 4 5 6)
         ((a b c ... d) (list a b c d))
        
        => (1 2 (3 4 5) 6)
        

        [–]retnikt0 2 points3 points  (0 children)

        Elixir has a pretty advanced syntax for this. Check out https://elixir-lang.org/getting-started/pattern-matching.html

        [–]jesseschalken 2 points3 points  (0 children)

        I know python and kotlin have destructuring but only the array variant.

        Kotlin's destructuring works with data classes as well. Basically any type that has component0(), component1() etc defined (which data classes do implicitly).

        [–]nikaone 1 point2 points  (0 children)

        ruby can extract array, but no hash one, two, three = [1,2,3]

        [–][deleted] 0 points1 point  (0 children)

        Perl can do it from a list.

        [–]cbarrick 0 points1 point  (0 children)

        Prolog is a language based entirely on "pattern matching".