I've never used Gleam and vaguely understand it as "Elixir with first class types", before Elixir had types, anyway. Some of those features seem awesome and drop dead obvious (like built-in TODOs/deprecations) but then I got to this:
In Gleam, the language takes the approach of being meticulous on doing things one simple way. Which means, case expressions are your everything:
Oh no. Did Gleam throw away pattern matching for function heads? I understand how it's redundant with case statements, but that seems like a giant step backwards.
Yeah there's no pattern matching in function heads but only through case expressions. For example:
pub fn wibble(a: Int, b: List(a)) {
case a, b {
1, [] -> todo
_, [_, ..] -> todo
_, _ -> todo
}
}
Pattern matching in function heads doesn't enable anything that case expression can't achieve already, so it makes sense (for Gleam at least!) to not have that
I'm actively at a point where I naturally start functions with a case statement and have to force myself to go back in my Erlang/Elixir code to rewrite separate function heads, so you can imaging how dizzy this makes me!
One thing I would miss is conditional destructuring. Like, I'm imagining when I've got complex inputs to a function and want to take some action based on a minimal condition, first:
% "Super complex" business calculation: (A + B) / C.
ratio(_, _, 0) -> denominator_zero;
ratio(_, _, C) when C > 1000 -> denominator_too_large;
ratio(#{price := A}, #{price := B}, C) -> (A + B) / C.
I think the only way this can be done with case statements is to first destructure all the inputs and then run a check to see if the third input is invalid? Maybe there's a reason that's strictly better, but I would miss the ability to, at a glance, know the result of the first clause without having to consider the structure ofreason anything about the first two parameters.
pub fn ratio(a: Item, b: Item, c: Int) -> Result(Int, RatioError) {
case a, b, c {
_, _, 0 -> Error(DenominatorZero)
_, _, c if c > 1000 -> Error(DenominatorTooLarge)
Item(price: a_price), Item(price: b_price), c -> Ok({a_price + b_price} / c)
}
}
Sure, you have the function head there with the types, but the match itself doesn't really look that much different. Personally I think not repeating the function name is an improvement.
Fun bit of trivia: the Erlang VM doesn’t support multiple function heads, so one is written in Erlang or Elixir the Erlang compiler will desugar them into a single function with a case expression.
There’s no reason one would need to always compare Gleam to Elixir. Judging by their own posts the author is a Go programmer, so they’d be more likely to compare it to Go.
todo is not strictly needed in Elixir, as there's no need to make the program pass type checking to be compiled. You'd generally use raise "Not implemented: should do something" if you wanted to crash.
Elixir has generic types in the typespec syntax, but those are only for dialyzer and there are varying opinions of its usefulness. There's no syntax yet for the new type system.
You can write Elixir by using option and result types, and I personally wish the ecosystem would have embraced that more. But there's no support from the tooling and most of the ecosystem uses varying types for ok/error results (:ok, {:ok, result}, {:ok, result, result2} and so on), making this more difficult. The stdlib doesn't have one set style either. OTOH, while frowned upon in libraries, it's also technically possible to assert in Gleam code.
The last point about nulls is kind of the same and not the same in Elixir. The same in that there's the atom nil but it's not really special and it's a separate type from others. But since the language is dynamically typed, that nil may appear anywhere unless guarded against.
ryan-duve | 12 hours ago
I've never used Gleam and vaguely understand it as "Elixir with first class types", before Elixir had types, anyway. Some of those features seem awesome and drop dead obvious (like built-in TODOs/deprecations) but then I got to this:
Oh no. Did Gleam throw away pattern matching for function heads? I understand how it's redundant with case statements, but that seems like a giant step backwards.
[OP] giacomo_cavalieri | 12 hours ago
Yeah there's no pattern matching in function heads but only through case expressions. For example:
Pattern matching in function heads doesn't enable anything that case expression can't achieve already, so it makes sense (for Gleam at least!) to not have that
ryan-duve | 12 hours ago
I'm actively at a point where I naturally start functions with a case statement and have to force myself to go back in my Erlang/Elixir code to rewrite separate function heads, so you can imaging how dizzy this makes me!
One thing I would miss is conditional destructuring. Like, I'm imagining when I've got complex inputs to a function and want to take some action based on a minimal condition, first:
I think the only way this can be done with case statements is to first destructure all the inputs and then run a check to see if the third input is invalid? Maybe there's a reason that's strictly better, but I would miss the ability to, at a glance, know the result of the first clause without having
to consider the structure ofreason anything about the first two parameters.Nicd | 9 hours ago
Here's one implementation of that in Gleam:
Sure, you have the function head there with the types, but the match itself doesn't really look that much different. Personally I think not repeating the function name is an improvement.
nick4 | 10 hours ago
I actually haven't missed pattern matching on function heads too much, even as someone who's done a lot of Haskell. I think I actually miss
ifs more.ryan-duve | 9 hours ago
There are no
ifstatements? Point Gleam. This morning is a roller coaster.lpil | 9 hours ago
Fun bit of trivia: the Erlang VM doesn’t support multiple function heads, so one is written in Erlang or Elixir the Erlang compiler will desugar them into a single function with a case expression.
patryk | 10 hours ago
I know it's not direct Gleam vs Elixir comparison, but I'd appreciate notes like "Elixir has this too!" and "This is different from elixir"
E.g.
@deprecatedworks in Elixir just finelpil | 9 hours ago
There’s no reason one would need to always compare Gleam to Elixir. Judging by their own posts the author is a Go programmer, so they’d be more likely to compare it to Go.
Nicd | 9 hours ago
My notes:
todois not strictly needed in Elixir, as there's no need to make the program pass type checking to be compiled. You'd generally useraise "Not implemented: should do something"if you wanted to crash.:ok,{:ok, result},{:ok, result, result2}and so on), making this more difficult. The stdlib doesn't have one set style either. OTOH, while frowned upon in libraries, it's also technically possible to assert in Gleam code.nilbut it's not really special and it's a separate type from others. But since the language is dynamically typed, thatnilmay appear anywhere unless guarded against.