`assoc` and `dissoc` handling of lists is inconsistent with maps
krader1961 opened this issue · comments
A recent question on the IM channels caused me to notice that the assoc
and dissoc
builtins behave very differently for maps compared to lists. Specifically,
-
assoc
can create new keys in a map but not append to a list, and -
dissoc
can delete keys in a map but not elements in a list.
I can't see a good reason for the inconsistency in how those two commands handle maps and lists. Also, the documentation implies, to a casual reader, that they modify the structures "in place". It would help if there was at least one realistic example showing that you need to assign the result of each command to a var. For example, something like this:
> var m = [&k1=a &k2=b]
> set m = (assoc $m k3 c)
> repr $m
[&k1=a &k2=b &k3=c]
Also, it is not clear that there is a net benefit from having del m[k1]
(building on my previous example) be equivalent to set m = (dissoc m k1)
. I've always liked the Python maxim that "there should be one-- and preferably only one --obvious way to do it." If both formulations are going to be retained then the documentation should make the equivalence clearer (via appropriate links between the two commands).
Lastly, once the shortcomings above of the assoc
and dissoc
commands vis-a-vis lists are addressed the del
special command should be augmented to also handle lists in a manner analogous to how it handles maps.
P.S., Appending to lists is so common that there should probably be a high performance means of doing so; e.g., an append
special command rather than set a-list = [$@a-list new-value]
.
Thanks @krader1961 for formalising my IM questions!
@iandol, I noticed the issue you asked about, vis-a-vis manipulating lists, long ago but didn't open an issue because it was only recently that I started writing non-trivial Elvish programs; despite using Elvish as my interactive shell for more than two years. Your questions on the IM channels reminded me that manipulating lists, especially appending to them, is far too expensive and cumbersome. Not to mention that common patterns, such as appending to, or deleting from, a list, is woefully under documented. Hopefully this issue will improve the situation; at least from a documentation perspective if not a performance perspective.
I did want to mention, from my perspective as a general user without any formal programming education, assoc
and dissoc
were not obvious to me in terms of things that could manipulate lists (I know nothing about clojure, from where I see assoc is inspired). The first thing that did come to my mind (before I read the docs at least) was set
(count+1) and del
. The meaning of delete to remove a variable or an element makes intuitive sense. However as @krader1961 is proposing a more consistent interface to add and remove items, then I suspect that assoc
and dissoc
, as long as they are linked from the more general docs about lists would be easy to discover and understand. I think having one consistent interface is better than two. In general this is another case (see also #1652) where I find the inconsistency between lists and maps confusing.
@krader1961 has now formalised his p.s. (noting no way to fast append) in this original issue, here: #1694