My concern is diversion: that disproportionate resources will be diverted towards a new focal point. Discourse will become dominated by the type system, at the expense of other concerns. Soon enough, the very course of the language will be perceived as resting on the resolution of formerly subordinate issues.
My main concern is when it would be safe to add to libraries for older version support.
I would love to see a couple of versions of Elixir released that know how to ignore any planned new types syntax before the syntax is enabled so that it is easier to offer older version support while taking advantage of new features like typing.
Explosion of complexity. I donât feel comfortable working with a language that I donât fully comprehend. Typescript crossed that line for me. Can the types be kept simple yet still useful? Is there going to be a push for ever-growing list of features for the type system? The most complex code occurs when two somewhat orthogonal features interact with each other (I have bad experiences from C++). How is the type system going to work with macros?
Style mismatch. Having to deal with both the dynamic and typed styles of coding in a single codebase. For example, are we going to have Result | Error vs {:ok, result} | {:error, error} issues?
Degraded code readability. I donât want to have to learn another language on top of Elixir. Typespecs feel foreign to me (e.g. ::) and I always need to have the docs open to declare a behaviour. Mixing types with other code negatively impacts the readability.mistake.
First of all - thanks a bunch for involving the community so early on in this journey that hopefully leads to an awesome type system @josevalim! I really enjoyed reading your early discoveries on what the type system might look like. Here are my top three worries:
An obtuse syntax which makes Elixir type definitions a lot more confusing to read and write. Coming to Elixir from other languages about a year ago one of the hardest things to grokk was actually how to write idiomatic function signatures. Elixir has pattern matching, guard clauses, and @specs, that all hint at what the function params are expected to be. Adding a fourth thing thatâs at least semi-related could potentially make function sigs even more complex.
Language server / IDE integration not being robust enough. Right now the Elixir LS semi-regularly errors out for me and needs to be restarted (when using VSCode). Iâve often been in situations where the LS has stopped working, and Dialyzer therefore gave up on highlighting issues (or even worse, highlighting issues that arenât there any more). If a type system is to be helpful for developer feedback I think these integrations need to be solid as well.
Hard to understand error messages from the type system. I dread reading whatever Dialyzer spits out, and often end up just trying to figure out what the issue is myself instead.
Looking forward to watching the ElixirConf US talk!
I am also concerned about the $ syntax. Most elixir code verbally describes what itâs doing, and creating something that would, unlike the & syntax, be sprinkled throughout almost all files that isnât self-describing feels wrong. I personally would prefer a new keyword or something in combination with the $ syntax that is self descriptive, but there are challenges with doing that too, right?
From my experience as a learner and a teacher any boilerplate adds complexity to understanding. People wouldnât be able to make simple programs fast (in iex) while they are learning and will give up.
Simplicity
I came to Elixir to learn about concurrency, faced easy to read syntax and this gave me ability to learn more about functional like programming and work with processes (actors, real OOP). And oh my processing Is not something simple to get used to even with such concise syntax. I am afraid that language will get complicated and will start to compete with mainstream languages like C++, Java. And Iâll just move to Erlang because I donât understand the point of mainstream languages. I droped Python because itâs a divided language now: there are several ways of types, several ways of concurrency (standart library doesnât work with concurrent frameworks). And I feel more like Defensive Programming aproach with types and itâs not an easy way for programming.
REPL
Are we getting rid from REPL?
For me type system is something more about compilation time errors. Iâd like to let it crash during runtime.
Typecasting: I want to somehow type data structures, and ensure that either I have something like this in my hands or fail hard and fast in my code. Like, interacting with external APIs where I cast/transform received data into something more usable first thing in my code - the ability to hard cast eliminates a lot of âifâ branches later on in the code. My fear: we get types without the casting, like in typescript. I want: in an ideal world something like serde in rust, where I can encode/decode stuff right From/Into (json/xml/âŠ). A huge percentage of company business code usually is concerned with casting data shapes back-and-forth, so for me personally this would be a killer feature.
duplication: the new types should automatically generate dialyzer specs or vice versa somehow - additional markup ontop of functions would be bad.
compilation times: this already is noticeably bad when there is a big phoenix monolith with lots of code and dependencies and then ontop of it dialyzer runs from scratch for a significant amount of time. I see why it is that way and understand the reasons, but at least it shouldnât get much slower.
Yesterday evening I finally watched it as well as your 2023 talk. I agree with most of the things you said in defense of a typing system (in Elixir). Naturally, I also agree with all the cons.
As for how this typing system will look like the only thing I understood was it would be used for interfaces (functions, callbacks) and structures. Now, since I myself already use typespecs for all non-trivial functions, I could get used to it but would still prefer it be optional, just like the typespecs, especially if the ambitions is to type variables within the function body one day. (I would, however appreciate if all your code in LV and other libs/frameworks had typespecs :).
Re the fear of a community split:
In my view thereâs no room for fear that an optional typing system would âsplit the communityâ for as long as this optionality is implemented the same way the typespecâs is i.e. relying on typing where one sees fit. There where itâs not used the compiler should simply assume (correctly) that the proofs and restrictions might not be desired or that the user finds it unnecessarily litter the code. If a typed function invokes a non-typed function, by default the user will get a warning that can otherwise be suppressed on a case by case, module by module or even the application as whole basis. And thatâs it. The time and the market will then judge best where and where to use it or not to use it while no âlegacyâ code would be ever jeopardized.
result in idioms that actually harm code evolution (catch alls/pokemons exhastiveness checks will hide future issues)
destroy âcoding the happy pathâ and âlet it crashâ semantics because the type system creates a tension that promotes the use of nanny coding standards / catchalls which may be well intentioned but ultimately harmful.
not deliver much value vs the significant effort typing âtypesâ to âkeep the compiler happyâ
reduce productivity in the wrong place vs testing
reduce readability, although I think âdoctypesâ would be a nice way to document possible function return values.
be at a layer too high. If itâs not in the core of the beam then we lose the potential for exploiting it for optimisation and also may have an impedance mismatch âall bets are offâ when using Erlang libraries that donât use the type system.
distract the community for a very long time.
end up with multiple rail gauges in libraries, and it is likely to be polarising to the point some will embrace it and some will despise it.
lead to similar outcomes like the early days of C programming before function prototypes, and we would need to declare the function twice, one in K&R style and another using the hipster ANSI C style with prototypes which meant using macros to harmonise the code so it could still compile with non ANSI C compilers.
create a false sense of security. Testing is good, value matching and let it crash is excellent. This already provides more value further than types.
I worry that the type system will make the macro system more complicated or less powerful. Also, I worry that if Elixir does not have some type system it can never be adopted more broadly.
My concern: I hope types do not lead to a break in language continuity. The leap from Python2 to Python3 was IMO disruptive.
I hope types are introduced over a very long time period, in a series of small incremental improvements, with time for the community to absorb each change.
Will this be able to work with existing typespecs as written? I have a concern about duplication of effort.
Iâm concerned about IPC interfaces like Phoenix PubSub and just basic process message passing. How will that work, or will it simply be a limitation on the concept?
How will this work with function heads? With typespecs as written, I canât write a @spec for each head - just one. I want to be able to write a type definition for each function head if I want, though Iâm not sure if the flexibility I want is achievable.
I disagree here. I would say the major use for pattern matching is to pull apart structures and access fields within them, the type testing is very much a bye product of this. And yes, you can write your code to explicitly access fields in a structure but I personally find that pulling them apart in one got with a pattern is easier and clearer.
Syntax differences from mainstream languages may hurt adoption
Using a variation of the proposed $ syntax is quite different from how parameter types are defined inline in mainstream web development languages such as TypeScript, Python, and PHP (the baseline that many developers will be coming from). By using the $ syntax on the line above the function definition, we increase the amount of âoddnessâ to the language for those considering Elixir from these more mainstream languages. People prefer the known over the unknown; there is only a certain amount of âoddnessâ that developers will tolerate.
Community adoption and documentation
The @spec syntax has not been widely adopted among the community. For those considering adding @spec above their function definitions, a challenge is finding good examples and documentation, for example how to use types with Ecto. Without the new type syntax being added to the HexDocs of major libraries, it will be unclear how to use the types, and the path of least resistance will be for developers to not bother adding them. As a result, the new type system would be unlikely to see widespread adoption.
As a library author, I generally want to support all Elixir versions that are officially supported. At the same time, Iâd like to switch from type specifications to the new type syntax rather sooner than later to give library users all the benefits that come with it. Iâm concerned that I (and other library authors) will have to make a choice between abruptly dropping support for older Elixir versions or waiting 2 years until all officially supported Elixir versions support the new syntax.
Iâm worried the new type system wonât fix the pain points I have with Elixir. In Ocaml I can change a type or a function and immediately the compiler will point out every instance that needs to be updated. In Elixir the compiler can only help when a function is no longer found due to the arity changing.
Concern 1: verbosity. The first thing that drew me to Elixir was the clean, compact syntax. I worry this would take a big hit.
Concern 2: not sound enough? If we are going to do types do it 100% imo. I worry a halfân half approach will be worst of both worlds. Dart started out with soft typing and moved to sound typing. Lessons to learn from I think.
Instead of soft types, I would rather Elixir be the best dynamic lang it can be and double down on enforcing better code conventions in the ecosystem to mitigate type bugs and error handling etc. As a newish Elixir mixer Iâm still confused if I should raise exception or return error atom tuple. Also to get more performance out of Elixir I think we could focus on core libraries running Rust under hood. Copy what Python did with C-langs.