This is a decade-old discussion at this point, and one I've avoided participating in much because I've historically viewed the problem as untractable, and did not have much to contribute.
We want a syntax sugar construct that can interact with the variable binding scope, that visually feels like an identifier but also looks like like an atom or a string <https://groups.google.com/g/elixir-lang-core/c/XxnrGgZsyVc/m/NBkAVto0BAAJ>, or is only used in contexts where the identifier type is clear, or have additional syntax to support both atoms and strings. There's just not a lot of room to play with a single colon, the second-smallest possible punctuation, that doesn't ultimately look close to a tuple, which is another commonly cited issue with these proposals. Working in a single double-quote syntactically can't work because they are matched and would risk breaking existing programs by passively parsing to the next string. Any syntax sugar addition *has* to be a syntax error today, in all possible expressions—typespecs, function heads, etc, to ensure backwards compatibility of existing code. Sigils literals have to reproduce the full complicated parsing of the entire language to turn their strings into good AST for all edge cases, and the sigil-suffix-style clarification of atoms vs strings has never been very compelling to me. It's also unusual for sigil literals to modify variable scope, so I have never much cared for it. This is just scratching the surface of a decade of discussion! However, *I do have one new idea I haven't seen before I thought I'd bring up.* The reply I linked above is in response to an interesting notion: introduce a new unary operator for this purpose. I never saw this idea get much play; the original post spitballs something like: 1.* %{`foo, `bar}* 2. *%{~foo, ~bar}* 3. *%{$foo, $bar}* I realized while playing around in iex this morning: - That we already have an existing unary operator that was not around for all of this historical discussion - That is already a tricky power-user syntax sugar for manipulating variables in scope - That emits a specific compile-time-error today if used on literal atoms, strings, and charlists I am referring, of course, to the capture operator. While *&* is generally used as a unary operator to capture a function, within a capture we allow passing it a number to inject variables into the function scope, ex *&2*. What if we allowed *&* to capture atoms, strings, and charlists as well, only within *%{}* Map literals, to implement this feature? In a sense, "capturing" a variable from the environment for use in/extracting from a Map context, as well as a function context? ex: ``` foo = 1 bar = 2 baz = 3 map = %{ &:foo, &"bar", &'baz' } #=> %{:foo => 1, "bar" => 2, 'baz' => 3} ``` Trying to use *& *in this way today yields: ``` ** (CompileError) iex:3: invalid args for &, expected one of: * &Mod.fun/arity to capture a remote function, such as &Enum.map/2 * &fun/arity to capture a local or imported function, such as &is_atom/1 * &some_code(&1, ...) containing at least one argument as &1, such as &List.flatten(&1) Got: :foo ``` We could overload it further with cases for maps. I'm not sure if complicating this already often-confusing operator is a good idea, but it feels like a good place to me, as it cleanly supports the exact literals with the types you care about, it already can modify variable scope, is already more of a power-user syntax sugar feature, and we already are committed to answering questions about it and guiding newcomers to documentation concerning it. It even syntax highlights well already. I suspect this syntax could even be leveraged within lists to build Keywords, as well, with some more thought. I could even see syntax for explicit struct support, either via the existing assertive access syntax (&.field) or even bare-words identifier access (&field) to encourage this particular usage. With both a struct extension and Keyword extension, you could do something like: ``` [&.host, &.port] = URI.parse( "postgresql://username:password@host:5432/database_name?schema=public") #=> [host: "host", port: 5432] ``` There are still a lot of syntax edge-cases to think through here, though. On Monday, June 26, 2023 at 5:04:40 PM UTC-5 zachary....@gmail.com wrote: > The point wasn't about not typing long names :) Or about remapping. It was > about knowing when I have to know that the keys and corresponding variable > names were different, and when I don't. > > Ultimately I think this either lives in core or nowhere else, and that if > people on a given project didn't like it they could lint it out w/ credo. I > don't feel like "everyone liking a given syntax" is a realistic goal. > > One thing I've seen in common in both the previous thread, the forum post, > and here is that there is more agreement/interest in only supporting this > syntax for structs. I think that may be a good middle ground/compromise for > us to consider. It doesn't preclude us supporting *more* in the future also. > > > On Mon, Jun 26, 2023 at 5:52 PM, Justin Wood <m...@ankhers.dev> wrote: > >> For what's it's worth, I generally see people wanting this for map >> deconstruction instead of construction. When it comes to deconstruction, we >> already have a different syntax for maps with atom keys. >> >> foo = %{bar: "baz"} >> foo.bar >> >> Here is a really contrived example: >> >> `%Struct{some_xy1_stup4d_8345324_name: some_xy1_stup4d_8354324_name} = >> value >> >> >> To me, this contrived example lends itself to not supporting this syntax. >> Personally, if I recieved some JSON or something else that had such a long >> and complicated name, I would opt to somehow shorten the variable name in >> my code. So I would choose to not use this syntax as I would not want to >> have to type that huge variable name multiple times, even with the help of >> auto complete. >> >> Another point to think about is that the internals of our programs do not >> always translate 1:1 through every boundary in our program. UI elements get >> renamed, features get renamed, etc. It is much easier to just rename a map >> key at one of my application boundaries instead of having to rename every >> use of a given variable in order to support this feature. >> >> Just a few quick thoughts. >> >> Justin >> >> -- >> > You received this message because you are subscribed to the Google Groups >> "elixir-lang-core" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to elixir-lang-core+unsubscr...@googlegroups.com. >> > To view this discussion on the web visit >> https://groups.google.com/d/msgid/elixir-lang-core/91427e5d-951f-4bbc-b63e-ffa1eabf3c56%40app.fastmail.com >> >> <https://groups.google.com/d/msgid/elixir-lang-core/91427e5d-951f-4bbc-b63e-ffa1eabf3c56%40app.fastmail.com?utm_medium=email&utm_source=footer> >> . >> > > -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/5388ac1a-eebd-40ef-a0f1-c00c3ad4559dn%40googlegroups.com.