OvermindDL1
Just got an idea on how we could get a strongly typed elixir ‘now’. Imagine this:
import TypedElixir
defmodulet TypedTest do
@moduledoc false
@spec hello() :: String.t
def hello, do: "world"
end
Or whatever for a name instead of defmodulet (I’m horrible with names) right now it is just a typed version of defmodule. It could start by enforcing @specs, then another pass to ensure that the inner function calls also follow the spec of the function by checking the specs of the other calls. Any calls that are not @specd outside of the enforced defmodulet bounds would require some type of @spec elsewhere. You could also @spec variables inside a function if so wished (better debugging to make sure you are passing things around right), but otherwise make sure that they are used properly in the function. If your spec does not match the def/defp usage then it would error, giving both what it detects it should be and what it is.
Even if I have to @spec everything in my program, I would so far beyond love getting compiler errors for mis-using types. Absolutely requiring @spec on def/defp when within a defmodulet makes type inference within the function significantly easier to reason about both for the coder and for the TypedElixir library.
It would indeed by quite nice if such type checking was added to the base defmodule, we could even pass in a @strict_types as a module attribute or so to enforce the above (require accurate @specs, not too generic, etc… etc…) but otherwise backwards compatible to now but with occasional helper messages at compile-time like This will always fail as you cannot add an integer and a string as these bindings will always be an integer and a string or so. A default compile would not cross-module type-check unless a special flag would be added or @strict_types were specified or so, which would then cause the compiler to load the other modules to acquire their typespecs, which could increase compiling time admittedly, but only one level deep may not be noticable.
My motivation for this is 95% of my bugs in Elixir/Erlang are due to using types wrong, like I may slightly change a tuple format somewhere but do not update it elsewhere and dialyzer does not catch it because the prior library state was in its cache that I then need to rebuild, in addition to dialyzer can take a long time to run. And honestly I just do not want an incorrect program to compile at all, I want it to be noisy and fail at compile-time, not run-time. Even a little bit of extra checking then would save so much pain.
Either-way, I made a TypedElixir library of the above, only thing it does so far is check that @specs exist on each def/defp as I play around with it (literally mix new’d it <5 minutes before this post), does not expand macros first or anything yet (should probably be next step). I’m curious on ideas on if this is a good idea or if I should not bother with the effort?
EDIT0: The expansion and some clean-up done, still only checking that @specs exist, nothing else yet…
Trending in Discussions
Other Trending Topics
Chat & Discussions>Discussions
Latest on Elixir Forum
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #genstage
- #ai
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










First 10 of 28 Posts
OvermindDL1
Given this module:
So far it just tests if specs exist, but it is a start. Verbosely it prints out this at compile-time:
I wonder if
@types can have arguments to make them parameterized… if not I should support that if possible or make a new one… I do not have too much time to work on this but at least it is a start if I confine my code to a certain style…benwilson512
Typing is hard.
I don’t know how you’re gonna handle stuff like ^
benwilson512
Types can be parameterized in the following way:
OvermindDL1
That is the challenge, I am curious if it is even possible in Elixir. So unless someone finds a case that is truly beyond difficult or impossible, I may work on it little by little over time.
Oh, and in that case with receive, I’d try to throw some error like (in the optimal case):
Or something like that. I want to be forced to put typing on anything and everything that is ambiguous, that is how you catch a lot of bugs.
OvermindDL1
Been playing with more, slowly building a DHM inference engine with dependent types (mostly a learning exercise), not working yet but would be nice to get something like this:
Not my preferred syntax but the Elixir parser is unforgiving for what I would prefer (without resorting to strings, blehg). This would define a
Testing.div/2function that accepts any number in its first argument, any number that is not 0 in its second, and can return any number. Basically if you tried to do something like:Then on the line with the
Boomcomment it would fail to compile due to unmatched constraint or so, you would have to do something like this instead:Or something that would actively refine the constraints of i to not include 0.
I doubt I will finish this, I think I’d be more apt to write an OCaml backend to Elixir, but this is still a fun very-slow-moving-project. ^.^
EDIT: Yeesh, this was two months later? I really do have about no time… Wish I could get paid to do this. >.>
gon782
sashaafm
How would you go about to writing an OCaml backend to Elixir? That idea seems very interesting, but I don’t see how that would bring static typing to Elixir?
OvermindDL1
It would be to supplement Elixir. Any module you made in OCaml would output an Elixir module of the same name. You could call into it from normal Elixir code, and you could call normal Elixir code from the OCaml-output-version by the ‘external’ declaration, that is the easy stuff. Everything within a module you’d know would be typed-safe, so as long as the external Elixir modules call it right (and I could always add when checks and assertions and such at public points to verify) then no worry about something stupid within (like me passing a user object in the room field in one of my projects here…). Could slowly convert your code to OCaml or just add it as you go. The more you’d have, the safer the overall project would be.
OCaml itself does not have dependent types (few ML languages do, Haskell does not either), but you can emulate them via typed modules and probably GADT’s… Just playing with the idea of them in my playground here.
DianaOlympos
Just so you know, the problem Philip Wadler found when he tried to type erlang :
self ()The other question is… how do you deal with distributed message. You can get a message from a node that do not follow the comtract you assigned. So your type checking is useless in that case…
michalmuskala
Another thing that makes typing erlang/elixir really difficult is dynamic loading of modules. The function you’re using may actually not exist yet when you’re writing it, the module may be loaded later. Not to mention hot upgrades that completely mess stuff up.