DEV Community

Cover image for Static Typing in Elixir
Adolfo Neto
Adolfo Neto

Posted on • Updated on

Static Typing in Elixir

🆕 Type system updates: moving from research into development

I am not a big fan of static typing. Or, rather, I am not someone who prefers static typing. (Read this great blog post, 'Programming types and mindsets,' by David Heinemeier-Hanson to understand it.) But I really appreciate the work of José Valim, Giuseppe Castagna, and Guillaume Duboc.

Here are some links that you might find useful:

Archived tweet

I am curious to see what the community will think. And do different segments of the community react differently? For instance, senior developers may love it while beginners may hate it. This is just a hypothesis that could be scientifically evaluated.

Top comments (3)

alchemist_ubi profile image
Yordis Prieto • Edited

Once a strong advocate for the camp that believed "I don't need types," I've found my stance shifting after seven years in the Elixir ecosystem. My craving for some form of static typing has grown, despite being aware that it's not the one-size-fits-all solution to every issue.

Admittedly, Dialyzer does exist as an option, but it's not perfect. While it has its uses, it lacks in user-friendliness and requires significant improvement. I believe that instead of introducing static types to Elixir outright, enhancing Dialyzer should be our first step. Please note, I'm not objecting to the idea of static types in Elixir.

However, it's crucial to remember that types are not a replacement for robust software architecture or diligent unit testing. They're not a panacea; they're merely another tool in our arsenal, ready to be leveraged whenever they make sense. Ultimately, it's essential to trust and allow developers the freedom to use these tools in ways that suit their workflows best.

Developer Experience: A Key Aspect

When I refer to an "IDE", I mean an Integrated Development Environment or Language Server Protocol (LSP).

Without static information about the codebase, there's a limit to what an IDE can do for you. When it comes to navigating a codebase or introducing new people to it, the absence of static types often complicates things. I've observed developers getting lost, struggling to figure out what to do, or spending an excessive amount of time inspecting data structures to understand the system's data flow.

Mastering the toolkit makes things easier, but I believe in optimizing for the least experienced user without compromising accuracy. Personally, I prefer to let the IDE assist me rather than remembering where every piece of information resides. While developers and teams have their own methods for organizing modules and files, scaling an organization and codebase can be challenging without the right tools.

Moreover, developers should be able to autocomplete, refactor codebase-wide, and utilize other productivity-enhancing features. I'm not saying static types are the only solution here, but there is a current pain point that Dialyzer alone can't solve.

Validation at Every Layer: A Necessity

If you have time, please take a moment to read the blog post Parse don't Validate and watch Domain Modeling Made Functional - Scott Wlaschin YouTube Video for further context.

I strongly adhere to the principle of "Garbage in, Garbage out." Validation should not be required ubiquitously across a codebase. Instead, at some point, there needs to be architectural trust in developers' abilities, complemented by thorough unit testing and programming language features.

In an ideal scenario, data validation would occur at the edges, dealing with user input, where data correctness cannot be guaranteed or controlled. Within my system, the type system would enforce a certain level of correctness. This isn't an all-or-nothing situation—I understand arguments about process message passing—but other ecosystems have managed to figure it out.

However, without static types to ensure data correctness, the absence of validations at runtime throughout the source code—or compensatory trivial unit tests—makes things difficult. I don't believe it's reasonable to simply tell programmers to "be more disciplined". Furthermore, we shouldn't need to validate information so extensively within a system when parsing should suffice.

Many end up using Ecto to validate edge data and then repeat validation in domain commands, queue processors, and so on. Additionally, the absence of a type system to enforce data correctness allows anyone to bypass "Factory Functions" and create data anywhere, thus disregarding necessary validation layers.

codewander profile image
codewander • Edited

I think my development cycle is faster with types because it feels slower to run unit tests than it does to compile in something like elm or ReScript. I get some validation by interactively testing in iex when I make a small change, but I don't feel ready to ship a change until a unit test has been added or updated. In elm, I feel comfortable shipping many simple changes without a unit test.

I think it's possible to avoid revalidation at multiple layers if you simulate parse-dont-validate with adt using tuples like "{: validated, int()}", and strong conventions about what can construct those validated tuples, but I agree that real static types would give you more confidence with such validated data.

matheuscamarques profile image
Matheus C. Marques

Debugging code can be a challenging task, especially when dealing with complex logic and recursive functions. One approach that can simplify problem-solving is the use of static typing. By applying static typing, developers can abstract the problem by hand more easily. However, it's important to note that the decision to use static typing should be strategic, as not all problems require extensive complexity and complications.