Published 25 Sep, 2023 by Louis Pilfold
Gleam is a type safe and scalable language for the Erlang virtual machine and JavaScript runtimes. Today Gleam v0.31.0 has been released, let’s take a look at what’s new.
Requiring explicit dependencies
A Gleam application’s dependency graph contains no duplicate packages, each package has exactly one version.
Application
│
▼
library_a
│
▼
library_b
Here the application has specified library_a
as a dependency in its
gleam.toml
, and library_a
has specified library_b
as a dependency in its
own gleam.toml
.
As there’s no ambiguity as to what version to use Gleam has historically allowed
importing modules from packages that you don’t directly depend upon. The
application could happily import modules from library_b
.
Over time we have learnt that this form of indirect dependency is unclear and confusing to a lot of folks, so we’re moving to making dependencies explicit and only permitting imports from direct dependencies.
With this release Gleam will now emit a warning when importing modules from a package your application does not directly depend upon, and in future versions of Gleam this will become an error.
warning: Transative dependency imported
┌─ src/app.gleam:2:1
│
2 │ import mist
│ ^^^^^^^^^^^
The module `mist` is being imported, but `mist`, the package it belongs to,
is not a direct dependency of your package.
In a future version of Gleam this may become a compile error.
Run this command to add it to your dependencies:
gleam add mist
Marking functions as deprecated
The @deprecated("...")
attribute has been added to allow marking functions as
deprecated.
If a deprecated function is used Gleam will emit a warning during compliation, informing the programmer that they need to update their code.
pub fn main() {
deprecated_function()
}
@deprecated("This function is not good! Use `new_function` instead, it is better.")
fn deprecated_function() {
// Inset implemenation here...
}
warning: Deprecated value used
┌─ /Users/louis/Desktop/thingy/src/thingy.gleam:2:3
│
2 │ deprecated_function()
│ ^^^^^^^^^^^^^^^^^^^ This value has been deprecated
It was deprecated with this message: This function is not good! Use
`new_function` instead, it is better.
Quality of life improvements
As we’re now ramping up to version 1.0 we’re making lots of small improvements to the ergonomics of the language.
The record access syntax (person.name
) can now be used in case clause guard
expressions.
pub fn listed(names: List(String), person: Person) -> String {
case names {
[name, ..names] if name == person.name -> True
[_, ..names] -> listed(names, person)
[] -> False
}
}
The as
keyword can now be used to assign the prefix of a string to a variable when pattern matching.
pub fn parse_tag(tag: String) -> Result(Tag, Nil) {
case tag {
"category " as key <> value
| "region " as key <> value
| "priority " as key <> value -> {
let key = string.trim(key)
Ok(Tag(key, value))
}
_ -> Error(Nil)
}
}
And the standard library gleam/int
module now has a series of functions for
performing bitwise operations.
int.bitwise_and(9, 3)
// -> 1
int.bitwise_or(9, 3)
// -> 11
int.bitwise_exclusive_or(9, 3)
// -> 10
int.bitwise_not(2)
// -> -3
int.bitwise_shift_left(1, 2)
// -> 4
int.bitwise_shift_right(1, 2)
// -> 0
Wisp
Gleam has been used to make backend web applications for a good few years, but without a helpful web framework the programmer has to feel comfortable piecing together various packages to build their application.
Most folks are not so interested in the nitty-gritty of how to put together a web application and want to focus on the business logic of their application, so the Wisp framework has been created to help folks get on with solving problems with Gleam.
Wisp takes the lessons learnt from various existing Gleam web applications and web frameworks in other languages, and provides a practical, type safe, and magic-free experience for building web applications. A Wisp request handler looks a like this:
import gleam/result.{try}
import my_app/people
import my_app/web.{Context}
import wisp.{Request, Response}
pub fn handle_request(req: Request, ctx: Context) -> Response {
use json <- wisp.require_json(req)
let result = {
use params <- try(people.parse_params(json))
use person <- try(people.save(params, ctx.db))
Ok(people.to_json(person))
}
case result {
Ok(body) -> wisp.json_response(body, 201)
Error(_) -> wisp.bad_request()
}
}
Today Wisp has a small feature set similar to that of Ruby’s Sinatra or Python’s Flask, but it is expected to grow over time to include more features as the maintainers and community decides what is useful and how they should work.
Wisp is not a Gleam-core project like the compiler or the standard library, but I (Louis Pilfold, Gleam’s creator) am the primary maintainer of Wisp, and the framework has been designed with the help of prominent members of the Gleam community.
Check out the website and the source code if you’d like to learn more. 🧚
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!
- Aaron Gunderson
- Adam Brodzinski
- Adam Mokan
- Adi Iyengar
- Alembic
- Alex Manning
- Alexander Koutmos
- Alexander Stensrud
- Alexandre Del Vecchio
- Ali Farhadi
- Amaan Qureshi
- Andy Aylward
- Anthony Khong
- Anthony Scotti
- Arnar Gauti Ingason
- Arnaud Berthomier
- Ben Marx
- Ben Myles
- Benjamin Peinhardt
- brettkolodny
- Brian Glusman
- Bruno Michel
- Bruno Parga
- by34
- Carlo Gilmar
- Carlos Saltos
- Chew Choon Keat
- chiroptical
- Chris Lloyd
- Chris Ohk
- Chris Rybicki
- Christopher Keele
- cijiugechu
- clangley
- Clay
- Coder
- Cole Lawrence
- Colin
- Cosmo Shin (신의하)
- Cristine Guadelupe
- Damir Vandic
- Dan Dresselhaus
- Danielle Maywood
- Danny Martini
- Dave Lucia
- David Bernheisel
- David Flanagan
- David Sancho
- dependabot[bot]
- Dmitrii Maganov
- Dmitry Poroh
- Edon Gashi
- Elliott Pogue
- Erik Terpstra
- Ernesto Malave
- Fernando Farias
- Filip Figiel
- Florian Kraft
- fly.io
- Ganesh Gupta
- Giacomo Cavalieri
- Graeme Coupar
- Guilherme de Maio
- Gustavo Villa
- Harry Bairstow
- Hayleigh Thompson
- Hazel Bachrach
- Henry Warren
- Hex
- hms
- Ian González
- Ingmar Gagen
- inoas
- Ivar Vong
- James MacAulay
- Jan Skriver Sørensen
- Jechol Lee
- Jen Stehlik
- jiangplus
- John Björk
- John Gallagher
- John Palgut
- Jonas Hedman Engström
- Jonathan Arnett
- Josef Richter
- Kayla Washburn
- Kieran Gill
- Lars Wikman
- Leon Qadirie
- lidashuang
- Manuel Rubio
- Marcin Koziej
- Marius Kalvø
- Mark Holmes
- Mark Markaryan
- Mark Story
- Markus
- Martin Janiczek
- Matt Van Horn
- matthew.cobbing
- Matthias Benkort
- max-tern
- Michael Chris Lopez
- Michael Davis
- Michael Duffy
- Michael Jones
- Mike Roach
- Mikko Ahlroth
- Natanael Sirqueira
- Nathaniel Knight
- NFIBrokerage
- Nick Reynolds
- Nicklas Sindlev Andersen
- NineFX
- Nino Annighoefer
- Noah Betzen
- Ocean Armstrong Lewis
- OldhamMade
- Ole Michaelis
- ontofractal
- Parker Selbert
- Paul Gideon Dann
- Pete Jodo
- Peter
- Prashant Singh Pawar
- Praveen Perera
- qingliangcn
- Raúl Chouza
- Redmar Kerkhoff
- Rico Leuthold
- Robert Attard
- Robert Ellen
- Rohit
- Ryan Winchester
- Sam Aaron
- Sammy Isseyegh
- Saša Jurić
- Scott Wey
- Sean Jensen-Grey
- Sebastian Porto
- SEKUN
- Septem Li
- Seve Salazar
- shayan javani
- Shuqian Hon
- Signal Insights
- Simone Vittori
- Stefan Luptak
- Strand Communications
- Szymon Wygnański
- Terje Bakken
- Theo Harris
- Tomasz Kowal
- Tristan Cacqueray
- Tristan Sloughter
- Weizheng Liu
- Willyboar
- Wilson Silva
- Wojtek Mach
- Wolf
- Xetera
- Yasuo Higano
- Yu Matsuzawa
- Zsombor Gasparin
- Šárka Slavětínská
Thanks for reading! Happy hacking! 💜