Map shorthand syntax has been proposed for Elixir many times. The support for adding it seems generally positive, but there are people who express concerns. I have wondered when reading those objections about whether they are theoretical concerns from people who have never used the shorthand or people who have used it and have horror stories about all the ways it can go wrong.
For those unfamiliar, what I mean when I say Map shorthand syntax is this (example in javascript):
let x =1;
let y = 2;
let point = {x, y}; //shorthand creation
let polarPoint = {r: 1, t: 2};
let {r, t} = polarPoint; //shorthand assignment
Which would be equivalent to:
let x =1;
let y = 2;
let point = {x: x, y: y};
let polarPoint = {r: 1, t: 2};
let {r: r, t: t} = polarPoint;
The main objections Iâve read are:
It is less explicit. It is not obvious what is going on. It feels like magic.
The variable name has become meaningful. So, for example, if you change the key name, you would also change the variable name.
People may overuse this, with the implication that some of those uses are bad.
What I would like to know is:
Have you used this feature?
What language?
What problems did you have? or why were the problems other people had not a problem for you?
I love it in JavaScript and use it all the time. But I donât think it would be the right thing for Elixir ⊠it doesnât feel like a pattern that would fit in very well.
But its common to use camelCase keys in objects so, I would say it really helps in React Projects, where you have a lot of functions which receive objects as params like a simple PureComponent:
const MyApp = ({ appName, version, currentUsersCount }) => {
return (
<div>
<h1>Welcome to {appName}!</h1>
<p>
You are one of our {currentUsersCount} Users.
This is version {version} of {appName}.
</p>
<h3>Have fun!</h3>
</div>
);
}
Thanks @fuelen, but I wanted to understand problems with the shorthand syntax itself regardless of language. I understand that Elixir has additional complexities around keys and I know there are libraries that attempt to solve it like short_maps, shorter_maps, shorthand, and synex. I would like to understand if there are objections that people using shorthand syntax experience in practice in other languages that we would be bringing into Elixir if we added it.
The problem with tuples is that theyâre positional and when you pattern match them, you have to match the whole structure. With maps, the order doesnât matter, because you can pull out the values by name. You can also match on a subset of the entire map. Itâs rare to see tuples larger than 3 elements. Erlang created records to deal with this problem before maps existed in the language. Ironically, the first discussion that Iâve found talking about adding shorthand to elixir was to use with records.
Iâve used this syntax in javascript and you enumerated all of the issues that I have with it there as well. It encourages a specific style of programming that I think leads to highly coupled code without any indication that its highly coupled. If you change a key in a json object that youâre passing around through all of your functions then you now need to 1) find all the functions that relied on that key and 2) update the code inside the function that also relied on that variable name. I understand why people like the brevity but I donât think that brevity provides much benefit in the long run.
Thanks for responding. I would make the argument that the key name and the variable name are already coupled, in that both are describing the value that they point to. So, if the value they point to changes, such that the name no longer makes sense, I would want to change both. I personally would make that sort of change regardless of shorthand syntax being present.
I suppose you could mean, when the names semantically are similar, they are changed to be the same. I think in this case, you could take the conservative approach and just change the variable name and use a key value pair to give them separate names, because it reduces the things that must change. However, if someone chooses to make the names the same universally, are you saying the code is worse off because of that? Wouldnât you have the same amount of coupling even if shorthand were not used since various other places depend on that maps key?
If you change a key in a json object that youâre passing around through all of your functions then you now need to 1) find all the functions that relied on that key and 2) update the code inside the function that also relied on that variable name.
I dont understand how your point is related to shorthand syntaxâŠ
If your code is either this
function foo(obj) {
console.log(obj.bar)
}
or this
function foo({ bar }) {
console.log(bar)
}
And you change the key bar to baz, you have to search and update it anyway⊠or not?
Indication of coupling could be provided with a typing system like TypeScript
interface MyObject {
bar: string
}
function foo({ bar }: MyObject) {
consoel.log(bar)
}
Unfortunately there are no out-of the box typing in JS, but on the other hand in Elixir we have types, so the coupling problematic wouldnât apply.
Lets say with structs, this would be really awesome:
My point is that in the case of elixir the coupling is obvious. The javascript syntax is highly non-obvious to me. This is a highly personal and subjective opinion but thatâs what this entire thread is about so I guess its fine .
My argument isnât that pattern matching on elixir maps today isnât coupled to the call site. It is. But shorthand syntax makes that coupling even less obvious.
Are you talking about dialyzer or something else? Iâd probably put dialyzer in the same category as TypeScript or Flow. Dialyzer is highly underutilized in my experience.
Maybe Iâve just been writing elixir for too long but I donât understand the appeal of this. Removing explicitness for the sake of brevity doesnât appeal to me.
Iâm using it in JS and tried in Rust while read TRPL. It works there because keys can be only of one type in both of those languages.
Elixir as you know is a different story.
@keathley same observations here! very well put, thanks.
I tolerate this in JS but itâs not my favorite feature
If such thing were added to Elixir weâd have another way to do exactly the same thing on a syntax level, which in my opinion is never good.
This feature would arguably improve readability of code if itâs read like English - what it does or should do, whatâs its intent. The trade off would be the ârealâ readability - what happens. To put it other way: when I scan through the code I want to know for sure and as quickly as possible: this is a function call, these are the parameters, itâs a list, itâs a map, itâs a tuple etc. - such feature would hinder this ability.
So yes, the first of listed points is the deal breaker in my opinion
@lessless If youâre using it in JS and having the same problem @keathley described, why are you still using it? Or did you mean you have used it, but donât anymore?
Iâve used such shorthand syntaxes in quite a variety of languages such as a few ML languages, Haskell, even C++ libraries.
In Elixir I could see it working as such:
%{a, :b} = %{"a" => 1, :b => 2}
1 = a
2 = b
It defaults the most common case to be string and atoms equal atoms in it. Not perfectly happy with it by any stretch, but it seems like a good âcommon case defaultâ and supports mixed values and all just fine (unless you have the same string value of a string and atom key, though you might have other issues in design then).
@yurko Do you have a similar problem with keyword lists not needing to be wrapped in [] when theyâre the last item? I would classify that as a similar feature to map shorthand.
Honestly, this is one thing that trips up everyone that Iâve taught JavaScript to. Some are new and some are âoldâ javascript, but neither understand the syntax right away. Those that have seen pattern matching think its that and are confused why nested destructuring (honestly never heard âpunâ) fails. This will just add complexity to the language to save a few keystrokes for advanced users, when Iâd prefer to have more newcomers picking up the language.