Gleam is a type-safe and scalable language for the Erlang virtual machine and JavaScript runtimes. Today Gleam v1.9.0 has been published. Let’s take a look!

Echo debug printing

There are debuggers you can use with Gleam, however the most popular ways to understand the runtime behaviour of a Gleam program is through writing tests and through print debugging.

The standard library function io.debug is most commonly used for print debugging. It takes a value of any type, uses target specific runtime reflection to turn it into a string of Gleam syntax, and then prints it to standard-error. This works well, but there are some ways in which this function is not optimal:

To improve on this the echo keyword has been introduced. Prefix an expression with it and the value will be printed to standard-error, along with the path to the file and line containing the echo expression, so you can click to jump to it in your editor.

pub fn main() {
  echo [1, 2, 3]
}

It can also be used in pipelines. Here the list returned by the first list.map call will be printed.

pub fn main() {
  [1, 2, 3]
  |> list.map(fn(x) { x + 1 })
  |> echo
  |> list.map(fn(x) { x * 2 })
}

The build tool is aware this is for debugging, so it’ll let you know if you forget to remove it before publishing a package for others to use.

Currently it uses the same runtime reflection and heuristics to format the output, but in future it’ll be enhanced to make use of the compiler’s static analysis.

Thank you Giacomo Cavalieri! We had all manner of annoying CI-related problems when implementing the integration tests for this feature, Jak’s a very patient and determined programmer indeed!

Git dependencies

There are times when we wish to try out early prototype versions of libraries we have made in our applications. It may be tempting to publish these unfinished packages to the package manager, but this would be inappropriate! Only production-ready packages should be published for other people to use, the Gleam package ecosystem is to be high quality and easy to depend upon safely.

As a more suitable alternative the build tool now supports depending on packages within git repositories. Add the git or HTTP URL of a repository along with a tag, branch, or commit SHA, and the build tool will download it for you and then treat it like a regular Gleam dependency package.

[dependencies]
gleam_stdlib = { git = "https://github.com/gleam-lang/stdlib.git", ref = "957b83b" }

Thank you Surya Rose for this much anticipated feature.

More powerful bit arrays on JavaScript

Gleam’s bit array syntax allows you to construct and parse binary data in a way that may be easier to understand than using binary operators. Historically bit arrays had to be byte aligned, meaning they had to have a number of bits that was divisible by 8. Richard Viney has done some incredible work and lifted this limitation. Thank you Richard!

Surya Rose has also been lifting JavaScript bit array restrictions, enabling the usage of dynamically sized segments in bit array patterns. Thank you Surya!

Faster list pattern matching on JavaScript

The list type is one of Gleam’s primary data structures, it is used very heavily in Gleam programs. yoshi~ has been working hard to identify potential performance optimisations for the virtual-DOM implementation of the Lustre framework, and in the process they identified a way to improve the JavaScript code we generate when pattern matching on lists.

Programs that compile to JavaScript and make heavy use of list prefix patterns may now be up to twice as fast!

Go-to type definition

Gleam’s built-in language server brings IDE-like functionality to all editors that support the language server protocol. It has had support for go-to definition for some time, but with this release Giacomo Cavalieri has added support for go-to type definition. Place your cursor on an expression and trigger the feature and the language server will identify the types of all the values used in the expression and present their definitions for you to view and to jump to. Thank you Jak!

HexDocs search integration

When a Gleam package is published HTML documentation is generated and published to HexDocs for users to read. HexDocs have been improving their search functionality to search for types and functions with in packages themselves, and Diemo Gebhardt has updated Gleam’s documentation generator to implement the search index interface so Gleam packages are included in the search. Thank you Diemo!

Another option for searching within Gleam packages is Gloogle, a Gleam community project, which can even search by function type signature.

Custom CA certificates support

Some enterprise networks may perform TLS interception for security reasons. In these environments custom CA certificates must be used as otherwise requests will get TLS errors due to the unknown authority of the injected certificates.

The new GLEAM_CACERTS_PATH environment variable can be used to specify a path to CA certificates for Gleam to use when interacting with the Hex package manager servers, making Gleam usable in these enterprise environments. Thank you winstxnhdw!

Convert to and from pipeline code actions

Gleam’s much-loved pipe syntax gives programmers another way to write nested function calls so that they read top-to-botton and left-to-right.

Two new language server code actions have been added to help you refactor between the pipe syntax and regular function call syntax. Triggering them on these two code examples will edit your code to match the other.

import gleam/list

pub fn main() {
  list.map([1, 2, 3], double)
}
import gleam/list

pub fn main() {
  [1, 2, 3] |> list.map(double)
}

You can also choose to pipe arguments other than the first by selecting them in your editor before triggering the code action. Thank you Giacomo Cavalieri!

Generate JSON encoder code action

Many Gleam programs make use of JSON, a common text-based data exchange format. With this release the Gleam language server now offers a code action to generate a function to convert a type into JSON using the gleam_json library. Given this type definition:

pub type Person {
  Person(name: String, age: Int)
}

If the code action is triggered on the type definition this function will be generated:

import gleam/json

fn encode_person(person: Person) -> json.Json {
  json.object([
    #("name", json.string(person.name)),
    #("age", json.int(person.age)),
  ])
}

Thank you Surya Rose for this code action!

Inline variable code action

The Gleam language server now offers a code action that will inline a variable that is used only once.

import gleam/io

pub fn main() {
  let greeting = "Hello!"
  io.println(greeting)
}

If the code action is triggered on the greeting variable the code will be edited like so:

import gleam/io

pub fn main() {
  io.println("Hello!")
}

Thank you Surya Rose!

Generate multi-variant decoder code action

Gleam’s Dynamic type represents data of unknown shape that comes from outside of the Gleam program, for example data sent to a HTTP server as JSON. To convert data from dynamic into known Gleam types the decoder API is used.

A previous release added convenient a code action which would generate a dynamic decoder for a given type definition. With this release this code action has been extended to support multi-variant custom types. For example, given this type definition:

pub type Person {
  Adult(age: Int, job: String)
  Child(age: Int, height: Float)
}

If the code action is triggered on it then this function will be generated:

import gleam/dynamic/decode

fn person_decoder() -> decode.Decoder(Person) {
  use variant <- decode.field("type", decode.string)
  case variant {
    "adult" -> {
      use age <- decode.field("age", decode.int)
      use job <- decode.field("job", decode.string)
      decode.success(Adult(age:, job:))
    }
    "child" -> {
      use age <- decode.field("age", decode.int)
      use height <- decode.field("height", decode.float)
      decode.success(Child(age:, height:))
    }
    _ -> decode.failure(todo as "Zero value for Person", "Person")
  }
}

Thank you Surya Rose!

String interpolate code action

The language server now offers a convenient code action to interpolate a value into a string easily. If the cursor is inside a literal string the language server will offer to split it:

"wibble | wobble"
//      ^ Triggering the action with the cursor
//        here will produce this:
"wibble " <> todo <> " wobble"

And if the cursor is selecting a valid Gleam name, the language server will offer to interpolate it as a variable:

"wibble wobble woo"
//      ^^^^^^ Triggering the code action if you're
//             selecting an entire name, will produce this:
"wibble " <> wobble <> " woo"

Thank you Giacomo Cavalieri for this!

Module qualifier hovering

The language server can now show documentation for a module when hovering the module qualifier of an imported type or value. Thank you Surya Rose!

Redundant function capture removal

Gleam’s function capture syntax is a shorthand for creating an anonymous function that takes one argument and calls another function with that argument and some other values. These two expressions are equivalent:

let double = fn(number) { int.double(number, 2) }
let double = int.double(_, 2)

If the function capture syntax is used without any additional arguments, then it is redundant and does nothing that referring the function directly wouldn’t do.

let print = io.print(_)

The Gleam code formatter will now remove the redundant function capture syntax for you, formatting it like so:

let print = io.print

Thank you Giacomo Cavalieri!

And the rest

And thank you to the bug fixers: Giacomo Cavalieri, LostKobrakai, Louis Pilfold, Mikko Ahlroth Pedro Francisco, PgBiel, Richard Viney, and Surya Rose!

For full details of the many fixes and improvements they’ve implemented see the changelog.

A call for support

Gleam is not owned by a corporation; instead it is entirely supported by sponsors, most of which contribute between $5 and $20 USD per month, and Gleam is my sole source of income.

We have made great progress towards our goal of being able to appropriately pay the core team members, but we still have further to go. Please consider supporting the project or core team members Giacomo Cavalieri and Surya Rose on GitHub Sponsors.

Thank you to all our sponsors! And especially our top sponsor: Lambda.

Try Gleam