While they look a lot like them, tuples are not an alternative to lists, they are an alternative to structs.
The usecase for tuples and structs is to group together several values that belong together, e.g. because theyâre different attributes of the same thing. You know in advance how many attributes there are, and what they mean.
A list is for a collection of things that are the same âshapeâ. Usually theyâre the same type - i.e. all integers, or all the same type of struct, or all functions. If theyâre different types then theyâre still expected to be handled in the same way. If you have âsome number of things that are all similar but I donât know how many in advanceâ then you want a list, e.g. if youâre reading in a file and you separate it into each line, then you would use a list (of strings).
To go back to tuples and structs, the classic âpersonâ example in so many code examples is good here. For our purposes a person has two attributes - name (a string) and age (a number). Here is how to return each of the options from a function:
As a tuple:
def func() do
{"John", 33}
end
As a struct:
defmodule Person do
defstruct [:name, :age]
end
def func() do
%Person{name: "John", age: 33}
end
The tuple is easiest: you donât have to declare anything in advance you just create it. Users of this function then have to know (e.g. through documentation or convention) that the first element is the name, and the second element is the age. They also get unwieldy when youâve got more than a few elements - you end up with difficult to read code accessing elements. Adding an extra parameter also usually required touching a lot of code Tuples are excellent for pairing up 2 or 3 things together, and passing them around locally (e.g. internal to a module), or where there is a good convention (e.g. the {:error, message} return convention).
For anything more complicated than a couple of elements you want a struct - rather than having to know which position is which member the fields are named. Structs enforce that you havenât forgotten any of the members, allow you to add new members without affecting most code and provide more information to autocomplete and type checking (also pattern matching if you want). Structs are a great choice a lot of the time.
You could also use a map for this purpose, but you usually donât want to. A map is closer to a list in that itâs a collection of an unknown number of items, but rather than looking them up by position in an array, you look them up by name. Structs are actually implemented âunder the hoodâ as maps, but to use them in the way Iâm talking about above you want the guarantees that structs provide. For example, when using a struct you can guarantee that a given field in the struct is present (because Elixir ensures that), whereas with a map you would always have to check in case you were passed a malformed one.