Because it's so good! Hear me out, Gleam has beautiful syntax; it's small yet very powerful.
Recently, Gleam has gained more popularity, and a lot of developers (including me) are learning it. At the time of this writing, it has exceeded 14k stars on GitHub; it grew really fast for the last month.
I'm sure there are other good reasons why Gleam is so good, but here are the reasons and features that I love Gleam for.
It's small and simple
One of the reasons many developers prefer C over other languages like C++ is that it's small.
And it's the same for Gleam; it's so small that you can learn it in an afternoon.
Small languages are good because they are fast to learn, fast to compile, and have fewer ways of doing things, which makes the code easier to read and reason about.
If you are interested in learning more about the good philosophy behind simple languages, check out this amazing article by Ryan Brewer.
Nice syntax
Gleam syntax is concise and easy to read. It saves you keystrokes when the full words are not necessary, for example fn
instead of function
, and pub
instead of public
.
One example I really liked is function captures. It's helpful when you want to use partial application with closures. It makes the code much shorter and easier to read.
Here's how I would implement the same example in both JavaScript and Gleam:
In JavaScript:
function add(a, b) {
return a + b
}
const addOne = (function () {
return function (b) {
return add(1, b)
}
})()
console.log(addOne(10)) // 11
In Gleam:
fn add(a: Int, b: Int) -> Int {
a + b
}
pub fn main() {
let add_one = add(1, _)
io.debug(add_one(10)) // 11
}
It's explicit
Since Gleam is a typed language, you will work with different types like floats and integers. Instead of guessing what both operand types are, you can know immediately from the operator type.
// Integers use the regular operator symbols
let add = a + b
let multiply = a * b
let compare = a > b
// and the others...
// Floats adds a dot after the operator
let add = a +. b
let multiply = a *. b
let compare = a >. b
// and the others...
I don't know about you, but this explicitness makes the code easier to understand and reason about for me.
Labelled arguments
The number of programming languages that support labelled arguments is relatively small. So, while it's not unique to Gleam, it's still one of the best decisions.
With labelled arguments, you don't have to remember the order of arguments when calling a function or go to the function definition to know what they are about.
Look at this example:
import gleam/io
fn log_message(message msg: String, level message_type: String) {
io.println("[" <> message_type <> "] " <> msg)
}
pub fn main() {
// When calling it you can change the order of arguments
log_message(level: "Error", message: "Record not found")
}
The cool thing about labelled arguments in Gleam is that you can give the argument a different label than the parameter name; see how msg
is labelled with message
and message_type
with level
. This is good when you want to provide a clearer name for the public API that is different from the internals.
Pipelines
Since Gleam is a functional language, you will write a lot of composed functions, meaning that the output of one function becomes the input to the next function.
With pipelines, your code will be much clearer and easier to read.
Here's an example without pipelines:
wrap_with_parenthesis(to_uppercase(remove_duplicate(letters)))
And here's with pipelines:
letters
|> remove_duplicate
|> to_uppercase
|> wrap_with_parenthesis
Reading code that uses pipelines is much more intuitive because we are reading step by step, from the value to the last function; whereas, without pipelines, you need to read from the value passed to the most inner function to the most outer one, which is more difficult to read.
Powerful flow control
While Gleam doesn't have an if
statement or return
keyword (yes, you heard it correct), it provides a much more powerful way called pattern matching.
If you are coming from a language that supports pattern matching, like Rust, you will instantly know what that means. Otherwise, it will feel odd to you at first. But once you learn it, you'll see why it's a better approach than other the ones.
Let me show you a quick example that I got from an exercise on exercism.
Let's say you have a string "[ERROR]: The error message"
, and you want to extract the message that comes after [ERROR]:
. With pattern matching you can simply do this:
pub fn get_message(log_line: String) -> String {
case log_line {
"[ERROR]:" <> msg -> msg
_ -> log_line
}
}
If you are not familiar with the syntax, it will feel confusing at first. But basically it just matches the message that comes after [ERROR]
on this line: "[ERROR]:" <> msg -> msg
. It gets rid of [ERROR]:
and just returns the message.
I didn't need any library or regular expression to do that. I'm just using the basic syntax of Gleam.
Developer friendly
There are tools that Gleam provides to improve the developer experience. My two top examples are the todo
and @deprecated
keywords.
With todo
, you can mark a specific function as unimplemented and provide a message for the reason.
pub fn do_something() {
todo as "I need to get other_function ready first"
}
And with @deprecated
, you can mark some function as deprecated and provide directions to what the user should use instead.
@deprecated("Use new_function instead")
fn old_function() {
Nil
}
Friendly community
No matter how many questions you have, or how difficult or easy they are, you can ask them on the Gleam Discord's channel and you will get the answer.
Seeing how friendly and helpful the community is makes me enjoy working with Gleam more.
Start learning Gleam
If you are interested in learning Gleam, start with their language tour, and then I highly recommend doing the exercises on Exercism. They are exceptionally good!
π Let's stay connected:
- π Blog: https://tahazsh.com/
- π Twitter/X: https://twitter.com/tahazsh
- π Mastodon: https://fosstodon.org/@tahazsh
- π₯ YouTube: https://www.youtube.com/@tahazsh
Top comments (0)