DEV Community

Robin Heggelund Hansen
Robin Heggelund Hansen

Posted on • Edited on

De-throning the List

Listen, I have a plan. What kind of a plan, you ask? A cunning one. As cunning as a fox? Yeah, I'd say so. As cunning as a cat that has trained a man to bring her food at the ring of a bell? Yeah... no. I mean, that is pretty clever. Let's instead say that I have an idea which could potentially be a very good one:

I want to remove the List.

Hear me out

Every programming language has a general purpose collection type. Most non-functional languages, like Javascript and Java, uses an array. However, in functional languages it's not too uncommon to see a list. Why is that?

For the most part I suspect the reason is historical. Efficient immutable arrays is a pretty recent invention, first being seen in Clojure back in 2007. Popular functional languages like Haskell, OCaml and Common Lisp are from the 80's and 90's, so it simply wasn't available at the time.

In addition, the list is very simple to implement and get right. And it does have some strong suites. For instance, if you want to access the first element, remove it or even add a new first element, you can do so in constant time. You can also iterate over the collection, from left to right, in linear time, as you'd expect.

But it also has some shortcomings which can be hard to swallow. If you want to retrieve or modify any element but the first, you'll do so in linear time (yuck). If you want to iterate the items from right to left, which you have to do when performing map or filter, you'll have to reverse the list first (yes, really!).

Another thing to mention is that List isn't really suited for a browser environment. Let's take a look at how [1, 2] is compiled down to JS:

{ ctor: '::', a: 1, b: { ctor: '::', a: 2, b: { ctor: '[]' } } }
Enter fullscreen mode Exit fullscreen mode

There's a problem with this though. Once the list gets big enough, browsers (or at least Chrome) will crash due to stack overflow exception. So in Elm 0.19, this is what the same list compiles to:

<core_namespace>$ToList([1, 2])
Enter fullscreen mode Exit fullscreen mode

This is much shorter and will minify beautifully, but also means that every list literal in your application has an extra cost at runtime. An inlined Array wouldn't have these issues.

Because of the issues I've just mentioned, I believe List isn't fit to serve as the default collection type in Elm. I think Array would serve this role better, especially considering it works more like what people are used to from Javascript.

So we'll replace List with Array, problem solved!

Well, not so fast.

First off, the implementation details of Array are hidden inside an opaque type. This is done with good reason, as Array is a tricky data structure to get right. But it also means that there are certain things you cannot do efficiently with an Array, which are trivial to do with a List, like filtering elements until you've found a certain amount.

The Array also seems to be bad at all the things a List is good at. For instance, if you wish to insert or remove an element at the beginning of a List it's a constant time operation. Doing the same with an Array requires re-building the entire data structure, which in comparison is horribly slow.

Finally, there are certain operations that are implemented for List but not for Array, like sort.

So we're stuck with the List then?

That's the thing. I don't think we are. I believe all the problems I've mentioned can be solved, and that's what my cunning plan is all about.

Over the next couple of weeks I'll explain my plan in full. There will be benchmarks, code snippets and maybe even another reference to Black Adder. The plan, as sinister as it is, does require a lot of work however, so I wouldn't count on seeing it implemented any time soon.

Tune in next time to see how we can make Array more flexible.

Top comments (0)