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.

Reply via email to