Fl4m3Ph03n1x

Fl4m3Ph03n1x

How hard would it be to have a static typing system in Elixir?

Background

This question comes mainly from my ignorance. Today is Black Friday, one of my favorite days of the year to buy books. One book in specific caught my attention:

Tradeoffs

I like types. Yes, they can get messy but after trying JavaScript without them for a few years I eventually came back to FP and typing systems.

I know we have dialyzer, but dialyzer is not that strong. Although it makes a good job at avoiding false positives (i.e., telling you there is an error when there isn’t) it doesn’t catch all the possible errors and a lot of them slip through it.

I understand this was a tradeoff made by the creators, but I just don’t understand what exactly the tradeoff was.

For example, I know BEAM is slower than JVM when it comes to crunching numbers. But I know this is a tradeoff because in BEAM numbers have no limit in how big they can be and in JVM they have. I also know this decision was taken because the creators didn’t want BEAM to spit out errors like NUMBER_TOO_BIG_EXCEPTION or something among those lines.

But with dialyzer, I know very little. So I have some questions.

Questions

  • Why isn’t dialzyer better at detecting errors?
  • What are the main challenges in making a solution for Elixir to have strong typing, when other tools like Flow and TypeScript exist for JavaScript?
  • What is holding dialyzer back from becoming something like TypeScript?

Personal Notes

I am not saying strong typing is superior and everyone should use it. It is fine if you don’t like strong typing, I am sure you have your reasons and those reasons are valid in your context.

What I am trying to do in this post, is understanding why dialyzer is not as strong as it could be in regards to some areas. I like dialyzer and I use it a lot, but I still think there is space for improvement.

Most Liked

rvirding

rvirding

Creator of Erlang

I just want to confirm what has already been mentioned a number of times in this thread: the reason for not having static typing in Erlang was the absolute need for doing dynamic code upgrades of running systems. This was an absolute requirement and if we couldn’t do it then our language/system wasn’t interesting. There aren’t many systems using it today as most try to do rolling upgrades but we didn’t have that option back then so we had to be able to upgrade a running system. Remember we are talking late 80’s early 90’s here.

Some evil tongues says it because we didn’t know how to write type-checking systems but that is totally ridiculous. As we had taught ourselves to write compilers, and done a number of them, to implement virtual machines, and done a number of them, and to implement run-time and os-like systems, and done a number of them as well, then implementing type-checking would not have been especially difficult. It’s not rocket science and it wasn’t then either. Just RTFM.

Whether you like dynamic typing or prefer static typing that is a matter of choice but as I have said for us it was not an option.

On a side note I would say probably the main difficulty with implementing a statically typed language on top of erlang/OTP/BEAM is interfacing to the world outside. I mean you can call any function with any arguments and send any message to any process so the problem how do I make the statically typed part of the system “safe”. And no, processes can’t hide either as with the Process.list/processes built-in functions I can see all processes.

A final note: Erlang/elixir/BEAM is actually strongly typed but dynamically typed not statically typed. If we want to be picky.

lpil

lpil

Creator of Gleam

Great questions! I have some thoughts :slight_smile:

Dialzyer is designed to be applied to existing untyped Erlang codebases in a useful fashion, without having to rewrite the codebase to satisfy the type checker. To achieve this it takes the “no false positives” approach, sort of meaning if it is possible for the code to be successful at runtime it will not emit an error, instead it only errors if it can infer that the code will definitely crash.

The trade off here is that it offers less safety than a conventional type system in exchange for ease applying it to existing code. Personally it’s not a trade off I enjoy, which I why I’ve been making Gleam, a statically typed language for the BEAM.

Typescript and Flow are great examples of projects to apply static types to an existing language. I think their gradual typing (which allows you to incrementally add type checking to a codebase) is much better than the approach that Dialyzer takes to achieve the same thing. Once fully applied the type checker can say that the codebase is completely safe, which is a great thing to be able to achieve.

What stops this existing for Elixir is largely programmer time and knowledge constraints. A system like this for Elixir or Erlang would take a long time to implement, and we don’t have a suitable team of people with the time to work on this.

If we could find some companies to pay for people to work on this full time we could have gradual typing for Elixir. :slight_smile:

It has a different design with different goals. It’s not possible to it to become like Typescript without it effectively becoming an entirely different tool.

I believe it’s a good thing to want to improve the tools we use! Lots of people would get great value from static typing in Elixir, and it hurts no one to discuss these things. If you are not interested the best thing to do is to not participate in the discussions on static typing.

In Gleam it’s fn(Pid(UnknownMessage), reason) -> msg :wink: See here!

19
Post #5
peerreynders

peerreynders

I think we need to be clear that we talking about static strong typing.

My impression is that it’s related to ROI/opportunity costs.

Hypothetically any process can send data to any other process based on a pid. But the value of that pid is allocated at runtime. So static analysis would have to superimpose some (artificial) static constraints on the process structure in order to check whether data being sent from one process is an accepted type in the destination mailbox.

But given that interprocess communication is typically about protocols there is a temporal aspect that static typing can’t cover. A perfectly “well formed” message in the mailbox about to be pulled out can still be “invalid” with respect to the current runtime state of the process.

Then there is the cultural aspect:

https://forum.elixirforum.com/t/what-do-you-think-is-missing-or-needs-improving-in-elixir/2369/47

And I must say that personally type errors are the errors I very rarely make. :smile:

i.e. how much value could improved static typing add to the ecosystem - considering the potential cost of going beyond what dialyzer is capable of doing right now and might that effort be more productively spent elsewhere in the ecosystem?

It’s easy as a technology consumer to want static typing but from the technology provider perspective the cost could be viewed a prohibitive in relation to the perceived benefit (and the potential collateral damage via additional complexity).

Microsoft started developing TypeScript in 2010, 14 years after the introduction of JavaScript. It was made public in 2012 but really didn’t gain significant traction until some time in 2016 likely spurred on by the announcement of Angular 2 in 2015.

TypeScript/Dart/CoffeeScript

TypeScript/Dart/CoffeeScript/JavaScript

React + TypeScript seems to have only really become a thing around 2017. Visual Studio Code was likely another factor helping TypeScript adoption.

TypeScript/Dart/CoffeeScript/Visual Studio Code

To some extent TypeScript adoption has more to do with tooling (VS Code IntelliSense, Webstorm Refactoring Support, Resharper) rather than deliberate adoption of static typing.

This comes at the complexity cost of language constructs (Advanced Types) that exist solely so that the (library/framework) developer can compile-time-programmatically describe to TypeScript how to extract the types necessary for successful type inference.

This isn’t typically a problem for library/framework users but can put a significant additional burden on the library/framework developers. Given the things that you can do in JavaScript (and therefore TypeScript) one will have to become extremely competent with TypeScript’s “type extraction/manipulation language” or perhaps revert one’s code to a more mundane, less elegant, more restrictive, less generic version.

In statically typed languages like OCaml it usually works the other way around. You have to become a competent type wrangler before you get to use some of the more advanced techniques (hopefully safely, as there is typically an unsafe escape hatch).

All of this should create a sense of how much time and effort it took to get TypeScript to the point of where it is today - and this is in an ecosystem with significantly more resources to throw at the problem than the BEAM ecosystem.

And TypeScript doesn’t have to deal with complexities of code replacement or concurrently collaborating runtime processes with mailboxes that can receive messages from any other process in possession of their pid.

So the effort required to push beyond the current capabilities of Dialyzer should not be underestimated - and must be carefully weighed against any potentially gained benefits.

// UnknownMessage is a type that has no values, it can never be constructed!

But UnknownMessage is acknowledging a fundamental limitation:

  1. You can only type the messages you expect to receive.
  2. It also implies that you cannot put a stop to an unexpected message from being sent to you.

And it is (2) that most static typing advocates would have a problem with.

People wouldn’t be too happy with TypeScript if there was no error when a function is called with the wrong data type - and instead of raising a compile time error the function call is simply excluded from the generated source code.

15
Post #9

Where Next?

Popular in Discussions Top

matthias_toepp
I’d love to hear what people think about Wisp, the new Gleam web framework started by Gleam’s primary creator Louis Pilfold. Gleam, alon...
New
ricklove
I was just introduced to Elixir and Phoenix. I was told about the 2 million websocket test that was done 2 years ago. From my research, t...
New
axelson
Decided against including more info in the title, but the gist is that Plataformatec sponsored projects will continue with the assets bei...
New
marciol
Please, let me know if this kind of discussion already took place in another topic . Hi all, how do you consider if is better to build ...
New
jer
I’ve been using umbrellas for a while, and generally started off (on greenfield projects at least) by isolating subapps based on clearly ...
New
und0ck3d
Hello everyone! A few days ago I’ve created a topic here about how people were creating CMSs with Elixir and Phoenix. I’ve been studying...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
wmnnd
The Go vs Elixir thread got me thinking: Would it be too hard to implement a simple mechanism for creating Go-style static app binaries f...
New
joeerl
I’m playing with Elixir - It’s fun. I think @rvirding does give Elixir courses these days. Re: files and database - when I given Erlang ...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

Other popular topics Top

msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43622 214
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
hariharasudhan94
Lets say i have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => "XXX...
New

We're in Beta

About us Mission Statement