diff --git a/_posts/2024-01-19-gleams-new-interactive-language-tour.md b/_posts/2024-01-19-gleams-new-interactive-language-tour.md index 7c00ce01..5ebc1c11 100644 --- a/_posts/2024-01-19-gleams-new-interactive-language-tour.md +++ b/_posts/2024-01-19-gleams-new-interactive-language-tour.md @@ -1,7 +1,7 @@ --- author: Louis Pilfold author-link: https://github.com/lpil -title: Gleam's New Interactive Language Tour +title: Gleam's new interactive language tour subtitle: Learn Gleam in your browser! tags: - Release diff --git a/_posts/2024-05-27-fault-tolerant-gleam.md b/_posts/2024-05-27-fault-tolerant-gleam.md new file mode 100644 index 00000000..d3eed28f --- /dev/null +++ b/_posts/2024-05-27-fault-tolerant-gleam.md @@ -0,0 +1,831 @@ +--- +author: Louis Pilfold +author-link: https://github.com/lpil +title: Fault tolerant Gleam +subtitle: Gleam v1.2.0 released +tags: + - Release +--- + +Gleam is a type safe and scalable language for the Erlang virtual machine and +JavaScript runtimes. Today Gleam [v1.2.0][release] has been published, a release +that focuses on improving the language server and developer experience. It's a +big one both in terms of size and impact, so let's take a look as what it +includes. + +[release]: https://github.com/gleam-lang/gleam/releases/tag/v1.2.0 + + +## Fault tolerant compilation + +Gleam's compiler has traditionally halted immediately when a compile time error +was encountered, presenting the error to the programmer and requiring them to +fix it before compilation can be attempted again. + +The main advantage of this is that the programmer has just the first and +most important error, rather than a mix of the real error and a bunch of +red-herring cascading errors. On the other hand, if there's multiple genuine +errors the programmer can only see first the one, which may not be the one they +want to work on, or the most understandable. + +Even worse, this halting behaviour causes major issues for the Gleam Language +Server (the engine that text editors like Neovim, Helix, Zed, and VS Code use to +get IDE features for Gleam). The language server internally uses the compiler to +build and analyse Gleam projects, so when the compiler halts with an error the +language server is left without up-to-date information about the code. Without a +successful build some language server features may not work, and the longer a +project goes without successful compilation (such as during a large refactoring) +the more drift there can be between the language server's understanding of the +code and the reality. + +With this release when the compiler encounters an error during analysis it will +move on to the next definition in the module, returning all of the errors along +with updated code information once the whole module has been analysed. This has +resulted in a dramatic improvement in the experience when using the Gleam +language server, it being much more responsive and accurate in its feedback. + +In future releases we will continue to improve the granularity of the fault +tolerant compilation and we will also introduce fault tolerant parsing. + +Thanks to [Ameen Radwan](https://github.com/Acepie) and myself for this feature! + + +## Language server imports improvements + +This is a Gleam import statement: +```gleam +import gleam/option.{type Option, Some, None} +// ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ +// the module unqualified imports +``` + +The language server could previously autocomplete module names, but now it can +also autocomplete types and values when importing them in the unqualified +fashion. + +You can also hover types and values in an import statement to see their +documentation, and use go-to definition on them and the module itself to jump +to where they defined in your project or its dependencies. + + +## Single line pipelines + +Gleam's much loved `|>` pipe operator can be used to pipe the output from one +function into the input of another, not dissimilar to `|` pipes in bash, etc. +Gleam's code formatter would always put each function of a sequence of pipes on +individual lines, but now you can opt to put them all on one line, so long as +altogether they are short enough to fit. +```gleam +[1, 2, 3] |> list.map(int.to_string) |> string.join(with: "\n") +``` + +In addition you can also force the formatter to break a pipe on multiple lines +by adding a line break. This: +```gleam +[1, 2, 3] |> list.map(int.to_string) +// By putting a newline here I'm telling the formatter to split the pipeline +|> string.join(with: "\n") +``` + +Will turn into this: +```gleam +[1, 2, 3] +|> list.map(int.to_string) +|> string.join(with: "\n") +``` + +Thank you to our formatter wizard [Giacomo Cavalieri](https://github.com/giacomocavalieri) +for this feature! + + +## Improved error messages for `use` expressions + +Gleam's [`use` expressions](https://tour.gleam.run/advanced-features/use-sugar/) +are very powerful and can be used to replicate many built-in features of other +languages such as Go's `defer`, procedural languages' early returns, Haskell's +do-notation, and more. As an unusual and powerful feature they can be confusing +at first, and that was made worse as any type errors from incorrect `use` +expressions would be generic ones rather than being specific to `use`. + +These errors have been greatly refined and we hope this will help folks learning +the language and debugging their code. Here's some specific examples: + +This error message is used when the right-hand-side of `<-` in a `use` +expression is not a function: +```txt +error: Type mismatch + ┌─ /src/one/two.gleam:2:8 + │ +2 │ use <- 123 + │ ^^^ + +In a use expression, there should be a function on the right hand side of +`<-`, but this value has type: + + Int + +See: https://tour.gleam.run/advanced-features/use/ +``` + +This error message is used when the right-hand-side of `<-` is a function, +but it takes no arguments: +```txt +error: Incorrect arity + ┌─ /src/one/two.gleam:3:8 + │ +3 │ use <- func + │ ^^^^ Expected no arguments, got 1 + +The function on the right of `<-` here takes no arguments. +But it has to take at least one argument, a callback function. + +See: https://tour.gleam.run/advanced-features/use/ +``` + +And this one is used when it takes arguments, but not the correct number of +arguments: + ```txt +error: Incorrect arity + ┌─ /src/one/two.gleam:3:8 + │ +3 │ use <- f(1, 2) + │ ^^^^^^^ Expected 2 arguments, got 3 + +The function on the right of `<-` here takes 2 arguments. +All the arguments have already been supplied, so it cannot take the +`use` callback function as a final argument. + +See: https://tour.gleam.run/advanced-features/use/ +``` + +And more! Too many to list here. Thank you to [Giacomo Cavalieri](https://github.com/giacomocavalieri) +for these big improvements! + + +## Type/value mix up feedback + +One common mistake is to try and import a type as a value, or a value as a type. +When an imported item is found not to exist the compiler will now check to see +if there is a matching type or value and explain the mix-up. +```text +error: Unknown module field + ┌─ /src/one/two.gleam:1:19 + │ +1 │ import gleam/one.{One} + │ ^^^ Did you mean `type One`? + +`One` is only a type, it cannot be imported as a value. +``` +```text +error: Unknown module type + ┌─ /src/one/two.gleam:1:19 + │ +1 │ import gleam/two.{type Two} + │ ^^^^^^^^ Did you mean `Two`? + +`Two` is only a value, it cannot be imported as a type. +``` + +Thank you [Pi-Cla](https://github.com/Pi-Cla/) for this feature! + + +## Assertion exhaustiveness checking + +Gleam has a `let assert` syntax to apply a pattern to a value, extracting values +contained within if the pattern matches, and crashing the program if it does +not. + +The compiler now performs exhaustiveness checking on these assertions to find +patterns that are total and warn that the `assert` is redundant as a result. +```text +warning: Redundant assertion + ┌─ /home/lucy/src/app/src/app.gleam:4:7 + │ +4 │ let assert x = get_name() + │ ^^^^^^ You can remove this + +This assertion is redundant since the pattern covers all possibilities. +``` + +Thank you [Giacomo Cavalieri](https://github.com/giacomocavalieri) for this feature. + + +## Catching common crash mistakes + +Gleam has `todo` and `panic` expressions, both of which crash the program due to +it being incomplete or in an invalid state respectively. The syntax looks like +this: +```gleam +panic as "The session is no longer valid, this should never happen!" +``` + +A common mistake is to try and give the message string using the function call +syntax like so: +```gleam +panic("The session is no longer valid, this should never happen!") +``` + +This is valid Gleam code, but it is not using that string as a message for the +panic. The string unreachable as the program panics before it is evaluated. A +compiler warning is now emitted when code like this is found. +```text +warning: Todo used as a function + ┌─ /src/warning/wrn.gleam:2:16 + │ +2 │ todo(1) + │ ^ + +`todo` is not a function and will crash before it can do anything with +this argument. + +Hint: if you want to display an error message you should write +`todo as "my error message"` +See: https://tour.gleam.run/advanced-features/todo/ +``` + +Thank you [Giacomo Cavalieri](https://github.com/giacomocavalieri) for this feature! + + +## Invalid constant error message improvement + +Gleam's constants are limited to a subset of the language that be evaluated at +compile time, and as such arbitrary functions cannot be called within them. +Previously if you tried to call a function you would get a somewhat confusing +parse error, but with this version it'll emit a much more helpful error message. +```text +error: Syntax error + ┌─ /src/parse/error.gleam:3:18 + │ +3 │ const wib: Int = wibble(1, "wobble") + │ ^^^^^^^ Functions can only be called within other functions +``` + +Thank you [Nino Annighoefer](https://github.com/nino) for this improvement! + + +## Unreachable code detection + +Code that comes after a `panic` expression is unreachable and will never be +evaluated as the program will crash before it is reached. The compiler will now +warn in these situations to catch these mistakes. + +For example, this code will emit this warning: + +```gleam +pub fn main() { + panic + my_app.run() +} +``` +```text +warning: Unreachable code + ┌─ /src/warning/wrn.gleam:3:11 + │ +3 │ my_app.run() + │ ^^^^^^^^^^^^ + +This code is unreachable because it comes after a `panic`. +``` + +Thank you [Giacomo Cavalieri](https://github.com/giacomocavalieri) for this feature! + + +## Further Hex integration + +Gleam is part of the Erlang ecosystem, and as such it uses the +[Hex package manager](https://hex.pm). + +The `gleam hex revert` has been added to the Gleam binary. It can be used to +unpublish a package release within the first 24 hours of it being published. +After 24 hours Hex package releases become immutable and cannot be removed. + +Additionally the error message that is emitted when you attempt to publish a +package that has already been published has been improved: +```text +error: Version already published + +Version v1.0.0 has already been published. +This release has been recently published so you can replace it +or you can publish it using a different version number + +Hint: Please add the --replace flag if you want to replace the release. +``` + +Thank you [Pi-Cla](https://github.com/Pi-Cla) for these features! + + +## Erlang module collision prevention + +The Erlang virtual machine supports loading new versions of existing module, +enabling an application to be upgraded while it is still running. One +unfortunate consequence of this is that if you accidentally reuse a module name +loading it into the VM will cause the application to be upgraded to the new +version, causing confusing errors as functions that no longer exist are called +and crash. + +The Gleam build tool would return an error and refuse to compile Gleam modules +that would overwrite each other, but with this version it will also emit an +error if a Gleam module would overwrite a built-in Erlang/OTP module. +```text +error: Erlang module name collision + +The module `src/code.gleam` compiles to an Erlang module named `code`. + +By default Erlang includes a module with the same name so if we were to +compile and load your module it would overwrite the Erlang one, potentially +causing confusing errors and crashes. + +Hint: Rename this module and try again. +``` + +## Better build tool errors + +A helpful error message is now shown if the `manifest.toml` file has become +invalid, perhaps due to a git rebase or accidental edit. +```text +error: Corrupt manifest.toml + +The `manifest.toml` file is corrupt. + +Hint: Please run `gleam update` to fix it. +``` + +Previously when no package versions could be found that satisfy the project's +requirements a very cryptic message would printed that detailed all the +constraints from all the versions that were incompatible. This was overwhelming +and practically impossible to read, so it has been replaced with a much simpler +message. +```text +error: Dependency resolution failed + +An error occurred while determining what dependency packages and +versions should be downloaded. +The error from the version resolver library was: + +Unable to find compatible versions for the version constraints in your +gleam.toml. The conflicting packages are: + +- hellogleam +- lustre_dev_tools +- glint +``` + +Thank you [zahash](https://github.com/zahash) for these improvements! + + +## Redundant pattern matching warnings + +Gleam's case expressons support pattern matching on multiple values at the same +time. This is uncommon so people used to other languages may habitually wrap +multiple values in a tuple or a list to match on them. The compiler will now +warn when this is done: +```text +warning: Redundant list + ┌─ /src/warning/wrn.gleam:2:14 + │ +2 │ case [1, 2] { + │ ^^^^^^ You can remove this list wrapper + +Instead of building a list and matching on it, you can match on its +contents directly. +A case expression can take multiple subjects separated by commas like this: + + case one_subject, another_subject { + _, _ -> todo + } + +See: https://tour.gleam.run/flow-control/multiple-subjects/ +``` + +Thank you [Giacomo Cavalieri](https://github.com/giacomocavalieri) for this feature. + + +## Redundant pattern matching auto-fix + +And further still, if you are using the Gleam language server then a code action +is offered to automatically fix redundant tuple wrappers. Place your cursor on +the tuple and select this language action and the language server will remove +the tuple from the values as well as from all patterns in the case expression. +```gleam +case #(x, y) { + #(1, 2) -> 0 + #(_, _) -> 1 +} +``` +Is rewritten to: +```gleam +case x, y { + 1, 2 -> 0 + _, _ -> 1 +} +``` +Thank you [Nicky Lim](https://github.com/nicklimmm) for this code action, and +for laying the foundation for other code actions like this in future! + + +## A helping hand for JavaScript programmers + +JavaScript programmers sometimes type `===` by mistake in their Gleam code. We +have an error message for that too now: +```text +error: Syntax error + ┌─ /src/parse/error.gleam:4:37 + │ +4 │ [1,2,3] |> list.filter(fn (a) { a === 3 }) + │ ^^^ Did you mean `==`? + +Gleam uses `==` to check for equality between two values. +See: https://tour.gleam.run/basics/equality +``` + +Thank you [Rabin Gaire](https://github.com/rabingaire) for this feature! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +## And the rest + +If you'd like to see all the changes for this release, including all the bug +fixes, check out [the changelog](https://github.com/gleam-lang/gleam/blob/main/changelog/v1.2.md) +in the git repository. + +## Thanks + +Gleam is made possible by the support of all the kind people and companies who have +very generously [**sponsored**](https://github.com/sponsors/lpil) or +contributed to the project. Thank you all! + +If you like Gleam consider sponsoring or asking your employer to +[sponsor Gleam development](https://github.com/sponsors/lpil). I work full time +on Gleam and your kind sponsorship is how I pay my bills! + +Alternatively consider using our [referral link for CodeCrafters](https://app.codecrafters.io/join?via=lpil), +who have recently launched a course on implementing Redis in Gleam. Use your +training budget to learn and to support Gleam too! + +