Gleam is a type safe and scalable language for the Erlang virtual machine and JavaScript runtimes. Today Gleam v0.32.0 has been published, a release that focuses on getting Gleam ready for a v1.0 release by making some breaking changes before the language is declared stable.

Resolving import ambiguity

Here is what Gleam’s import syntax looks like:

import gleam/option.{Option, Some, None}

pub fn greet(option: Option(String)) -> String {
  case option {
    Some(name) -> "Hello " <> name
    None -> "Hello, World!"
  }
}

Here the module gleam/option is being imported, and the values Some, and None and the type Option are being imported in an unqualified manner so they can be referred to without the module_name. prefix.

While Option is a type and None is a value they are both imported using the same syntax. This becomes more complex when we consider that in Gleam a type and a value can have the same name. For example:

/// A type called `Person`
pub type Person {
  /// A value constructor, also called `Person`
  Person(name: String)
}

In this case when you read the code import the/module.{Person} you cannot tell if the type is being imported, the value, or both. This ambiguity is resolved by the compiler by checking to see how the imported item is used.

Clarity is a core goals of Gleam, so to ease the cognitive load of reading Gleam code the syntax for importing types and values has been altered.

import gleam/option.{type Option, Some, None}

To import a type the keyword type is used before the name, no keyword being used for a value. Now it is always clear what an import statement is doing!

The old syntax is still supported, but will be removed in a future release, and a deprecation warning will be emitted when it is used.

BitString -> BitArray

Gleam has a type for a contiguous sequence of bits. It is similar to Python’s bytes type, however it is not restricted to 8 bit bytes, it can be any number of bits.

It also features a literal syntax for construction and pattern matching, so much of what you would need to use bitwise operations for in other languages can be done with a simpler syntax.

pub fn seven_bit_little_endian_int() -> BitString {
  <<2:size(7)-little>>
}

This feature, which Gleam inherited from Erlang, is much loved by the community except for the name. Many Gleam users, especially those coming from languages other than Erlang or Elixir, find the name BitString confusing. What does it have to do with strings? It is for text only?

This confusion is understandable, and so the name has been changed to BitArray, and in the pattern syntax the binary and bit_string options have been renamed to bytes and bits, hopefully making their purpose clearer. Along with this the gleam/bit_string standard library module has been deprecated in favour of gleam/bit_array. The old names and module are deprecated and will be removed in a future release.

The return of gleam fix

Wow, that’s a lot of deprecated stuff! It’s going to be annoying to fix all the existing code, right? Thankfully not, as the gleam fix command is back.

Run gleam fix in the root of any Gleam package and it will automatically update your code to use the new syntax. It will also update the gleam.toml file to set the Gleam version constraint to >= 0.32.0, ensuring that if you publish your package to the Hex package manager any users on older versions of Gleam won’t get confusing errors coming from the new syntax.

Language server code actions

The gleam binary includes the compiler, the build tool, the package manager, and also the language server, which provides IDE features to VS Code, Vim, Emacs, and any other edit which support the protocol.

With this release the language server gets its first code action! It can now automatically remove all unused imports with a single press of a button.

This is a nice convenience feature, but it also means that the language server internally has the infrastructure in place to add more code actions in future. User experience and productivity is highly important to us, so the language server will be getting more code actions and new features in future releases.

Thank you Tristan de Cacqueray for this feature!

Target specific gleam check

If during development you want to see whether your code type checks but don’t care about compiling it to run your tests you can use the gleam check command.

With this release it gains the --target flag, allowing you to specify a compilation target other than the default for the package. This is useful in packages that use conditional compilation, a less common but sometimes necessary Gleam feature.

Thank you Kunal Kundu for this feature!

Module access in guard expressions

Values defined in other modules can now be referenced in case clause guards expressions using the module_name.value syntax.

import some/module.{type Person}

pub fn greet(person: Person) -> String {
  case person {
    Person(name: n) if n == module.friends_name -> "Hey Buddy!"
    _ -> "Hello! Welcome!"
  }
}

Thank you Shayan Javani for this feature!

Bit array constants on the JavaScript target

Bit arrays can now be used in constant expressions on the JavaScript target.

pub const some_bits = <<1, 2, 3, 4>>

Thank you Shayan Javani for this feature!

@deprecated types

The previous release added the @deprecated attribute, which could be used to mark values as deprecated. This release extends this to allow type definitions to be marked as deprecated too.

@deprecated("Use the Pet type instead")
pub type Animal {
  Cat
  Dog
}

When a type is marked as deprecated the compiler will emit a warning when the type or any of its value constructors are referenced.

Thank you Om Prakaash for this feature!

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