[HN Gopher] Show HN: es6_maps, new Elixir syntax feature via run...
       ___________________________________________________________________
        
       Show HN: es6_maps, new Elixir syntax feature via runtime compiler
       hacking
        
       Hi HN! I thought you might enjoy this even if you don't know much
       about Elixir.  `es6_maps` is a small library that introduces a
       "shorthand" map creation syntax, similar to shorthand object
       construction in JavaScript/TypeScript. For those unfamiliar with
       Elixir, the most interesting aspect might be how it achieves this.
       `es6_maps` takes advantage of BEAM (Erlang's VM) hot-reload
       capabilities to amend the Elixir compiler bytecode at runtime,
       adding functions that expand the shorthand syntax for further
       compilation. I think it's a nice showcase of the power you can
       wield (with care) when writing in BEAM languages.  Let me know what
       you think!
        
       Author : kzemek
       Score  : 58 points
       Date   : 2024-05-12 11:17 UTC (11 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | arrowsmith wrote:
       | This is great!
       | 
       | I've always thought that if I could change one thing about
       | Elixir, it would be to add exactly this shorthand syntax that I'm
       | used to from JS. I'm sick of having to type everything twice,
       | like e.g. `%{foobar: foobar}`.
       | 
       | I'm impressed to see it implemented. I didn't know it was
       | possible to pass custom compilers to your Mix project definition
       | - but now that I think about it, I can see how Elixir's
       | metaprogramming features would lend themselves well to
       | implementing custom syntax like this.
       | 
       | Fantastic work, all I want to know is why Elixir doesn't have
       | this syntax built-in already.
        
         | dudul wrote:
         | > I'm sick of having to type everything twice, like e.g.
         | `%{foobar: foobar}`
         | 
         | I'm actually very confused by this use case. How often do you
         | have to do that? Fill a map with kv tuples where keys and
         | values have the exact same value?
        
           | cmoski wrote:
           | the key is an atom called foobar, and the value is being
           | extracted to a variable called foobar. The variable's value
           | is not shown in the example.
           | 
           | You do this quite a bit in Elixir, unless you use the .
           | syntax, e.g. somemap.foobar which is marginally slower.
        
             | dudul wrote:
             | Got it - I misunderstood the short code sample, I thought
             | the 2nd half of the tuple was a literal instead of a
             | variable. Makes sense.
        
           | gmassman wrote:
           | This pattern appears frequently in just about all programming
           | languages. I've written a lot of JS and Python, and a
           | moderate amount of Elixir, and this pattern crops up quite
           | often. Usually it's a side effect of complex scopes with
           | several layers of function calls.
           | 
           | Honestly I'm a little surprised you haven't seen this
           | pattern. The only times it wouldn't be used are when people
           | rename variables, which is frankly a practice I abhor.
        
             | leononame wrote:
             | JS and python are just about all programming languages?
             | 
             | I'm not trying to be snarky, but e.g. I haven't seen it in
             | Go, F# and Rust, some languages where I have at least seen
             | _some_ code. I also don't remember a similar pattern in
             | Java, C# and C nor PHP or Dart, but I will readily admit
             | that it's I haven't coded in any of these in the last two
             | years, so I might be a bit out of touch and I'm not super
             | proficient in all those languages
        
               | boxed wrote:
               | Go, and F# do almost all positional arguments. I think
               | Rust too. Java, C#, C, PHP are also positional only or
               | 99% of the time. I assume Dart too.
               | 
               | We are talking named/keyword/etc.
               | 
               | Personally I find positional arguments to be an anti-
               | pattern in all but a very specific set of circumstances.
        
               | debugnik wrote:
               | C#, F# and PHP all support named arguments and they're
               | quite common for optional parameters.
        
               | leononame wrote:
               | If I understand correctly, we aren't talking about
               | named/keyword arguments. This is about a shorthand syntax
               | in ES6 objects, nothing to do with function arguments.
               | 
               | In JS, when creating an object, instead of writing {name:
               | name}, where "name" is both the key in the map as well as
               | the variable you want it to assign to, you can do {name},
               | whereas e.g. in Go you would do map[string]any{"name":
               | name}.
               | 
               | Edit: Or, for completeness' sake, it's the same with
               | structs in Go, where you would instantiate a struct like
               | this: Person{name: name}.
        
               | pflanze wrote:
               | If we're talking about constructing structs, like in `Foo
               | { bar, baz: 123 }` (with the `bar` style shortcut in it),
               | I have used that kind of syntax 10 times in 16 KLOC of
               | Rust. Not a lot, but it does happen, and I found it kinda
               | neat when LSP integration suggested its use.
               | 
               | I've probably used it more for pattern matching (`let Foo
               | { bar, baz } = ...`), but haven't measured the number of
               | instances of that idiom.
        
               | leononame wrote:
               | You're right constructing struts in Rust works with that
               | pattern, so I'll take the Rust bit back.
        
           | cess11 wrote:
           | The use of : in 'foobar: foobar' here is syntax sugar for
           | :foobar, foobar
           | 
           | where :foobar is a symbol that evaluates to itself and foobar
           | evaluates to the value the variable points to.
        
       | cmoski wrote:
       | Does it work for nested maps?
        
         | kzemek wrote:
         | Yes it does!
        
       | jzimbel wrote:
       | This was done previously with the `short_maps` library, which the
       | author--a member of the Elixir core team--eventually retired and
       | archived due to regrets from the undesirable impacts on clarity.
       | 
       | https://github.com/whatyouhide/short_maps
       | https://andrealeopardi.com/posts/a-story-of-regret-and-retir...
        
         | MrJohz wrote:
         | That's quite surprising to me. As someone who writes a lot of
         | Javascript, I usually find it easiest to read with this syntax
         | than without it, and I generally recommend to my team that they
         | use the shorthand where they can. This is because the meaning
         | is clear and well-known, and being concise (while still being
         | clear) is very valuable.
         | 
         | I wonder what specifically the original author found made it
         | more difficult to read. Was it unfamiliarity? They allude to
         | some confusion between sigils and strings, so I wonder if the
         | issue was partly an Elixir-specific one.
        
           | igsomething wrote:
           | The map '%{username, age, first_name, last_name}' would be 1
           | character away from the tuple '{username, age, first_name,
           | last_name}'. It is easy to miss the '%' character and you'll
           | waste some time figuring out why your code is throwing match
           | and/or function clause errors at runtime.
        
         | aarongraham wrote:
         | I really don't understand why some people are so against this
         | as a language feature. I get that the community tries to stay
         | away from "magic" but where is the line between magic and
         | convenient syntactic sugar.
         | 
         | For example keyword lists as the last argument to a function
         | don't need brackets, and keyword lists are really lists of
         | tuples where the first item is an atom. I feel like those two
         | things are in some ways less obvious and more magical than this
         | map shorthand.
        
           | hhreefgguu wrote:
           | Magic == "I don't like it, but I want to sound more objective
           | or rational than I really am".
           | 
           | You're definitely correct that there's as good an argument
           | that these implicit features you mention are "too magical" as
           | there is the the "ES6" syntax is too magical.
        
         | kzemek wrote:
         | There was also a relatively popular fork shorter_maps [0],
         | mentioned in the blog post above. My motivation for
         | implementing es6_maps instead of using/updating shorter_maps
         | was (I'm copying from my post in the Elixir forums [1]):
         | 
         | 1. I do firmly believe this is a good language feature and a
         | very natural extension of map literals syntax;
         | 
         | 2. at the same time, being a language feature it should be
         | simple - es6_maps works only with atom keys and has no extra
         | features over the key expansion.
         | 
         | Point 1 is additionally reinforced by how easy it was to
         | introduce to the compiler - I'm injecting just 9 lines of
         | simple code, while parser and lexer already accept short-form
         | maps without modifications.
         | 
         | [0] https://github.com/meyercm/shorter_map [1]
         | https://elixirforum.com/t/es6-maps-ecmascript6-style-shortha...
        
       | rubyn00bie wrote:
       | I personally don't think this is a good idea, and I think the
       | formatter plugin is going to give someone insane amounts of
       | regret one day. It's neat as "look what I did" but Elixir is all
       | about removing magic.
       | 
       | It (lack of magic) is one of the things I appreciated most,
       | having originally come from Ruby and Rails. I've been using it
       | professionally for nearly ten years, and I can say this isn't a
       | feature I've ever really wanted. My text editor can save the
       | typing via shortcuts I type, and in doing so supports string
       | keys, atom keys, has zero compile time dependencies, and no new
       | syntax ;)
       | 
       | I'd really encourage you to put a note at the _top_ of the readme
       | that this shouldn't be used in production code.
        
         | karmajunkie wrote:
         | i don't like adding foundational syntax using libraries, but i
         | do wish they would add this to the language. deconstruction by
         | pattern is super common and the syntactic sugar would be most
         | welcome.
        
         | kzemek wrote:
         | > I think the formatter plugin is going to give someone insane
         | amounts of regret one day
         | 
         | The formatter plugin features a "reverse" flag exactly to
         | prevent any kind of regret like that. You can reformat your
         | code automatically to remove all shorthand maps and remove the
         | dependency in a couple simple steps.
         | 
         | > I'd really encourage you to put a note at the top of the
         | readme that this shouldn't be used in production code.
         | 
         | Noted, although I _do_ think it 's production ready. I'm going
         | to keep updating the library if or when a new version of the
         | Elixir compiler breaks it, and it does feature an easy way out
         | in case I disappear.
        
         | sb8244 wrote:
         | I don't agree that this is magic. It's only "magic" because the
         | language doesn't do it today (thus requiring the compiler
         | extension.) If this were in the language itself, it would
         | probably be pretty popular.
         | 
         | The argument against it feels like "because we've always done
         | it this way."
        
           | oxidant wrote:
           | Agreed. It's just syntax, similar to implicit keywords
           | (mentioned already) and & anonymous functions[0].
           | 
           | Pattern matching a large number of items off a map is
           | verbose. Putting many new keys in a map can be verbose if
           | they're existing variables.
           | 
           | I'd rather have shorter code that was just as readable than
           | many lines that add to cruft.
           | 
           | [0] Reading `&%{foo: &1.bar}` as a new Elixir dev looks like
           | character soup and is arguably more magical.
        
       | vessenes wrote:
       | A good reminder that macros give you super powers!
       | 
       | I don't know a lot of elixir, so I can't say if this is a great
       | idea for inclusion into the standard or not, but it's undeniable
       | that giving macro-based access to the AST adds a lot of
       | expressivity and flexibility.
        
       | bryantwolf wrote:
       | I've been using Destucture [1] for a few years. It's an
       | interesting compromise that works for atom and string keys
       | because it's explicit, kind of like the sigil approach. Though
       | this seems way more streamlined, especially as someone who uses
       | JS for front-end apps.
       | 
       | [1]https://github.com/danielberkompas/destructure/
        
         | kzemek wrote:
         | Oh nice, I didn't know about that one! It's interesting how
         | many solutions are in this space; aside from Destructure[0] and
         | shorter_maps[1] I also know about shorthand[2] and synex[3].
         | 
         | [0] https://github.com/danielberkompas/destructure [1]
         | https://github.com/meyercm/shorter_maps [2]
         | https://hex.pm/packages/shorthand [3]
         | https://hex.pm/packages/synex
        
         | h0l0cube wrote:
         | I like this because it makes the sugaring distinct. Anyone
         | unfamiliar with the sugar will know there's something different
         | going on, while not really adding much noise.
        
       ___________________________________________________________________
       (page generated 2024-05-12 23:00 UTC)