Hacker News new | past | comments | ask | show | jobs | submit login
Gleam 0.14 – Type-safe language for the Erlang VM (gleam.run)
280 points by lpil on Feb 18, 2021 | hide | past | favorite | 51 comments



If curious see also

Gleam: A statically typed language for the Erlang VM - https://news.ycombinator.com/item?id=22902462 - April 2020 (109 comments)

An interview with the creator of Gleam: an ML like language for the Erlang VM - https://news.ycombinator.com/item?id=19547418 - April 2019 (0 comments)


My list of alternative languages for the Erlang VM:

https://gist.github.com/macintux/6349828#alternative-languag...


Heads up the purescript fork is now purerl[1].

[1]https://github.com/purerl/purerl


Thanks, fixed.


I was so sad to see Reia being abandoned by the author. I think that a Java/C looking language like Gleam (and Reia) has a much better chance than Elixir to migrate really big numbers of developers to the BEAM, because of familiarity. And don't forget PHP, another language with curly braces and many developers. Disclaimer: I make more than half of my money out of Elixir so I certainly love it, and yet I'm not optimistic about it taking over the world. Too unusual looking, not as much as Erlang but more than Gleam. Then it's more about community building than technical excellence. Good enough and a large community is all it takes (eg: PHP and any BASIC.)


I’ve always found Erlang’s distinctive syntax to be a boon.

It looks different, so I don’t fall into old patterns, and there’s practically nothing there. Very concise, minimal, just gets out of the way.

I just can’t get into Elixir because it’s both too familiar and so verbose.


I understand your point about Erlang. I think it applies to Elixir too.

Elixir notoriously looks like Ruby but it doesn't. Idiomatic Elixir is totally different. Programs are written in a different way because of pervasive pattern matching. It doesn't look like anything I used before.


I'm a PHP dev who also does Elixir but yeah I never had much colleagues interested.

LiveView helped a bit.


I know it's not a long list, but when I run into these sorts of lists I want to see them sub-categorized -- perhaps by strong static/dynamic typing or by language family (LISP vs. ML, et. al.) or maturity. The PureScript link is now out of date as well.


Frankly that would be tough, given my limited PL knowledge, but it would also be a good way to brush up on same. I'll take it under consideration.


it's cool that gleam emits typespecs. After tooling around implementing type analysis in Elixir, I do have a personal take that dialyzer typespecs are broken, maybe we should convene a group in the erlef to coordinate towards improving the typesystem.


The limitations of Dialyzer and typespecs were a big motivator for creating Gleam. They were not reliable or fast enough for my taste.

There is some work being done towards better types for Erlang, as well as sharing types between languages on the BEAM. I'm excited to see what comes in future.


Do you have any links where I could read up on the work being done for type sharing? Sounds awesome to me.


I don't know if this counts as "publishing" but I've made several videos on my personal gripes (warning, super wonky, super BEAM-specific), with accompanying code for a type system that 'fixes' the problems.

https://www.youtube.com/watch?v=_XSRsYSwNpQ

https://youtu.be/VynXxiXPmG8

https://youtu.be/2ooSWOCBTPQ

https://youtu.be/qv-GR4sEsd4


This is the first time I've come across your work! Very cool stuff.


thanks! work on my typechecker has slowed recently due to excitement with nerves + zig, and then nx + zig, so my plan is to do a bit more work with the typesystem starting next week.


I see where you are going with Zig, and I don't want to dissuade you, but consider adding lumen https://github.com/lumen/lumen to our train set.


I think lumen (and especially rust) is the wrong way to go for a BEAM reimplementation.

For starters, if you look at the BEAM vm, there are, what, 10 different allocators? This is a use case that screams out "use zig". Sure, you can tell rust to use no_std, but if you start pulling in libraries from cargo, there's no guarantee that they will respect you, and you can define a global custom allocator for collections in std, but wrangling more than one global allocator (presumably by making a single flexible global allocator and using macros to select branches of it) is going to be tiresome, and a very easy way to wind up with critical logic errors.

Moreover it's far easier to safe, highly performant things in zig.

https://www.youtube.com/watch?v=UaF6-5BmX2I&t=1h10m

benchmarks of go, rust, and zig at 1h13m


I do think there are some things that Rust can learn from Zig. One of the biggest wins for the BEAM is that each process has its own heap, so GC pauses only impact a process and they are often short lived, so another reason it is less of an issue.

I see what you are saying, but in a way, coordinated groups of Wasm envs can also bring many of the same qualities.

I have no experience with allocators in Rust, that is definitely a gap for me.

I'd love to a see a Zigification of BEAM, Python, etc. That Zig can load header files directly and includes a C compiler is so damn nice.


> coordinated groups of Wasm envs

too much overhead. The way that zap gets so fast as in the video is by decreasing overhead, minimizing coordination, and by allocating on the stack instead of the heap for all allocations related to context switching. One could imagine a BEAM system where you create a custom allocator where FIRST you get allocations on the stack for the first X register refs, then later it reaches out to the heap. This would be blazingly fast for the 99% use case in elixir.

You're also generally going to have a hard time figuring out how to do this in rust, as I don't think it's so easy to mix stack and heap allocations into a single interface for rust.


> mix stack and heap allocations into a single interface for rust.

I am not good enough at Rust to even discuss, let alone debate this.

We can talk about things, Zig and Rust and then go up an abstraction level and talk about systems and communities, I believe both want to address this issue. I think it is more important to outline the problem and them to address it.

The languages are just the reification of a philosophy.


I don't think anything has been published yet. It's very much in the early ideas stage, but there's a couple private mailing lists with some discussion going on.


Agreed, I loved working in Elixir but hated the typespecs. Felt like it was a lot of work for only a little benefit. It's not typing that I don't like but the way it's implemented in Elixir felt like it was very hard to get correct quickly. Very fiddly and time consuming. About the 10th time Dialyzer broke the build for no easily discernible reason, I wanted to scrap it.


As dumb as this sounds... you can use typespecs as documentation even if you never run dializer. We do this at work in a legacy code base that would be painful to dialyze without errors, but it makes new code nicer to look at.


I use it exactly for this. Just use typespecs as a hint to the person looking at the code as to what is expected to be passed.


If you never do anything but read them... why not documentation?


I do both. All to help me in the future as much as possible when I come back scratching my head.


Terseness.


Yup. One could write "It takes a string as an argument & reverses it". Or one could write "String.reverse(()". For any non trivial case, such as weird options, you'll normally write documentation anyway.


Isn't there a big risk the typespecs are wrong then?


I wouldn't go so far as to say they aren't useful. I find dialyzer is not awful at finding mistakes that I make.

I have thought about this a lot (I'm writing a static typechecking library for Elixir) and really the problem is the dialyzer typesystem. Almost all of the problems stem from the root fact that there isn't a granular concept of how to treat functions in the type system. What does `(int, int) -> int` mean? Dialyzer does not have a good answer for that question.

Mind you I am not a "PL theory" type of guy, I do have a math degree, but my PhD is in the sciences, so I am more approaching this issue from a "discovering what would be truly useful" perspective more than "applying an existing typesystem to the BEAM", which is I think in line with the traditional pragmatism of the BEAM ecosystem.


> What does `(int, int) -> int` mean?

This is an interesting question. Do you have any thoughts on what a better answer to that question might mean? Or languages you think do better here? Thank you


Here's my thought:

let's go with a simpler one: int -> int

"I guarantee that if you send me an int then i will return you an int without crashing"

In elixirland: `IO.inspect/1` would satisfy this, as would `Kernel.-/1`. The interesting thing is that `any -> int` is then a subtype of `int -> int` and we need a new type `_ -> int` which is "any one-arity function that emits int".

Then types become a statement of "resistance to crashing" in the BEAM vm, which I think is the useful thing that people are looking for.

I don't have answers to everything; I don't know how to deal with a function that generates random numbers from 1 to 20 and crashes on 13, for example.

We should have a discussion about this! I'll reach out on another channel.


I have no skin in this game, but:

> "I guarantee that if you send me an int then i will return you an int without crashing"

This is a much stronger guarantee than you get in any language except very specialized ones. Coq, for example (not just not crashing, but also guaranteed termination). But even in Haskell an Int -> Int function can crash or decide not to terminate. Reading more into a type opens up cans of worms that are hard to solve.


Ok so aside from well known out of control things like another process telling the vm to brutal_kill you, cosmic arrays, or miscodes, OS interactions, oom errors or nif panics (the last three which bring down the whole VM anyways, so who cares), the crashing surface error for a BEAM process is extremely well defined.

The only no_returns otherwise are loops and hibernates. Hibernates are explicit. You might have a hard time analyzing the tail-calls to figure out an ultimate type that captures a no_return loop, but I think ignoring that condition would not be horrible for a BEAM type system (along the same lines as the random number crash scenario that I described).


> Ok so aside from well known out of control things like another process telling the vm to brutal_kill you, cosmic arrays, or miscodes [...] the crashing surface error for a BEAM process is extremely well defined.

I'm not sure what you're saying. Crashing "miscodes" (like pattern match failures) are a thing, no? A "well defined" thing, but not one that a type system that doesn't include proper theorem proving will save you from.


I think you can usefully tackle this problem without too much difficulty. At least, within a langauge like Gleam you can.

An effects tracking system can be used to determine things such as use of FFI, `assert`, recursion, and side effects. With these statements like "this function does not crash" is easy, and "this function does not diverge" is also possible, though it will not detect all functions that do not diverge.


>I don't have answers to everything; I don't know how to deal with a function that generates random numbers from 1 to 20 and crashes on 13, for example.

Most languages don't have a way to type that, I'm pretty sure it requires dependent types.


I'm not sure resistance to crashing is a good way to think of it? It just means that you need to pass it an int for logical results, and if you do it'll return you an int if everything goes well.

The types don't prove the logic doing the right thing or that nothing can break while the function runs, but they prove that you are using it mostly correctly in what you give it and what you do with what it'll return.


There's an effort currently being led by Facebook to create a gradual type system for Erlang call Gradualizer, which should also make its way over to Elixir.

https://github.com/josefs/Gradualizer

https://github.com/OvermindDL1/gradualixir


I don't think Gradualizer is led from FB. The FB static type system hasn't been opened up yet AKAIK.


They were supposed to in November but wiffed.


Wow, Gleam is written in Rust. Great to see other languages being developed in Rust


Why not write things you might write in gleam in Rust, too?


They have a different runtime model (and therefore present a different concurrency/parallelism API).

Rust (usually) compiles to a single standalone binary, that includes any runtime needed. Concurrency is now usually provided via sync with something like Tokio underneath. You can absolutely do actor programming (see Riker and Actix), but it's not the primary way Rust is intended to be used, and it doesn't offer the same set of management capabilities that the BEAM does

Erlang/Elixir/Gleam run on the BEAM. This is a standalone runtime (VM) that then executes code. Deployment involves a lot more pieces, but once done you get a lot more tooling built in (e.g. the observer to see what actors are running). It is designed from the ground up for actor model concurrency, and concepts like supervisor trees have been proven to be best-in-class for managing code running over long periods of time and handling errors in a self-healing way. Plus the separate VM means you can do things like zero-downtime update ("hot code loading").


Probably because you're looking for simplicity, the BEAM, and access to the Erlang ecosystem.

Or maybe it just like speaks to you.


Rust is great but it’s a very different experience writing Gleam. Rust is much faster but more complex and more challenging to learn, Gleam is designed to be more approachable. It is like Go vs C++


Seems Gleam compiles to erlang instead of beam code, like Typescript compiles to javascript. Wish it'll be as successful as Typescript


Really? This approach sounds suboptimal to me.


This approach allows you try it in an existing project without pursuing the team to switch together.


Why do you say that?




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

Search: