-
Notifications
You must be signed in to change notification settings - Fork 3.4k
The main reasons for multiple assignment and its current default behavior are convenience of use. In practice, I find more common to assign to the same variable (usually when manipulating a data structure) than to match against it, for this reason the default is to allow multiple assignment unless you use ^ for matching. This also avoids the dreaded numbered variables like post0
, post1
and post2
, making code easier to change.
Such decision may introduce trade-offs, but I consider the examples given so far to be invalid because of their premise: "assume in this case that the chunks of code are large and/or complex pieces where the use of a variable isn't necessarily immediately obvious".
If you have large or complex pieces of code, you are going to have bigger problems when maintaining it. The most recommended solution would be to break your code apart into smaller functions, which will be easier to understand for many reasons, one of them being exactly by introducing a new variable scope, so it is easier to see which variables are into play.
Also, tests should help developers catch such scenarios. If you don't have a reasonable test coverage or the code is too large or complex, not only an assignment will be an issue, but also typos and other kind of mistakes will easily make your code explode.
Notice that optional parenthesis in Elixir can also cause the same scoping conflicts, as the introduction of a variable can cause a previous function with arity 0 called without parenthesis to return the value of the variable. Here, similar trade-offs are involved with the same conclusion: the convenience of skipping parenthesis largely overweights the possible lexical scope conflict that may be introduced, since the latter may happen only in big chunks of complex code. In practice, after working with languages which has such behaviors for quite some time, I honestly can't remember when was the last time I was bitten by such issues (if ever).
I would have chosen undefined
instead of nil
if it was actually a recurrent pattern in Erlang APIs but the truth is that it isn't. Some APIs like records and process dictionaries do return undefined, but the majority of them (dict
, orddict
, lists
, etc) APIs don't return undefined
but rather false
or a tuple.
Someone already asked me why not make the ||
operator work on tuples like { :error, _ }
so we can easily wrap Erlang code without nil
. It is basically the same idea of using something else Erlang already returns instead of nil
.
That said, I believe the undefined cases to be few so I chose to go with a terminology which is shorter and more known by developers (nil
or null
) instead of undefined
.