elves / elvish

Powerful scripting language & versatile interactive shell

Home Page:https://elv.sh/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`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,

  1. assoc can create new keys in a map but not append to a list, and

  2. 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.

Note that commit 0b0f5ba introduced a conj command to efficiently append to a list. Since the commit comment does not refer to an issue, and is quite terse, it is unclear what prompted its addition and why that change did not also modify the assoc command to support appending to a list.

@krader1961 has now formalised his p.s. (noting no way to fast append) in this original issue, here: #1694