Desugaring ?
What's syntax sugar?
Syntax within a programming language that is designed to make things easier to read or express. It allows developers to write code in a more concise, readable, or convenient way without adding new functionality to the language itself.
Desugaring converts syntax sugar (like x + 1
) into more fundamental operations (like Num.add(x, 1)
).
Let's see how ?
is desugared. In this example we will extract the name and birth year from a
string like "Alice was born in 1990"
.
parse_name_and_year : Str -> Result { name : Str, birth_year : U16 } _ parse_name_and_year = |str| { before: name, after: birth_year_str } = Str.split_first(str, " was born in ")? birth_year = Str.to_u16(birth_year_str)? Ok({ name, birth_year })
After desugaring, this becomes:
parse_name_and_year_try = |str| when Str.split_first(str, " was born in ") is Err(err1) -> return Err(err1) Ok({ before: name, after: birth_year_str }) -> when Str.to_u16(birth_year_str) is Err(err2) -> return Err(err2) Ok(birth_year) -> Ok({ name, birth_year })
So birth_year = Str.to_u16(birth_year_str)?
is converted to
when Str.to_u16(birth_year_str) is Err(err2) -> return Err(err2) Ok(birth_year) -> birth_year
As you can see, the first version is a lot nicer!
Thanks to ?
, you can write code in a familiar way and you get the benefits of Roc's
error handling to drastically reduce the likelihood of crashes.
Full Code
app [main!] { cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.19.0/Hj-J_zxz7V9YurCSTFcFdu6cQJie4guzsPMUi5kBYUk.tar.br" } import cli.Stdout main! = |_args| Stdout.line!(Inspect.to_str(parse_name_and_year("Alice was born in 1990")))? Stdout.line!(Inspect.to_str(parse_name_and_year_try("Alice was born in 1990")))? Ok({}) ### start snippet question parse_name_and_year : Str -> Result { name : Str, birth_year : U16 } _ parse_name_and_year = |str| { before: name, after: birth_year_str } = Str.split_first(str, " was born in ")? birth_year = Str.to_u16(birth_year_str)? Ok({ name, birth_year }) ### end snippet question ### start snippet desugared parse_name_and_year_try = |str| when Str.split_first(str, " was born in ") is Err(err1) -> return Err(err1) Ok({ before: name, after: birth_year_str }) -> when Str.to_u16(birth_year_str) is Err(err2) -> return Err(err2) Ok(birth_year) -> Ok({ name, birth_year }) ### end snippet desugared expect parse_name_and_year("Alice was born in 1990") == Ok({ name: "Alice", birth_year: 1990 }) expect parse_name_and_year_try("Alice was born in 1990") == Ok({ name: "Alice", birth_year: 1990 })
Output
Run this from the directory that has main.roc
in it:
$ roc main.roc Ok({birth_year: 1990, name: "Alice"}) Ok({birth_year: 1990, name: "Alice"})