The Design Principles of the Elixir Type System [pdf]
irif.fr
irif.fr
1. Scroll down to "Girard's Paradox" here: https://en.wikipedia.org/wiki/System_U
f :: () -> T
f x = f x
myT = f ()
What this shows is that Haskell types are not sound as a logic, but that doesn't mean they aren't a fine type system.I wonder how that will work with Ecto schemas, or if it will work at all. Ecto Schemas do not specify required/optional keys, the Changesets do. But Changesets only exists in runtime. Loosing the ability to reuse the schema and have required/optional keys defined on the changesets would be a huge step back in my opinion, but pretty much all the type systems I know work that way.
The type system they propose is based on the framework of semantic subtyping and includes several new features and improvements:
Semantic subtyping: The authors extend the semantic subtyping framework to fit Elixir/Erlang, particularly defining new function domains to account for the tight connection between Elixir/Erlang functions and their arity.
Guards: They develop a precise type system for analyzing guards in pattern matching. Records and dictionaries: The authors propose a new typing discipline unifying records and dictionaries.
Dynamic type: They integrate the dynamic type into the type system, which is used to describe untyped parts of the code and how they interact with statically typed parts. This uses techniques from the gradual typing literature.
Strong arrows: The authors introduce a new gradual typing technique for typing functions that takes into account runtime type tests performed by the virtual machine or inserted by the programmer. This allows for more precise static types without modifying the source code compilation.
The implementation of the proposed type system for Elixir faces several challenges:
Performance and Usability: The authors are concerned about how the type system will perform on large code bases and how the community will interact with and use the type system. They plan to introduce the type system gradually to assess its performance impact and the quality of the reports it can generate in case of typing violations (Page 24).
Type Annotations: The introduction of typing must not require any modification to the syntax of Elixir expressions. The system must extract a maximum of type information from patterns and guards. Programmers who prefer a fully statically typed environment should be able to reduce the reliance on gradual types within their code by emitting warnings when dynamic() is used (Page 21).
Structs: The second milestone is to introduce type annotations only in structs, which are named and statically-defined closed record types. By propagating types from structs and their fields throughout the program, they aim to increase the type system’s ability to find errors (Page 24).
Function Annotations: The third milestone is to introduce the $-prefixed type annotations for functions, with no or very limited type reconstruction. Users can annotate their code with types, but any untyped parameter will be assumed to be of the dynamic() type (Page 24).
Row Polymorphism: To type functions operating on maps, row polymorphism is needed, but extending semantic subtyping with it is an open problem the authors are working on. They also plan to study how to remove the constraint that key-types must be chosen among a predefined set of types (Pages 25-26).
Message-passing: Typing the concurrency constructs and the actor model of Elixir is an obvious next step. Elixir's concurrency and distribution system is based on message-passing between lightweight threads called processes (Page 26).