They're making huge progress on automated type checks in the Elixir compiler. As with many dynamic languages, Elixir is pretty fast to write the first time. But error-prone refactoring is the...
They're making huge progress on automated type checks in the Elixir compiler. As with many dynamic languages, Elixir is pretty fast to write the first time. But error-prone refactoring is the widely recognized shortcoming, because it's easy to introduce bugs where function calls and signatures no longer match up. That's a big reason why test-driven design is widely used with dynamically typed languages.
The people working on Elixir have known this for years, and have been working for years on some novel approaches in the compiler to infer types at compile time.
Now in the age of LLM programming, type inference is even more of a necessity, because an LLM could get the code subtly wrong the first time, and a coding agent needs a way of checking its work. Ideally as a first step before resorting to generating an entire unit test suite. Excessive unit tests are also an additional maintenance burden (and LLM tokens = money).
This reminds me a lot of Crystal's type system. Crystal started out as "Ruby but statically typed and compiled". It's since evolved into its own thing and isn't commited to Ruby compatibility, but...
This reminds me a lot of Crystal's type system. Crystal started out as "Ruby but statically typed and compiled". It's since evolved into its own thing and isn't commited to Ruby compatibility, but they did have to solve many of the same problems as Elixir. It allows you to omit type annotations in most cases, with extensive use of union types and flow typing. Flow typing is awesome. It basically captures the intuition of "this thing can be X or Y, but within this particular branch we know statically that it must be X (because we have performed a runtime type test as a branch condition), so we can narrow the type of (X or Y) to X within this particular branch safely."
The inference for the pattern matching is something I haven't seen to that extent before, so that's cool. On the other hand, not having parametric polymorphism or recursive types yet is a major limitation. Crystal solves this by requiring you to be explicit about parametric types, i.e., it won't try to infer the concrete type of a generic type like Array(T); you must specify the type of T when instantiating an empty array. It's one of the few places in the language where you cannot ever omit an explicit type.
They're making huge progress on automated type checks in the Elixir compiler. As with many dynamic languages, Elixir is pretty fast to write the first time. But error-prone refactoring is the widely recognized shortcoming, because it's easy to introduce bugs where function calls and signatures no longer match up. That's a big reason why test-driven design is widely used with dynamically typed languages.
The people working on Elixir have known this for years, and have been working for years on some novel approaches in the compiler to infer types at compile time.
Now in the age of LLM programming, type inference is even more of a necessity, because an LLM could get the code subtly wrong the first time, and a coding agent needs a way of checking its work. Ideally as a first step before resorting to generating an entire unit test suite. Excessive unit tests are also an additional maintenance burden (and LLM tokens = money).
This reminds me a lot of Crystal's type system. Crystal started out as "Ruby but statically typed and compiled". It's since evolved into its own thing and isn't commited to Ruby compatibility, but they did have to solve many of the same problems as Elixir. It allows you to omit type annotations in most cases, with extensive use of union types and flow typing. Flow typing is awesome. It basically captures the intuition of "this thing can be X or Y, but within this particular branch we know statically that it must be X (because we have performed a runtime type test as a branch condition), so we can narrow the type of (X or Y) to X within this particular branch safely."
The inference for the pattern matching is something I haven't seen to that extent before, so that's cool. On the other hand, not having parametric polymorphism or recursive types yet is a major limitation. Crystal solves this by requiring you to be explicit about parametric types, i.e., it won't try to infer the concrete type of a generic type like Array(T); you must specify the type of T when instantiating an empty array. It's one of the few places in the language where you cannot ever omit an explicit type.