What sort of support is there for live updates of servers?
Not built into the type system, but Erlang’s hot code upgrades can be used as normal. You are effectively doing normal Erlang dynamic programming if you do this so the usual level of caution is required.
This looks great! Are you planning to implement the usual OTP stuff (Supervisor, GenServer, GenStatem) natively too?
In order to get the ball rolling I may create some type-unsafe bindings to GenServer etc using an opaque Pid type, though longer term I would like to have type safe bindings.
This is quite difficult to achieve while using the same patterns and keeping compatibility with OTP, so more research needs to be done here. For now the focus is on the synchronous language and tooling, so people can start writing programs.
Hiya, seems really interesting! How does this work if you want to import an existing library that runs a supervision tree? How do you interact with that? What happens with messages? And how do you code for concurrency? Not sure from this comment whether the Pid type exists yet. Had a glance through gleam.run and not found anything there but I could be missing it.
There are no official bindings to any of OTP’s libraries yet, though the FFI can be used to define them. Exactly how Gleam’s message passing will work is a subject of ongoing research and still very much yet to be decided.
In my applications I have been writing the supervisor code in Erlang and the genservers and business logic in Gleam.
Thanks! OK, I think I get it, there’s no (e.g.) receive or ! yet, so does that mean that your Gleam module implements the business logic as pure functions (I guess calling out to erlang libraries?), exports them as the gen_server callbacks, & OTP routes messages in via e.g. handle_info/2? Trying to work out in my head how complete a gen_server could be without receiving messages - especially interesting as it’s making me think deeper into how much all the behaviours actually handle for us behind the scenes(!) :-)
Genserver interfaces are pure and functional, there’s no need to introduce a concept of processes in order to construct one so the behaviour module can be implemented with Gleam today. The trouble lies with the caller process and the gen_server module itself (if we were to re-implement it) as they need to know about processes in order to safely send messages to one, etc.
Currently I’m using an opaque Pid type in my projects and relying on the programmer to ensure the correct messages go to the correct process, as is the case in Erlang or Elixir. I would like to have a type safe solution here, but we’re not there yet sadly.
Here’s a (largely unsafe) example of a genserver today in Gleam: https://github.com/gleam-lang/example-url-shortener/blob/d10ad7cac591803431be76dc8335be06668a1c36/src/tiny_db.gleam
It’s internally consistent and type checked, but there’s certainly places in which it could be improved.
Got it. Really interesting stuff, thanks! Like the look of gleam too. Nice one.
This is really very cool and I applaud your efforts. Thanks for making something so awesome for everyone to use and learn from.
Is there any comparison between the different statically typed options for the Erlang VM? I know there is Alpaca and I seem to faintly remember walking across another language but can’t remember its name.
There is Alpaca, Purescript (purerl), Gradualizer, and Elchemy that I know of. I’ve not written a comparison as I’m weary about seeming unfriendly or competitive when really I would like all these projects to succeed!
Are there more specific questions I could answer for you?
Thanks for the list!
I guess my main question would be which of these would map my existing OCaml workflow best onto the Erlang VM.
From where I’m standing I would say the Purerl is the most mature and usable right now, making it a good choice. It is more of a Haskell than an OCaml though, Gleam is in some ways closer to OCaml there.
On the whole they’re all rather immature projects, so if you want real-world use I probably wouldn’t use any of them (except possible Purerl). I intend to continue to develop Gleam and the ecosystem around it so hopefully it’ll fill that niche in the not too distant future.
Nice work, always nice to see more BEAM-based languages. A quick question, apologies if I missed it in the documentation already: how does the static typing handle messages from remote processes that are potentially on future versions, i.e. messages that aren’t type-compatible with the receiver process?
I ask because Akka in the JVM world ran into similar problems and then just fell back to java.lang.Object and instanceof checks for actor messages, and Erlang naturally doesn’t encounter this problem due to dynamic typing.
Rich Hickey makes interesting points in his talks about type systems, pointing out that incompatibilities between type changes shouldn’t really occur for additive changes, but that would seem to require structural typing to support and be compatible across multiple versions of the same codebase, from what I can see.
How we should type message passing is the subject of ongoing research and as a result there is no built in constructs for the BEAM’s concurrency primitives in the language. If you wish to use them you’d use the FFI and write this code in Erlang, so it would be dynamically typed.
As for the talk from Rich Hickey, my preference is to have breaking changes and to have tooling that makes resolving these problems straightforward rather than always expanding the existing API. This will definitely be the route that Gleam takes with message passing as we will likely go through before the first stable release.
Am I the only person who finds it frustrating that people create ML’s with needlessly different syntax? It makes porting code burdensome, so I will never adopt it. Hopefully there will be an ML syntax mode at some point in the future.
Gleam doesn’t aim to be an ML language and if you come to it expecting it to be one you’ll likely be disappointed. The type system is directly influenced by ML but other aspects of the language come from elsewhere.
The big question: why not port something else like pony or cloud haskell? Or why not add static types to something like erlang itself?
I’m not sure what you mean about Pony or Cloud Haskell but I have some answers to why not Erlang.
Static typing Erlang is a different and considerably more difficult problem than making a compatible soundly typed language. Realistically for a typer for Erlang to get adoption it needs to be flexible enough to allow it to be applied incrementally to existing Erlang codebases, which means gradual typing. Gradual typing offers a very different set of guarantees to those that Gleam offer. By default it’s unsafe, which isn’t what I wanted.
There’s also some more human issues such as my not being part of Ericsson, so I would have little to no ability to make use or adapt the existing compile, I would have to attempt to be compatible with their compiler. If we were successful in that the add-on nature means it becomes more of a battle to get it adopted in Erlang projects, something that I would say the officially supported Dialyzer has struggled to do.
Overall I don’t believe it would be an achievable goal for me to add static types to Erlang, but making a new language is very achievable. It also gives us an opportunity to do things differently from Erlang- I love Erlang, but it certainly has some bits that I like less.
I’m not sure what the point of Pony on BEAM would be. Pony’s reference capabilities statically prove that “unsafe things” are safe to do. BEAM wouldn’t allow you to take advantage of that. Simplest example: message passing would result in data copying. This doesn’t happen in the Pony runtime. You’d be better of using one of the languages that runs on BEAM including ones with static typing.
Thanks for Pony and thanks for the reply!
As you might imagine I’m very interested in how Pony types actors. I skimmed the documentation but many aspects such as any supervision trees were unclear to me (likely my fault). Are there any materials on the structuring Pony applications you could recommend? Thank you :)
There are no supervision trees at this time in Pony. How you would go about doing that is an interesting open question.
Because Pony is statically typed and you can’t have null references, the way you send a message to an actor is by holding a “tag” reference to that actor and calling behaviors on it. This has several advantages but, if you were try to do Erlang style “let it crash”, you run into difficulties.
What does it mean to “let it crash”? You can’t invalidate the references that actors hold to this actor. You could perhaps “reset” the actors in some fashion but there’s nothing built into the Pony distribution to do that, nor are the mechanics something anyone has solid ideas about.
There aren’t a lot of materials on structuring Pony applications I can recommend at this time. I’d suggest stopping by our Zulip and starting up a conversation in the beginner help stream: https://ponylang.zulipchat.com/#narrow/stream/189985-beginner-help