Lists vs. Tuples - What to use and when?
ElixirElixir Problem Overview
I am trying to grasp the difference between Lists and Tuples in Elixir
. From the Basic Types section of Elixir Guides, I understand that:
- Lists are stored as Linked Items
- Updating a List is fast (only when prepending)
- Fetching List items is slow
- Fetching List information (size/length) is slow
- Tuple Elements are stored together
- Getting Tuple information is fast
- Fetching Tuple elements is fast
- Modifying Tuples is expensive
Okay, that's all fine but I'm still not sure what to use when. I see that most of the methods return a tuple but everywhere else Lists are used, and many methods accept Lists as input, not tuples. By the stated points above, shouldn't Tuples be used for passing data around, since reading from a tuple of user-given values would be fast?
I also noticed Tuples aren't enumerable, what's up with that? Wouldn't using Enum
over them be faster than using it on Lists?
If someone could help me understand them better, possibly by giving a few examples of what to use when, that'd be awesome.
Elixir Solutions
Solution 1 - Elixir
You've already given a pretty good summary of the differences, so in any conditions where one of those things is important it should help you decide on which to use.
The way to think about it is that Lists are open-ended data structures and their size can vary at runtime while Tuples have a constant size set at compile time.
For example if you wanted to store all the commands the user has given during an iex
session you would want a list - the length of that list will depend on the number of commands given in that session. Contrast this with a typical use-case for tuples - returning {:ok, result}
or {:error, reason}
from a method - here the number of elements is known up-front and so you don't pay an unacceptable price for the performance improvements of Tuples.
As for enumeration - Tuples conceptually aren't collections and every element's position is supposed to also denote its role. Consider an {:ok, #PID<0.336.0>}
Tuple - iterating over it would first give you an :ok
and then a #PID<0.336.0>
, it would be very strange to write a function acting in a uniform way on those things.
Solution 2 - Elixir
I'm no expert but this is my understanding:
Under the hood, a list is a linked list. Hence it's got the performance characteristics of a linked list. That is, getting the length is O(n) because I have to walk the entire list. Likewise a list has the advantages of a linked list as well; that is, it's easy to grow it by adding to the front.
I'm not sure what a tuple is under the hood but I do know it's not a linked list. Someone asked about enumerating tuples on the Elixir language mailing list back in 2013 and this is part of the response:
> "Tuples also aren't meant to be iterated over, don't get confused by > the fact that you could using elem/2 and size/1. Tuples are for > storing multiple pieces of information together, which does not imply > that they are intended for storing a collection."
-- Peter Minten
> "Another explanation would be that tuples are poor man's records. In > other words, a tuple represents a single piece of data, a single > value, albeit aggregate. You cannot take away an element from a tuple > without changing the semantic meaning of that particular tuple value. > > "This is contrary to lists and other collections that store many > values independent values. Taking a value away from list simply > reduces the length of the list. It doesn't affect semantic meaning of > anything."
-- Alexei Sholik
In other words just because there's a superficial resemblance between tuples and lists one shouldn't assume the behavior is the same.
Solution 3 - Elixir
In addition to what already had been said, what helped me differentiate a tuple from the list is analogy to a row in a database. If you think of a tuple this way, it is easy to see how information within the tuple is related to each other and it also becomes obvious why you wouldn't use it as Enumerable.
Solution 4 - Elixir
If you're familiar with Java:
- A list is like a
LinkedList
. - A tuple is like an
ArrayList
.
Solution 5 - Elixir
Tuples are meant to hold a fixed number of elements that's why they allocate memory upfront. Basically tuples are not meant to change (although it's possible but expensive). They provide one piece of related information.
For example: Geographical coordinates {43.258389, -2.924405}
Lists on the contrary are more suited for dynamic collections (they are cheaper to modify).
I found this post very useful: https://blog.appsignal.com/2018/08/21/elixir-alchemy-list-vs-tuples.html
Solution 6 - Elixir
Since someone mentioned that they're not sure what a tuple resembles under the hood, a tuple would be similar to an array since both an array and tuple store elements in contiguous memory. So, the same rules would follow with when you would use an array over a linked list as it would with a tuple over a list in Elixir.