Gleam is a type safe and scalable language for the Erlang virtual machine and JavaScript runtimes. Today Gleam v0.28.0 has been released, let’s take a look at what’s new.

Language server revamp

Gleam is all about productivity and making the job of the programmer as low-stress as possible. To be productive we need more than just a great language, we also need great tooling around that language, including top-notch editor support. To this end the Gleam binary includes a language server, a headless IDE engine that adds Gleam functionality to VSCode, Vim, Emacs, Helix, and any other editor that supports the protocol.

The Gleam language server was released in Gleam v0.21.0, and while a popular addition it was rather limited in this initial version. In the releases since then much work has been done restructuring compiler internals to make further improvements to the language server possible. With this release the first batch of those improvements are ready for use.

Lightning fast analysis

The Gleam compiler is very fast, so the build tool could afford to be a little naive and recompile an entire package when a single file changed, rather than having fine-grained incremental compilation. This became a problem when the language server was introduced because rebuilding a package was more work than we wanted to perform on every keystroke, so the package would only be rebuilt when the user saved their changes, meaning the programmer would only have up-to-date information in their editor after saving.

With Gleam v0.26.0 the build tool learnt how to perform per-module incremental compilation, and with this release the language server now uses that to parse and analyse code on every keystroke. Gleam is now among the snappiest and most responsive language servers I’ve used!

Thank you John Björk for your work on this feature!

There’s still lots of things we can do to improve the performance of the compiler and build tool, we’re only going to get faster from here on out.

Monorepo support

Gleam is most commonly run using the Erlang virtual machine, but it can also be compiled to JavaScript and run in other places, such as web browsers. Folks in the Gleam community use this to build web applications where both the frontend and backend are written in Gleam, with both parts living in the same code repository.

louis ~/src/gleam/developer-survey $ tree -L 2
.
├── Dockerfile
├── README.md
├── fly.toml
├── backend
│   ├── gleam.toml
│   ├── manifest.toml
│   ├── src
│   └── test
└── frontend
    ├── gleam.toml
    ├── manifest.toml
    ├── src
    └── test

Previously the language server only suppored a single Gleam project per editor instance, with the editor open at the root. If another Gleam project was opened the language server would not be able to analyse it, offering very little assistance to the programmer.

Gleam can now handle as many Gleam projects as you’d like to open in a single editor session, and they can be nested in any way you like. The language server will spin up a new engine for each project opened, and route requests to the correct one per-file.

More on-hover information

A VS Code editor window showing a documentation popup for Gleam code

Access to good documentation is vital, so the language server will now show documentation when you hover over Gleam code in your editor.

Previously information was only shown on hover for values, but now pattern-match patterns are also supported, showing their type and their documentation.

And that’s all the user-facing changes to the language server in this release. Let’s take a look at the other changes.

Checksum based caching

Gleam gained per-module incremental compilation in v0.26.0, based off of the file modification time. One drawback with this approach is that it will consider a module to need recompiling if the file modification time changes, even if the contents of the file have not changed, for example when changing git branches.

The build tool now checks the checksum of the file contents after checking the modification time, and only recompiles the module if both have changed, reducing the amount of unnecessary work.

Thank you Nikita Lapkov for this feature!

Unary negation

Gleam now has a unary negation operator, -, which can be used to negate integers, while before only integer literals could be negated with -.

pub fn negate(x: Int) -> Int {
  -x
}

A little funny that we’ve got this far without this feature, but there you go! Thank you Zack for this feature!

Syntax refinements

In Gleam let x = 1 is an expression and returns a value, and it could be used anywhere that an expression can be used. This resulted in some questionable code being supported, with potentially confusing scoping rules for variables defined.

let x = let y = 1
// Is y in scope here?
1 + let x = 1
// Is x in scope here?

To help keep Gleam easy to understand the syntax has been restricted slightly, with assignments only being permitted within functions and blocks.

let x = {
  let y = 1
}
1 + {
  let x = 1
}

This should make it clearer to the programmer where variables go out of scope.

On the subject of syntax, the deprecated assert and try syntaxes have been removed, and semicolons have changed from being whitespace to being a syntax error. If your code has any of these run the gleam fix command with Gleam v0.27.* and it will be auto-updated for you.

Running modules

The gleam run command now supports running a module of your choice, rather than just the main module for your project.

gleam run --module my/favourite/module

The module can also be from a dependency, opening up the door to dependency provided tooling being straight-forwardly usable from the command line. For example, a web application framework may provide a project scaffolding command to quickly get started with the framework.

gleam add magic_framework
gleam run -m magic_framework init

Thank you Lunarmagpie for this feature!

Fast immutable maps on JavaScript

In Gleam all data is immutable and very fast. Or at least, it is now! Up until this release the implementation of immutable maps in JavaScript has been slower than we would like it to be, some operations performing a full-copy of the map before updating it.

With this release we have a brand new and very fast persistent hash map implementation on JavaScript, inspired by Clojure’s hash map implementation.

Thank you to Julian Schurhammer for this very impressive and much appreciated contribution!

Thanks

Gleam is made possible by the support of all the kind people and companies who have very generously sponsored or contributed to the project. Thank you all!

If you like Gleam consider sponsoring or asking your employer to sponsor Gleam development. I work full time on Gleam and your kind sponsorship is how I pay my bills!

Thanks for reading! Happy hacking! 💜