Hacker News new | past | comments | ask | show | jobs | submit login

I've always viewed Erlang (and by extension, Elixir) as safe from these types of improvements. Maybe I don't have enough experience in these languages, but having guards, and the different approach to conditionals seemed to do away with most of the pitfalls usually "safeguarded from" by the caution tape and excessive road signage of type systems.

I'm curious to learn more, but I can't shake a feeling of vague trepidation here.




Erlang and Elixir have long had "dialyzer" as a type checker. The problem is that it had some severe limitations in approach (and implementation) and so the cost/benefit ratio wasn't great.

This article really speaks to how they're thinking about the costs of the type system, so that you mostly get benefit, and that's great.


> having guards, and the different approach to conditionals seemed to do away with most of the pitfalls usually "safeguarded from" by the caution tape and excessive road signage of type systems

It doesn’t seem that way to me at all. The main pitfall static typing guards me from is runtime errors that can be easily avoided, guards don’t really help there.

If I do

  def double(num) when          is_number(num)  do
    num * 2
  end
I could have some call double(“4”) in my code somewhere, and if that’s reached it would throw a FunctionClauseError and crash the process. I don’t want to be able to do that, I want the compiler to scream at me when I write double(“4”) and not let me do it, the guard is doing nothing of the sort.


> I want the compiler to scream at me when I write double(“4”) and not let me do it, the guard is doing nothing of the sort.

The optimal solution, then, is for the compiler to be smart enough to recognize that there's a guard and to preemptively enforce it at each callsite. You shouldn't need static typing for this, because the compiler should be able to figure out "oh, there's an is_number guard here, lemme whip up a type constraint for that".

Hell, the even-more-optimal solution would be to not need the guard in the first place, since the * operator already implies an is_number(num) constraint.


> The optimal solution, then, is for the compiler to be smart enough to recognize that there's a guard and to preemptively enforce it at each callsite.

It sounds to me like you are describing static typing. As far as I know, type inference from patterns and guards is one of the features of the static type system being developed for Elixir right now [1].

> Hell, the even-more-optimal solution would be to not need the guard in the first place, since the * operator already implies an is_number(num) constraint.

The most optimal solution in my opinion would be a type annotation for the function, so that you do not need to write a guard which adds a runtime overhead just to verify a type that you know you want to always be the same anyways is correct.

Type inference from the `*` operator sounds interesting, unfortunately unlike other languages (like Gleam which has *. +. etc.) Elixir does not have a separate set of operators for floats and integers, so you would not be able to infer which type of number the variable needs to be.

If it were up to me, Elixir would not have pattern matching via functions and instead allowed for type annotation in the function head, I think the matching with multiple function clauses is a lot less readable than just having one function with a big case statement at the top level – of course no way that will change, it is how it is.

[1] https://elixirforum.com/t/full-static-type-inference-of-set-...


> Elixir does not have a separate set of operators for floats and integers, so you would not be able to infer which type of number the variable needs to be.

Elixir doesn't care; it'll convert to a float if necessary (namely, if one of the arguments is a float):

    iex(1)> 1 * 1.0
    1.0
This is identical to the behavior of e.g. Julia:

    julia> 1 * 1.0
    1.0
> The most optimal solution in my opinion would be a type annotation for the function

My point is that the type annotations are redundant, at least in this particular case; the acceptable types are already obvious from the function definition itself.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: