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

Progressing the language server

Last year we collected feedback from the community via the Gleam developer survey, in part to learn what would be the most impactful and useful features to work on next. The results were clear: people want better tooling and editor support!

This year a lot of work has gone into improving the Gleam language server, a headless IDE engine that adds Gleam functionality to VSCode, Vim, Emacs, Helix, and any other editor that supports the protocol. The internals have had a full-rewrite and the compiler continues to be re-structured to enable more features to be added to the language server.

A VS Code editor window showing a string function being suggested as a completion, along with its documentation and type signature

This release brings the first version of a much awaited feature to the language server: autocompletion! Autocompletion is provided for module functions, types, and constants either imported or defined within the current module.

In future releases autocompletion will continue to be developed, providing suggestions for locally defined variables, record fields, and more.

gleam run --module target selection

The gleam run --module command can be used to run the main function from a given module, including those defined in dependency packages. This has many uses, for example it could be used by a web framework to provide code generation:

$ gleam run -m framework/generate user name:string age:int

Gleam supports two compile targets, Erlang and JavaScript. Each runtime has quite a different approach to concurrency and IO, so Gleam programs designed to run on one may not be able to run on the other without modification. If the dependency module is intended to be run on a specific target rather than using the default for your project then you’d need to specify --target erlang or --target javascript when running the command.

With this release the intended target for dependency modules will be detected and automatically set, no more need to specify --target!

Thank you Lunarmagpie for this feature!

More precise cache invalidation

Gleam code compiles really fast! Both because of the compiler performance, and because it supports incremental compilation to avoid compiling code that doesn’t need to be recompiled.

Previously the build tool would be conservative when deciding what needed to be removed from the cache when new dependencies were added or removed, removing all the build caches for the dependencies. With the version it will be more precise, removing only the caches for dependencies that have to be rebuilt for the new configuration.

Standard library improvements

With the try syntax removed from the language we can now use that as the name of a function. Taking advantage of this the result module gains a new try function that can be used to return early if a computation fails:

use user <- try(login("Juno", "blink182"))
use info <- try(get_profile(user))

This succeeds the existing then function, which provides the same functionality but with a slightly less clear name.

The result module also gains the partition function, which can be used to split a list of results into a list of successes and a list of failures.

result.partition([
  Ok(1), Error("two"), Ok(3), Error("four"),
])
// -> #([1, 3], ["two", "four"])

The iterator module gains the each function which runs a function on each item from an iterator.

open_file("access.log")
|> stream_lines()
|> iterator.each(process_line)

The list module gains the try_each function which runs a function on each item from a list, returning early if the function returns an error.

posts
|> list.try_each(save_post)
// -> Error(CouldNotSave(reason: MissingTitle))

The dynamic module gains the optional_field function which can be used to extract a field from untyped data, falling back to None if the field is not present.

let decode = fn(x) {
  json.decode(x, using: optional_field("name", string))
}

decode("{\"name\": \"Gleam\"}") 
// -> Ok(Some("Gleam"))

decode("{}")
// -> Ok(None)

Thank you to all the contributors who made these improvements possible!

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! 💜