elvish
elvish copied to clipboard
Maybe sort the output of the `keys` command
It would be nice if the output of keys
was in a predictable order; i.e., sorted. Especially in an interactive context the current random order is somewhat annoying:
> keys $str:
▶ has-prefix~
▶ title~
▶ trim~
▶ contains~
▶ trim-suffix~
▶ index-any~
▶ trim-left~
▶ has-suffix~
▶ to-lower~
▶ last-index~
▶ to-title~
▶ contains-any~
▶ index~
▶ join~
▶ compare~
▶ trim-prefix~
▶ trim-space~
▶ count~
▶ to-upper~
▶ equal-fold~
▶ replace~
▶ split~
▶ trim-right~
⬥ keys $str: | to-lines | sort | all
⮕ compare~
⮕ contains-any~
⮕ contains~
⮕ count~
[… and so on …]
But of course you knew that already. I agree that having them sorted is nice to have, as this has been an irritant to me too. But unless this is literally a two line fix (it might be), I wouldn't give this a really high priority at present. For my own uses, I'll just turn the above into a function, possibly without the trailing all
.
I don't know any languages that offer any promises in the order of keys in a hash/dictionary. I agree this would be nice in an interactive context, but then it should be a feature of the editor. Particularly since sorting the output of the keys
command would imply (as mentioned in the chat) coercing all keys to the same type. I personally find the ability to have arbitrary objects as keys useful sometimes.
I don't know any languages that offer any promises in the order of keys in a hash/dictionary.
That is true for hash based maps which is, as you note @zzamboni, a widely used implementation strategy. But there are tree based implementations that do guarantee the order of the keys. And some languages, such as Python, have had ordered dictionaries for a long time. Although, in the case of Python it wasn't the default behavior until very recently.
I personally find the ability to have arbitrary objects as keys useful sometimes.
Me too. I'm not proposing restricting keys to strings. I'm proposing requiring that the keys for a particular map be the same data type; whether that is string, float64, list, or something else. Regardless of the merits of having keys
always sort the keys. Note that @hanche's example for sorting the keys only does "the right thing" for strings:
> m = [&(float64 11)=a &(float64 3)=c]
> keys $m | to-lines | sort
11
3
Since the keys are numbers I would expect the order to be 3, 11. Lists as keys also produce the wrong sorted order when coerced to strings:
> m = [&[1]=a &[1 2]=b &[1 1]=c]
> keys $m | to-lines | sort
[1 1]
[1 2]
[1]
There was an IM/Gitter discussion about this wherein @xiaq pointed out that preserving insertion order is often more useful than sorting the map's keys. Which is why Python's collections.OrderedDict
exists and has recently become the default implementation for its dictionaries/maps. If Elvish static maps like the $str:
namespace are constructed in a fashion where the keys are inserted in sorted order and iterating over the map preserves that order then this issue becomes moot. Other than any requisite documentation updates.
It would be okay if the output of keys
was predictable but not necessarily sorted. Having the output of keys
be based on insertion order would resolve this issue if maps like $str:
had their content initialized with the keys sorted.
Regarding whether map keys should be homogenous this, from "When to release Elvish 1.0", seems relevant:
Static type system. A language without any kind of static type system is not likely to be future-proof. I have this vague idea that Elvish should have an optional structural type system much in the style of TypeScript, but there are many details to be figured out.
Revisiting this I'm going to close this issue. It's now easy enough to do keys $str: | order
. The order
command builtin was added a few days after my previous comment. If someone can make a convincing argument that the default enumeration of map keys should be predicated on insertion order they should open a new issue. I still, however, feel that Elvish map keys should be homogenous. While that is clearly orthogonal to the original intent of this issue I'm still extremely bothered that examples like this are valid Elvish:
> var x = [&x=y &(num 0)=z &[a b]=why]
> pprint $x 369 µs
[
&(num 0)= z
&[
a
b
]= why
&x= y
]
I'm still convinced that heterogenous key types should be disallowed. Note that I am not arguing for disallowing heterogenous value types.
Note that the order
builtin requires the values to be homogenous:
> order [a [a]]
Exception: bad value: inputs to "compare" or "order" must be comparable values, but is uncomparable values
It's not obvious why maps should not include a similar restriction. Certainly the Go language, and pretty much all other languages, require maps to have a homogenous key type.
Closing again, because even though Elvish maps allow heterogenous key types that will rarely be true in practice. And if someone wants to use heterogenous key types they should be aware that order [(keys $map)]
will fail (at least at this time). That inability to use the order
command in that situation does not justify automatically ordering the output of keys
since doing so could be accomplished by an equivalent modification to the order
command to support heterogenous value types. Ultimately Elvish should either require map keys to be homogenous or the order
command should be modified to support ordering heterogenous value types.