Gleam is a type safe and scalable language for the Erlang virtual machine and JavaScript runtimes. Today Gleam v1.18.0 has been published.
Language server record field support
Gleam's focus on static analysis and static types really helps with creating tooling, and that can be seen very clearly with Gleam's much-loved language server. All its features and capabilities can be seen in its documentation.
One remaining missing part of it was full support for record fields, a problem
now fixed! The language server now supports go-to-definition, find-references
and rename for record fields. These work on the field declaration, on labelled
arguments, on labelled patterns, on record updates and on record.field
accesses, both within a module and across modules. For example:
pub type Person {
Person(name: String, age: Int)
}
pub fn main() {
let lucy = Person(name: "Lucy", age: 10)
lucy.name
// ^ Go-to-definition jumps to the `name` field, and renaming it here
// renames the field everywhere it is used.
}
Thank you Alistair Smith! People will be very happy for this one!
Type variable renaming
Similarly, the language server now permits renaming type variables in functions, types, and constants. For example:
pub fn twice(value: a, f: fn(a) -> a) -> a {
// ^ Rename to "anything"
f(f(value))
}
Produces:
pub fn twice(value: anything, f: fn(anything) -> anything) -> anything {
f(f(value))
}
Thank you Surya Rose!
Updating imports for renamed modules
Another addition to the language server is support for renaming modules. When your text editor tells the language server that a Gleam file has been renamed, it will find all the uses of that module and update them for the new name. For example:
import db_users
pub fn main() -> db_users.User {
db_users.new("username")
}
Renaming db_users.gleam to database/user.gleam would produce:
import database/user
pub fn main() -> user.User {
user.new("username")
}
Thank you Surya Rose!
Pattern match on value code action
Flow control in Gleam is done with pattern matching. With how common this is,
the language server's "pattern match on value" code action is a great
time-saver, quickly inserting a case expression that the programmer can add
their logic to.
The code action can now be triggered on function calls and their returned values. For example:
pub fn main() {
load_user()
// ^^ Triggering the code action over here
}
fn load_user() -> Result(User, Nil) { todo }
Will produce the following code:
pub fn main() {
case load_user() {
Ok(value) -> todo
Error(value) -> todo
}
}
Thank you Giacomo Cavalieri!
Faster JavaScript with data singletons
When targeting JavaScript, Gleam's compiler outputs straightforward JavaScript code, similar to what a human would write. This gives it performance similar to hand-written JavaScript, which the web framework Lustre has used to achieve comparable or better performance to JavaScript frameworks, such as React.
That said, there is always opportunity to improve the code generated by a compiler. Gleam will now identify data structures where all instances are equivalent, and use a single value for each use instead of constructing a new instance each time.
Take this Gleam code, for example:
import gleam/option.{type Option}
pub fn two_optionals() -> #(Option(a), Option(b)) {
#(option.None, option.None)
}
You could imagine that previously, that Gleam code would compile to JavaScript code like this (pseudocode):
import { None } "../gleam_stdlib/gleam/option.mjs";
export function two_optionals() {
return [None.new(), None.new()];
}
While now code closer to this will be generated (pseudocode):
import { None } "../gleam_stdlib/gleam/option.mjs";
export function two_optionals() {
return [None.instance, None.instance];
}
In our tests this has an impactful improvement to performance, especially to
code that uses lots of these data structures such as the view functions of
Lustre applications.
Thank you Surya Rose for this optimisation!
Ambiguous pipe syntax deprecation
Gleam's much-loved pipe syntax gives programmers another way to write nested function calls so that they read top-to-bottom and left-to-right.
The pipeline one |> two is equivalent to two(one). Most of the time one |> two(three)
is equivalent to two(one, three), however if that doesn't result in the
correct types then it can instead compile to two(three)(one). This second
option means that the pipe syntax is visually ambiguous, and one cannot tell
exactly how it compiles without knowing about the function being called. This
is not in keeping with the wider language, so the two(three)(one) version has
been deprecated and will need to be written explicitly as one |> two(three)().
With this, pipelines have the same rules as use expressions, and the reader
can always tell how they compile.
We scanned all the publicly published Gleam code and found that the deprecated style is almost never used, but just to help anyone who is using it, the language server now offers a code action to fix the new deprecated style.
Thank you Surya Rose!
Git dependency path support
Gleam's build tool supports adding dependencies from git repositories, which is often useful if there is a package that is not ready to be published, but you still want to try it out. The build tool didn't let you specify a path within the git repository, so if the package you want to use isn't at the root of the repository then you were out-of-luck.
To resolve this John Downey has added
an optional path field for git dependencies, to specify a subdirectory within
the repository.
[dependencies]
my_package = {
git = "https://github.com/example/monorepo",
ref = "main",
path = "packages/my_package",
}
Thank you John! Monorepo fans rejoice!
Raising Hex API limits
Gleam uses Hex, the package manager for the Erlang ecosystem. It has rate
limits that will not be hit in typical use, but can cause problems for folks
doing many chatty operations, such as running gleam deps update on many
packages within a monorepo.
Hex offers much higher rate limits for authenticated requests, so an API key
can now be provided to Gleam via the HEXPM_READ_API_KEY environment variable.
This will only be used for read operations, so we recommend using an API key
that only has read permissions.
Thank you John Downey!
Hex experience improvements
That's not all for Hex, we've also fixed a bunch of sharp edges in the Gleam developer experience when working with the package manager.
Moritz Böhme has added a helpful error message for when someone attempts to revert a release that is older than 24 hours and so cannot be reverted. Previously the error from the API would be shown, which could be confusing.
He has also improved the error message when failing to decrypt a locally stored Hex API key, such as due to making a typo in the decryption password. Thank you Moritz!
Surya Rose has updated the Gleam build
tool to use the new Hexdocs URLs, as they recently switched from
hexdocs.pm/package_name to package-name.hexdocs.pm for security reasons.
Lastly, the gleam hex owner transfer command now takes the username via the
flag --user, and the gleam hex owner add command now takes the package name
via the flag --package. This should make these commands a little easier to
understand.
Convert int base code action
Like many languages, Gleam supports writing ints in decimal, octal, hexadecimal, and binary. The language server now offers code actions to switch between them instantly. For example:
pub fn lucky_number() {
0b1011
//^^^^^^ Hovering this
}
The language server is going to show code actions to rewrite it as 11,
0o13, or 0xB. Thank you Giacomo Cavalieri!
Generate missing type code action
The language server now offers a code action to generate a missing type
definition when an unknown type is referenced. For example, if Wibble
is not defined:
pub fn run(data: Wibble(Int)) { todo }
The code action will generate:
pub type Wibble(a)
pub fn run(data: Wibble(Int)) { todo }
Thank you Daniele Scaratti!
In addition to regular double-slash comments, Gleam has triple and quadruple slash comments which are used for writing API documentation. The language server now has code actions to convert between regular comments and documentation comments. For example:
// Module description.
// Code action available here.
// Comment before function.
// Another code action here.
pub fn wibble() {
// No code action here.
todo
}
/// Doc comment.
/// Another code action here.
pub fn wobble () {
todo
}
Triggering the code actions in all of these places will result in:
//// Module description.
//// Code action available here.
/// Comment before function.
/// Another code action here.
pub fn wibble() {
// No code action here.
todo
}
// Doc comment.
// Another code action here.
pub fn wobble () {
todo
}
Thank you Daniel Venable!
Redundant alias fixing
Gleam's automatic code formatter will now remove redundant import aliases that have no effect on the code. For example:
import wibble.{Wibble as Wibble}
The name and the alias of the imported value are both Wibble, so the
formatter will remove the alias like so:
import wibble.{Wibble}
Thank you Daniel Venable!
Faster compilation with arenas
But wait, where is Giacomo Cavalieri? Normally there are many changes with his name next to them in a Gleam release post… Well he has been busy making large changes to compiler internals, namely introducing memory arenas. He has gone into detail about this on his blog, so I've let him explain there.
The user-facing outcome of this is improved performance of the code generators
and the formatter. gleam format has been measured to be up to 13% faster on
projects like lustre, with a 10% smaller peak memory footprint!
This work is still ongoing, and we should have some very exciting additions in future releases.
And more!
And a huge thank you to the bug fixers and experience polishers:
0xda157, Andrey Kozhev, Asish Kumar, Charlie Tonneslan, Eyup Can Akman, Francesco Cappetti, Gavin Morrow, Giacomo Cavalieri, John Downey, Matt Champagne, Surya Rose, and Zbyněk Juřica.
For full details of the many fixes and improvements they've implemented, see the changelog.
Support Gleam
Gleam is not from big-tech and has not taken any VC funding. We rely entirely on the community for our livelihoods.
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 contributors! And special thanks to our top sponsor:
- # <h1>NinaLovesToPutLongTextIntoNameFields.GitHubNamesArePrettyFun(IThinkThereAreOnlyAFewAnnoyingBugsAndOneFormThatStoppedWorkingCompletely).AnywayCheckOutGleam!ItIsAReallyCoolLanguageWithALovelyCommunity.BLM!CovidIsNotOver!TransRightsAreHumanRights!</h1>
- 0xda157
- Aaron Zuspan
- Abel Jimenez
- Aboio
- Adam Brodzinski
- Adam Daniels
- Adam Johnston
- Adi Iyengar
- Adrian Mouat
- Ajit Krishna
- albertchae
- Aleksei Gurianov
- Alembic
- Alex Houseago
- Alex Kelley
- Alex Manning
- Alexander Stensrud
- Alexandre Del Vecchio
- Aliaksiej Homza
- Alistair Smith
- Ameen Radwan
- Andrey
- André Mazoni
- Andy Young
- Antharuu
- Anthony Scotti
- Antonio Farinetti
- Arthur Weagel
- Arya Irani
- Asish Kumar
- Baqtiar
- Barry Moore II
- Bart Louwers
- Ben Martin
- Ben Myles
- Benjamin Kane
- Benjamin Moss
- bgw
- Billuc
- blurrcat
- Brad Mehder
- Brett Cannon
- Brett Kolodny
- Brian Glusman
- Bruce Williams
- Bruno Konrad
- bucsi
- Caleb Falcione
- Cameron Presley
- Carlo Munguia
- Carlos Saltos
- Chad Selph
- Charlie Aten
- Charlie Tonneslan
- Chew Choon Keat
- Chris Lloyd
- Chris Ohk
- Chris Vincent
- Christian Visintin
- Christopher De Vries
- Christopher Keele
- Clifford Anderson
- Coder
- Cole Lawrence
- Comamoca
- Constantin (Cleo) Winkler
- Corentin J.
- Cris Holm
- Curling IO
- Cyphernil
- dagi3d
- Damir Vandic
- Dan
- Dan Dresselhaus
- Dan Gieschen Knutson
- Dan Piths
- Dan Strong
- Daniele
- daniellionel01
- DanielVenable
- Daniil Nevdah
- Danny Arnold
- Danny Martini
- Dave Lucia
- David Bernheisel
- David Cornu
- David Pendray
- dependabot[bot]
- Diemo Gebhardt
- Djordje Djukic
- Dylan Anthony
- Dylan Carlson
- Ed Rosewright
- Edon Gashi
- Eileen Noonan
- Eric Koslow
- Erik Ohlsson
- Erik Terpstra
- erikareads
- ErikML
- erlend-axelsson
- Ernesto Malave
- Ethan Olpin
- Evaldo Bratti
- Evan Johnson
- evanasse
- Eyüp Can Akman
- Fabrizio Damicelli
- Falk Pauser
- Fede Esteban
- Felix
- Felix Dumbeck
- Filip Figiel
- Florian Kraft
- frakappa
- Francis Hamel
- frankwang
- G-J van Rooyen
- Gabriela Sartori
- Gavin Morrow
- Gears
- Geir Arne Hjelle
- Giacomo Cavalieri
- ginkogruen
- Giovanni Kock Bonetti
- Grant Everett
- graphiteisaac
- Guilherme de Maio
- Guillaume Heu
- Hannes Nevalainen
- Hans Raaf
- Hari Mohan
- Harry Bairstow
- Hazel Bachrach
- Henning Dahlheim
- Henrik Tudborg
- Henry Warren
- Heyang Zhou
- Hizuru3
- Hubert Małkowski
- Iain H
- Ian González
- Ian M. Jones
- idea-list
- Igor Montagner
- inoas
- Isaac Harris-Holt
- Isaac McQueen
- iskrisis
- Ivar Vong
- Jachin Rupe
- Jake Cleary
- Jake Wood
- James Birtles
- James MacAulay
- James Turner
- Jan Fooken
- Jan Pieper
- Jan Skriver Sørensen
- Jean Niklas L'orange
- Jean-Adrien Ducastaing
- Jean-Luc Geering
- Jen Stehlik
- Jerred Shepherd
- Jimmy Utterström
- Joey Kilpatrick
- Joey Trapp
- Johan Strand
- Johanna Larsson
- John Björk
- John Downey
- John Strunk
- Jojor
- Jon Charter
- Jon Lambert
- Jonas E. P
- Jonas Hedman Engström
- jooaf
- Joseph Lozano
- Joshua Steele
- José Valim
- João Palmeiro
- jstcz
- Julian Hirn
- Julian Lukwata
- Julian Schurhammer
- Justin Lubin
- Jérôme Schaeffer
- Jørgen Andersen
- KamilaP
- Kemp Brinson
- Kero van Gelder
- Kevin Schweikert
- Kile Deal
- Kirill Morozov
- Kramer Hampton
- Kristoffer Grönlund
- Kristoffer Grönlund
- Krzysztof Gasienica-Bednarz
- Kuma Taro
- Landon
- Leah Ulmschneider
- Lennon Day-Reynolds
- Leon Qadirie
- Leonardo Donelli
- Lexx
- lidashuang
- Lukas Bjarre
- Luke Amdor
- Manuel Rubio
- Marius Kalvø
- Mark Dodwell
- Mark Holmes
- Mark Markaryan
- Markus Stark
- Markus Wesslén
- Martin Fojtík
- Martin Janiczek
- Martin Poelstra
- Martin Rechsteiner
- Matt Champagne
- Matt Heise
- Matt Mullenweg
- Matt Savoia
- Matt Van Horn
- Matthew Jackson
- Max Duval
- Max McDonnell
- METATEXX GmbH
- Michael Davis
- Michael Duffy
- Michael G
- Michael Jones
- Michael Mazurczak
- Michal Timko
- Mikael Karlsson
- Mike Roach
- Mikey J
- MoeDev
- Moin
- Moritz Böhme
- MrBocch
- N. G. Scheurich
- n8n - Workflow Automation
- Natalie Rose
- Nessa Jane Marin
- Nick Leslie
- Nick Papadakis
- Nicklas Sindlev Andersen
- NicoVIII
- Nigel Baillie
- Niket Shah
- Nikolai Steen Kjosnes
- Nikolas
- NineFX
- nkxxll
- Nomio
- nunulk
- Olaf Sebelin
- OldhamMade
- Oliver Medhurst
- Oliver Tosky
- ollie
- Optizio
- P.
- Patrick Wheeler
- Paul Guse
- Pedro Correa
- Pete Jodo
- Peter Rice
- Philpax
- Qdentity
- R.Kawamura
- Race
- Rasmus
- Raúl Chouza
- rebecca
- Redmar Kerkhoff
- Reilly Tucker Siemens
- Renatillas
- Renato Massaro
- Renovator
- Rico Leuthold
- Rintaro Okamura
- Ripta Pasay
- Rob Durst
- Robert Attard
- Robert Ellen
- Robert Malko
- Rodrigo Álvarez
- Rohan
- Rotabull
- Rupus Reinefjord
- Ruslan Ustitc
- Russell Clarey
- Ryan Moore
- Sakari Bergen
- Sam Aaron
- Sammy Isseyegh
- savanto
- Savva
- Saša Jurić
- Scott Trinh
- Scott Wey
- Sean Cribbs
- Sebastian Porto
- Seve Salazar
- Sgregory42
- Shane Poppleton
- Shawn Drape
- Shunji Lin
- shxdow
- Sigma
- simone
- Spenser Black
- SR
- Stefan
- Steinar Eliassen
- Stephane Rangaya
- Strandinator
- Sławomir Ehlert
- Thomas
- Thomas Coopman
- Thomas Crescenzi
- Tim Brown
- Timo Sulg
- Tobias Ammann
- Tomasz Kowal
- tommaisey
- Tristan Sloughter
- Tudor Luca
- Tyler Butler
- upsidedowncake
- Valerio Viperino
- Vassiliy Kuzenkov
- vemolista
- Viv Verner
- Volker Rabe
- Will Ramirez
- Wilson Silva
- Xucong Zhan
- Yamen Sader
- Yasuo Higano
- Zach Krzyzanowski
- Zbyněk Juřica
- Zsolt Kreisz
- ZWubs
- ~1814730
- ~1847917
- ~1867501
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.