1 month and 10,910 lines of code later it is time for another Gleam
release! Let’s see what’s new this time.
Module constants
Sometimes we want to use a certain fixed value in multiple places in our
project. Until now we’ve had two options. The first option was to copy and
paste the value into multiple places in our code.
pub fn is_before(year: Int) -> Bool {
year <2101
}
pub fn is_during(year: Int) -> Bool {
2101 <= year && year <= 2111
}
Duplication of values like this is error prone, especially if we want to
update the values later, as we’ll need to find every place it’s used in order
to change it.
Another option is to wrap the value in a function.
pub fn start_year() -> Bool {
2101
}
pub fn end_year() -> Bool {
2111
}
pub fn is_before(year: Int) -> Bool {
year Bool {
start_year() <= year && year <= end_year()
}
This is better than copying the value in our code, but isn’t yet ideal. A
function can perform any amount of computation (with side effects!) when it is
called, so we have to read the definition of the function to be sure what it
does.
To make matters worse Gleam’s case clause guards don’t support calling of
functions within them, so this code will be rejected by the compiler:
pub describe(year: Int) -> String {
case year {
year if year "Before"
year if year > end_year() -> "After"
_ -> "During"
}
}
To solve all these problems Gleam now has module constants. They are always
inlined by the compiler, and can be used in case clause guards.
Using them the above code can be rewritten like so:
pub const start_year: Bool = 2101
pub const end_year: Bool = 2111
pub fn is_before(year: Int) -> Bool {
year Bool {
start_year <= year && year <= end_year
}
pub describe(year: Int) -> String {
case year {
year if year "Before"
year if year > end_year -> "After"
_ -> "During"
}
}
Much better! Module constants are going to provide the basis of some exciting
new features in future, so watch this space. :rocket:
Thanks to Ahmad Sattar
for taking the
lead in the implementation of this feature.
Bit string syntax
One of great things about Erlang is how easy it is to work with raw bits and
bytes using the bit string literal syntax. Starting with this release Gleam
supports this too!
Explaining all the things one can do with the bit string syntax would take
longer than I have now, but in short they give a declarative way of
constructing and parsing raw data of any format. What’s more the Erlang VM is
highly optimised for this, so bit syntax is highly efficient too!
For example, if I wanted to create a 4 byte unsigned little endian integer
with the value of 100 I could do so using bit syntax like this:
let my_integer = <<100:unsigned-little-int-size(4)>>
Or if I wanted to extract the title, artist, album, year, and comment from an
MP3 music file’s ID3 tags I could pattern match on it like this:
pub fn get_metadata(id3: BitString) -> Result(Metadata, String) {
case id3 {
<<
"TAG":utf8,
title:utf8-size(30),
artist:utf8-size(30),
album:utf8-size(30),
year:utf8-size(4),
comment:utf8-size(30),
_rest:binary,
>> -> Ok(Metadata(title, artist, album, year, comment))
_ -> Error("Not a valid ID3 tag")
}
}
Thanks to Benjamin Tan’s blog post
for this example.
For another example of bit syntax in action check out this
very serious
base64 encoding alternative
which converts arbitrary data into emojis!
As part of this new feature we have introduced BitString
and UtfCodepoint
types into the prelude, and split the standard library Iodata
type into
StringBuilder
and
BitBuilder
types, which
are for efficiently constructing strings and bit strings respectively.
Thanks to Tom Whatmore
for taking the
lead in the implementation of this feature.
The rest
For information on the rest of additions, improvements, and bug fixes in this
release please check out the Gleam changelog
and the standard library changelog
.
Supporting Gleam
If you would like to help make strongly typed programming on the Erlang
virtual machine a production-ready reality please consider
sponsoring
Gleam
via the GitHub Sponsors program.
This release would not have been possible without the support of all the
people who have sponsored
and contributed
to it, so a huge thank you to them.
-
Adelar da Silva Queiróz
-
Ahmad Sattar
-
Al Dee
-
Arian Daneshvar
-
Arno Dirlam
-
Ben Myles
-
Bruno Dusausoy
-
Bruno Michel
-
Bryan Paxton
-
Chris Young
-
Christian Meunier
-
Christian Wesselhoeft
-
Clever Bunny LTD
-
Dave Lucia
-
David McKay
-
Dym Sohin
-
Erik Terpstra
-
Gustavo Martins
-
Hasan YILDIZ
-
Hendrik Richter
-
hindenbug
-
Hécate
-
James MacAulay
-
Jan-Erik Rediger
-
John Palgut
-
José Valim
-
Kasim Tuman
-
Lars Wikman
-
Leandro Cesquini Pereira
-
Mario Vellandi
-
mario
-
Michael Jones
-
Mike Roach
-
ontofractal
-
Parker Selbert
-
Peter Saxton
-
Quinn Wilton
-
Robin Mattheussen
-
Sasan Hezarkhani
-
Sascha Wolf
-
Sasha
-
Saša Jurić
-
Sean Jensen-Grey
-
Sebastian Porto
-
Shayne Tremblay
-
Shritesh Bhattarai
-
Simone Vittori
-
Tom Whatmore
-
Tristan Sloughter
-
Tyler Wilcock
-
Wojtek Mach
Thanks for reading! Have fun! :purple_heart: