← Back to context

Comment by pkos98

18 hours ago

Coming from Elixir, I gave Gleam a try for a couple of days over the holidays. Reasons I decided not to pursue:

- No ad-hoc polymorphism (apart from function overloading IIRC) means no standard way of defining how things work. There are not many conventions yet in place so you won’t know if your library supports eg JSON deserialization for its types

- Coupled with a lack of macros, this means you have to implement even most basic functionality like JSON (de)serialization yourself - even for stdlib and most popular libs’ structs

- When looking on how to access the file system, I learned the stdlib does not provide fs access as the API couldn’t be shared between the JS and Erlang targets. The most popular fs package for erlang target didn’t look of high quality at all. Something so basic and important.

- This made me realise that in contrast to elixir which not only runs on the BEAM („Erlang“) but also runs with seamless Erlang interop, Gleam doesn’t have access to most of the Erlang / Elixir ecosystem out of the box.

There are many things I liked, like the algebraic data types, the Result and Option types, pattern matching with destructuring. Which made me realize what I really want is Rust. My ways lead to Rust, I guess.

> Gleam doesn’t have access to most of the Erlang / Elixir ecosystem out of the box.

Gleam has access to the entire ecosystem out of the box, because all languages on the BEAM interoperate with one another. For example, here's a function inside the module for gleam_otp's static supervisor:

    @external(erlang, "supervisor", "start_link")
    fn erlang_start_link(
      module: Atom,
      args: #(ErlangStartFlags, List(ErlangChildSpec)),
    ) -> Result(Pid, Dynamic)

As another example, I chose a package[0] at random that implements bindings to the Elixir package blake2[1].

    @external(erlang, "Elixir.Blake2", "hash2b")
    pub fn hash2b(message m: BitArray, output_size output_size: Int) -> BitArray

    @external(erlang, "Elixir.Blake2", "hash2b")
    pub fn hash2b_secret(
      message m: BitArray,
      output_size output_size: Int,
      secret_key secret_key: BitArray,
    ) -> BitArray

It's ok if you don't vibe with Gleam – no ad-hoc poly and no macros are usually dealbreakers for certain types of developer – but it's wrong to say you can't lean on the wider BEAM ecosystem!

[0]: https://github.com/sisou/nimiq_gleam/blob/main/gblake2/src/g...

[1]: https://hex.pm/packages/blake2

  • Isn’t this the proof of my point - How does the need of writing „@external“ annotations by hand not contradict the point of being „out of the box“ usable?

    Hayleigh, when I asked on the discord about how to solve my JSON problem in order to get structured logging working, you replied that I’m the first one to ask about this.

    Now reading this: > It's ok if you don't vibe with Gleam – no ad-hoc poly and no macros are usually dealbreakers for certain types of developer

    Certainly makes me even more feel like gatekeeping.

    • I don't think Hayleigh was trying to gatekeep, just noting that some developers prefer features that Gleam intentionally omits.

      As for the @external annotations, I think you're both right to a degree. Perhaps we can all agree to say: Gleam can use most libraries from Erlang/Elixir, but requires some minimal type-annotated FFI bindings to do so (otherwise it couldn't claim to be a type-safe language).

    • How does it contradict it? Without any modification/installation you can interop with Erlang/Javascript. How is that not out of the box usability of the Erlang/JS ecosystem? Syntax isn't as seamless as Elixir, but we need a way to tell Gleam what types are being passed around.

      Why do you feel like a gatekeeper? Your opinion is valid, it's just that the interop statement was wrong.

      2 replies →

    • This is the same as Elixir, you need to specify what Erlang function to use in that language if you want to use Erlang code. The only difference is that Gleam has a more verbose syntax for it.

      2 replies →

I'm a bit torn on ad-hoc polymorphism. You can definitely do cool things with it. But, as others have pointed out, it does reduce type safety:

https://cs-syd.eu/posts/2023-08-25-ad-hoc-polymorphism-erode...

  • The same point holds of interfaces. And it’s not clear what the alternative is. No type system I’m aware of would force you to change all occurrences of this business logic pattern, with or without ad hoc polymorphism.

    But at least ad hoc polymorphism lets you search for all instances of that business logic easily.

    • ML languages have a "types, modules, types-of-modules, and functors" approach to ad-hoc poly. It's a bit strange compared to what other languages do. I am wondering whether it's ever been seen outside of SML and OCaml.

      For JSON deserialisation, you would declare a module-type called "JSON-deserialiser", and you would define a bunch of modules of that module-type.

      The unusual thing is that a JSON-deserialiser would no longer be tied to a type (read: type, not module-type). Types in ML-like languages don't have any structure at all. I suppose you can now define many different JSON-serialisers for the same type?

I’ve been doing Elixir for 9 years, 5 professionally. Nobody cares about ad-hoc polymorphism. The community doesn’t use protocols except “for data”. Whatever that means. Global singleton processes everywhere. I’m really discouraged by the practices I observe but it’s the most enjoyable language for me still.

  • >I’ve been doing Elixir for 9 years, 5 professionally. Nobody cares about ad-hoc polymorphism.

    That’s true for Elixir as practiced, but it’s the wrong conclusion for Gleam.

    Elixir doesn’t care about ad-hoc polymorphism because in Elixir it’s a runtime convention, not a compile-time guarantee. Protocols don’t give you universal quantification, exhaustiveness, coherence, or refactoring safety. Missing cases become production crashes, not compiler errors. So teams sensibly avoid building architecture on top of them.

    In a statically typed language, ad-hoc polymorphism is a different beast entirely. It’s one of the primary ways you encode abstraction safely. The compiler enforces that implementations exist, pushes back on missing cases, and lets you refactor without widening everything into explicit pattern matches.

    That’s exactly why people who like static types do care about it.

    Pointing to Elixir community norms and concluding “nobody cares” is mixing up ecosystem habits with language design. Elixir doesn’t reward those abstractions, so people don’t use them. Gleam is explicitly targeting people who want the compiler to carry more of the burden.

    If Gleam is “Elixir with types,” fine, lack of ad-hoc polymorphism is consistent. If it’s “a serious statically typed language on the BEAM,” then the absence is a real limitation, not bikeshedding.

    Static types aren’t about catching typos. They’re about moving failure from runtime to compile time. Ad-hoc polymorphism is one of the main tools for doing that without collapsing everything into concrete types.

    That’s why the criticism exists, regardless of how Elixir codebases look today.