August 28th, 2024

Typing Lists and Tuples in Elixir

Elixir's new type system introduces sound gradual typing to prevent runtime errors, enhancing list and tuple handling while requiring developers to prove type adherence, potentially increasing boilerplate code.

Read original articleLink Icon
Typing Lists and Tuples in Elixir

The Elixir programming language is introducing a new type system that supports sound gradual typing, allowing for safe interaction between static and dynamic code. This system aims to eliminate runtime type errors by distinguishing between empty and non-empty lists and enhancing tuple handling. The article discusses various approaches to implementing functions like "head" for lists, highlighting the trade-offs between raising exceptions, returning option types, and enforcing type checks at compile-time. It emphasizes that while more precise types can help catch errors, they also require developers to prove their code adheres to these types, potentially increasing boilerplate code. For tuples, the new type system will allow for more specific type definitions, including minimum sizes and dynamic behavior, while still accommodating existing dynamic features. The article concludes by noting that the development of this type system is a collaborative effort, with ongoing support from various organizations.

- Elixir's new type system aims to provide sound gradual typing to prevent runtime errors.

- The handling of lists and tuples will be improved by distinguishing between empty and non-empty types.

- Developers may face increased boilerplate when proving type adherence in their code.

- The type system will support dynamic behavior while allowing for static type checks.

- The development is supported by partnerships with organizations like CNRS and Remote.

Link Icon 6 comments
By @ku1ik - 3 months
I really respect Elixir core team’s approach to adding gradual typing to the language. They don’t rush it. They didn’t put too much focus on syntax so far (I’d argue the syntax in many cases is less important than foundations) and instead they focused on soundness of the system. With each new Elixir version the compiler is getting smarter, catching more bugs. Not hugely smarter, but smarter enough that I feel safer. Looking forward to Elixir 1.18!
By @munchler - 3 months
F# has both a `head` and `tryHead` function to handle lists that may or may not be empty. In general, `tryFoo` is a good pattern for naming functions that might fail.

Having a separate NonEmptyList type might seem like a good idea in theory, but in my experience, it leads to code that is significantly more complicated.

By @yellowapple - 3 months
Looks nice; I dig the $-prefixed type annotations. I also like that the types boil down to familiar conventions like atoms / atom-tagged tuples under the hood; that's exactly how I'd expect an Erlang/Elixir type system to work, and is exactly how I already tend to use tagged tuples.

> If we get rid of this limitations, we could define head as follows:

    $ non_empty_list(a) -> a
    def head([head | _]), do: head
In this case, I ain't sure what the typespec is really contributing here:

- We can already infer the input type, thanks to Erlang/Elixir baking pattern-matching into function signatures

- We can already infer the output type, because there's only one possible output and it's coming directly from the input

This is exactly the problem I hit the last time I tried to chase down the "typespec ALL the things!" path with Dialyzer: the typespecs are just restating what's already obvious from looking at the function, making them redundant at best. Yeah, having a summary of the input and output types is valuable for more complex functions, but it's already a common Erlang (and Elixir, by descent from Erlang and Ruby) best practice to break down complex functions into smaller, simpler units, at which point the typespecs lose value again.

I'm probably missing something here, though - and maybe a more complicated example would better illustrate the value these typespecs add.

By @btbuildem - 3 months
I've always viewed Erlang (and by extension, Elixir) as safe from these types of improvements. Maybe I don't have enough experience in these languages, but having guards, and the different approach to conditionals seemed to do away with most of the pitfalls usually "safeguarded from" by the caution tape and excessive road signage of type systems.

I'm curious to learn more, but I can't shake a feeling of vague trepidation here.

By @ccanassa - 3 months
I love that the creators are considering adding gradual types.

Given TypeScript’s popularity, it’s clear that developers really appreciate types. Honestly, the lack of types is what eventually drove me away from Clojure.

By @29athrowaway - 3 months
Erlang is an influential language, it has its uses.

But Erlang and by extension Elixir are a hard sell unless you are writing a system like Whatsapp.