From 0bd7c693381f4148ebcb4786f23ce9fdcafcf637 Mon Sep 17 00:00:00 2001
From: Anthony Bullard <1380687+gamebox@users.noreply.github.com>
Date: Thu, 7 Mar 2024 05:21:57 -0600
Subject: [PATCH 01/10] Create gleam-for-go-users.md
This is an initial version that is mostly a copy of gleam-for-php-users.md
---
cheatsheets/gleam-for-go-users.md | 7417 +++++++++++++++++++++++++++++
1 file changed, 7417 insertions(+)
create mode 100644 cheatsheets/gleam-for-go-users.md
diff --git a/cheatsheets/gleam-for-go-users.md b/cheatsheets/gleam-for-go-users.md
new file mode 100644
index 00000000..86a299a1
--- /dev/null
+++ b/cheatsheets/gleam-for-go-users.md
@@ -0,0 +1,7417 @@
+---
+layout: page
+title: Gleam for Go users
+subtitle: Hello Gophers!
+---
+
+- [Comments](#comments)
+- [Variables](#variables)
+ - [Match operator](#match-operator)
+ - [Variables type annotations](#variables-type-annotations)
+- [Functions](#functions)
+ - [Exporting functions](#exporting-functions)
+ - [Function type annotations](#function-type-annotations)
+ - [Referencing functions](#referencing-functions)
+ - [Labelled arguments](#labelled-arguments)
+- [Operators](#operators)
+- [Constants](#constants)
+- [Blocks](#blocks)
+- [Data types](#data-types)
+ - [Strings](#strings)
+ - [Tuples](#tuples)
+ - [Lists](#lists)
+ - [Maps](#maps)---
+layout: page
+title: Gleam for Go users
+subtitle: Hello Hypertext crafters!
+---
+
+- [Comments](#comments)
+- [Variables](#variables)
+ - [Match operator](#match-operator)
+ - [Variables type annotations](#variables-type-annotations)
+- [Functions](#functions)
+ - [Exporting functions](#exporting-functions)
+ - [Function type annotations](#function-type-annotations)
+ - [Referencing functions](#referencing-functions)
+ - [Labelled arguments](#labelled-arguments)
+- [Operators](#operators)
+- [Constants](#constants)
+- [Blocks](#blocks)
+- [Data types](#data-types)
+ - [Strings](#strings)
+ - [Tuples](#tuples)
+ - [Lists](#lists)
+ - [Maps](#maps)
+ - [Numbers](#numbers)
+- [Flow control](#flow-control)
+ - [Case](#case)
+ - [Piping](#piping)
+ - [Try](#try)
+- [Type aliases](#type-aliases)
+- [Custom types](#custom-types)
+ - [Records](#records)
+ - [Unions](#unions)
+ - [Opaque custom types](#opaque-custom-types)
+- [Modules](#modules)
+ - [Imports](#imports)
+ - [Named imports](#named-imports)
+ - [Unqualified imports](#unqualified-imports)
+- [Architecture](#architecture)
+
+## Comments
+
+### Go
+
+In Go, comments are written with a `//` prefix.
+
+```Go
+// Hello, Joe!
+```
+
+Multi line comments may be written like so:
+
+```Go
+/*
+ * Hello, Joe!
+ */
+```
+
+IN Go, top level declarations can be annotated with a comment directly above it to create documentation for that symbol.
+
+```Go
+// This is a special interface
+type Foo interface {}
+
+// Bar struct
+type Bar Struct {}
+
+// This will quux a string
+func Quux(str string) string {
+ return str
+}
+```
+
+Any of these documentation comments on exported members will be included in your package documentation
+
+### Gleam
+
+In Gleam, comments are written with a `//` prefix.
+
+```gleam
+// Hello, Joe!
+```
+
+Comments starting with `///` are used to document the following function,
+constant, or type definition. Comments starting with `////` are used to
+document the current module.
+
+```gleam
+//// This module is very important.
+
+/// The answer to life, the universe, and everything.
+const answer: Int = 42
+
+/// A main function
+fn main() {}
+
+/// A Dog type
+type Dog {
+ Dog(name: String, cuteness: Int)
+}
+```
+
+`//` comments are not used while generating documentation files, while
+`////` and `///` will appear in them.
+
+## Variables
+
+You can rebind variables in both languages.
+
+### Go
+
+In Go you specify values by:
+- Specifically declare the variable with the `var` keyboard and a name and then either just the type, or an optional type and value
+- a variable name (or comma separated list of names), the `:=` operator and then an expression
+
+```Go
+size := 50
+size := size + 100
+size = 1
+```
+
+### Gleam
+
+Gleam has the `let` keyword before its variable names.
+
+```gleam
+let size = 50
+let size = size + 100
+let size = 1
+```
+
+### Match operator
+
+#### Go
+
+Go has no real support for any sort of pattern matching or destructuring. It does support multiple return values. These are assigned to
+separated variable names separated by commas
+
+```Go
+a, b := func() (int, int) { return 1, 2 }();
+// a == 1
+// b == 2
+```
+
+#### Gleam
+
+In Gleam, `let` and `=` can be used for pattern matching, but you'll get
+compile errors if there's a type mismatch, and a runtime error if there's
+a value mismatch. For assertions, the equivalent `let assert` keyword is
+preferred.
+
+```gleam
+let #(a, _) = #(1, 2)
+// a = 1
+// `_` matches 2 and is discarded
+
+let assert [] = [1] // runtime error
+let assert [y] = "Hello" // compile error, type mismatch
+```
+
+Asserts should be used with caution.
+
+### Variables type annotations
+
+#### Go
+
+Go is a dynamically typed language. Types are only checked at runtime and
+a variable can have different types in its lifetime.
+
+Go gradually introduced more and more type hints that are optional.
+The type information is accessible via `get_type()` at runtime.
+
+These hints will mainly be used to inform static analysis tools like IDEs,
+linters, etc.
+
+```Go
+class Foo {
+ private ?string $bar;
+}
+```
+
+As Go's `array` structure is a combination of maps and arrays.
+The Go manual states that it is an *ordered map*.
+While creating arrays in Go the type of its elements cannot be set explicitly
+and each element can be of a different type:
+
+```Go
+$someList = [1, 2, 3];
+$someTuple = [1, "a", true];
+$someMap = [0 => 1, "foo" => "bar", true => false];
+```
+
+Single variables cannot be type-annotated unless they are `class` or `trait`
+members.
+
+#### Gleam
+
+In Gleam type annotations can optionally be given when binding variables.
+
+```gleam
+let some_list: List(Int) = [1, 2, 3]
+let some_string: String = "Foo"
+```
+
+Gleam will check the type annotation to ensure that it matches the type of the
+assigned value. It does not need annotations to type check your code, but you
+may find it useful to annotate variables to hint to the compiler that you want
+a specific type to be inferred.
+
+## Functions
+
+### Go
+
+In Go, you can define functions with the `function` keyword. One or many `return`
+keywords are optional.
+
+```Go
+function hello($name = 'Joe') : string
+{
+ if ($name = 'Joe') {
+ return 'Welcome back, Joe!';
+ }
+ return "Hello $name";
+}
+
+function noop()
+{
+ // Will automatically return NULL
+}
+```
+
+Anonymous functions returning a single expression can also be defined and be
+bound to variables.
+
+```Go
+$x = 2
+$GoAnonFn = function($y) use ($x) { return $x * $y; }; // Creates a new scope
+$GoAnonFn(2, 3); // 6
+$GoArrowFn = ($x) => $x * $y; // Inherits the outer scope
+$GoArrowFn(2, 3); // 6
+```
+
+### Gleam
+
+Gleam's functions are declared like so:
+
+```gleam
+fn sum(x, y) {
+ x + y
+}
+```
+
+Gleam's anonymous functions have the same basic syntax.
+
+```gleam
+let mul = fn(x, y) { x * y }
+mul(1, 2)
+```
+
+A difference between Go's and Gleam's anonymous functions is that in Go they
+create a new local scope, in Gleam they close over the local scope, aka create
+a copy and inherit all variables in the scope. This means that in Gleam you can
+shadow local variables within anonymous functions but you cannot influence the
+variable bindings in the outer scope. This is different for Go's arrow
+functions where they inherit the scope like Gleam does.
+
+The only difference between module functions and anonymous functions in Gleam
+is that module functions heads may also feature argument labels, like so:
+
+```gleam
+// In some module.gleam
+pub fn distance(from x: Int, to y: Int) : Int {
+ abs(x) - abs(y) |> abs()
+}
+// In some other function
+distance(from: 1, to: -2) // 3
+```
+
+### Exporting functions
+
+#### Go
+
+In Go, top level functions are exported by default. There is no notion of
+private module-level functions.
+
+However at class level, all properties are public, by default.
+
+```Go
+class Foo {
+ static $bar = 5;
+ private $quux = 6;
+
+ static function batz() {
+ return "Hello Joe!";
+ }
+
+ private static function kek() {
+ return "Hello Rasmus!";
+ }
+}
+echo Foo::$bar; // 5
+echo Foo::$quux; // Error
+echo Foo::batz(); // "Hello Joe"
+echo Foo::kek(); // Error
+```
+
+#### Gleam
+
+In Gleam, functions are private by default and need the `pub` keyword to be
+marked as public.
+
+```gleam
+// this is public
+pub fn sum(x, y) {
+ x + y
+}
+
+// this is private
+fn mul(x, y) {
+ x * y
+}
+```
+
+### Go
+
+Global functions may exist in a global scope, and to execute functions or
+create objects and invoke methods at some point they have to be called from
+the global scope. Usually there is one `index.Go` file whose global scope
+acts as if it was the `main()` function.
+
+### Gleam
+
+Gleam does not support a global scope. Instead Gleam code is either
+representing a library, which can be required as a dependency, and/or it
+represents an application having a main module, whose name must match to the
+application name and within that `main()`-function which will be called via
+either `gleam run` or when the `entrypoint.sh` is executed.
+
+In contrast to Go, where any Go file can contain a global scope that can
+be invoked by requiring the file, in Gleam only code that is within functions
+can be invoked.
+
+On the Beam, Gleam code can also be invoked from other Erlang code, or it
+can be invoked from browser's JavaScript, Deno or NodeJS runtime calls.
+
+### Function type annotations
+
+#### Go
+
+Type hints can be used to optionally annotate function arguments and return
+types.
+
+Discrepancies between type hints and actual values at runtime do not prevent
+interpretation of the code. Static code analysers (IDE tooling, type checkers
+like `Gostan`) will be required to detect those errors.
+
+```Go
+function sum(int $x, int $y) : int {
+ return $x + $y;
+}
+
+function mul(int $x, int $y) : bool {
+ # no errors from the interpreter.
+ return $x * $y;
+}
+```
+
+#### Gleam
+
+Functions can **optionally** have their argument and return types annotated in
+Gleam. These type annotations will always be checked by the compiler and throw
+a compilation error if not valid. The compiler will still type check your
+program using type inference if annotations are omitted.
+
+```gleam
+fn add(x: Int, y: Int) -> Int {
+ x + y
+}
+
+fn mul(x: Int, y: Int) -> Bool {
+ x * y // compile error, type mismatch
+}
+```
+
+### Referencing functions
+
+#### Go
+
+As long as functions are in scope they can be assigned to a new variable.
+As methods or static functions classes, functions can be accessed via
+`$this->object_instance_method()` or `self::static_class_function()`.
+
+Other than that only anonymous functions can be moved around the same way as
+other values.
+
+```Go
+$doubleFn = function($x) { return $x + $x; };
+// Some imaginary pushFunction
+pushFunction($queue, $doubleFn);
+```
+
+However in `Go` it is not possible to pass around global, class or instance
+functions as values.
+
+#### Gleam
+
+Gleam has a single namespace for constants and functions within a module, so
+there is no need for a special syntax to assign a module function to a
+variable.
+
+```gleam
+fn identity(x) {
+ x
+}
+
+fn main() {
+ let func = identity
+ func(100)
+}
+```
+
+### Labelled arguments
+
+Both Go and Gleam have ways to give arguments names and in any order.
+
+#### Go
+
+When calling a function, arguments can be passed:
+
+- positionally, in the same order of the function declaration
+- by name, in any order
+
+```Go
+// Some imaginary replace function
+function replace(string $each, string $with, string $inside) {
+ // TODO implementation
+}
+// Calling with positional arguments:
+replace(",", " ", "A,B,C")
+// Calling with named arguments:
+replace(inside: "A,B,C", each: ",", with: " ")
+```
+
+#### Gleam
+
+In Gleam arguments can be given a label as well as an internal name.
+Contrary to Go, the name used at the call-site does not have to match
+the name used for the variable inside the function.
+
+```gleam
+pub fn replace(inside str, each pattern, with replacement) {
+ todo
+}
+```
+
+```gleam
+replace(",", " ", "A,B,C")
+replace(inside: "A,B,C", each: ",", with: " ")
+```
+
+There is no performance cost to Gleam's labelled arguments as they are
+optimised to regular function calls at compile time, and all the arguments
+are fully type checked.
+
+## Operators
+
+| Operator | Go | Gleam | Notes |
+| ------------------ | ------ | ------------------------- | -------------------------------------------------------------------------------------- |
+| Equal | `==` | `==` | In Gleam both values must be of the same type |
+| Strictly equal to | `===` | `==` | Comparison in Gleam is always strict. (see note for Go) |
+| Reference equality | `instanceof` | | True only if an object is an instance of a class |
+| Not equal | `!=` | `!=` | In Gleam both values must be of the same type |
+| Not equal | `!==` | `!=` | Comparison in Gleam is always strict (see note for Go) |
+| Greater than | `>` | `>` | In Gleam both values must be **Int** |
+| Greater than | `>` | `>.` | In Gleam both values must be **Float** |
+| Greater or equal | `>=` | `>=` | In Gleam both values must be **Int** |
+| Greater or equal | `>=` | `>=.` | In Gleam both values must be **Float** |
+| Less than | `<` | `<` | In Gleam both values must be **Int** |
+| Less than | `<` | `<.` | In Gleam both values must be **Float** |
+| Less or equal | `<=` | `<=` | In Gleam both values must be **Int** |
+| Less or equal | `<=` | `<=.` | In Gleam both values must be **Float** |
+| Boolean and | `&&` | `&&` | In Gleam both values must be **Bool** |
+| Logical and | `&&` | | Not available in Gleam |
+| Boolean or | ||
| ||
| In Gleam both values must be **Bool** |
+| Logical or | ||
| | Not available in Gleam |
+| Boolean not | `xor` | | Not available in Gleam |
+| Boolean not | `!` | `!` | In Gleam both values must be **Bool** |
+| Add | `+` | `+` | In Gleam both values must be **Int** |
+| Add | `+` | `+.` | In Gleam both values must be **Float** |
+| Subtract | `-` | `-` | In Gleam both values must be **Int** |
+| Subtract | `-` | `-.` | In Gleam both values must be **Float** |
+| Multiply | `*` | `*` | In Gleam both values must be **Int** |
+| Multiply | `*` | `*.` | In Gleam both values must be **Float** |
+| Divide | `/` | `/` | In Gleam both values must be **Int** |
+| Divide | `/` | `/.` | In Gleam both values must be **Float** |
+| Remainder | `%` | `%` | In Gleam both values must be **Int** |
+| Concatenate | `.` | `<>` | In Gleam both values must be **String**
+| Pipe | `->` | |>
| Gleam's pipe can chain function calls. See note for Go |
+
+### Notes on operators
+
+- For bitwise operators, which exist in Go but not in Gleam,
+ see: .
+- `==` is by default comparing by value in Go:
+ - Types may be autocast to be compareable.
+ - Two objects with the same members values will equal:
+- `===` is for comparing by strict equality in Go:
+ - Types will not be autocast for comparison
+ - Two objects with the same members will not equal. Only if a variable binds
+ to the same reference it will equal.
+- Go operators are short-circuiting as in Gleam.
+- Chains and pipes:
+ - In Go chaining is usually done by constructing class methods that return
+ an object: `$foo->bar(1)->quux(2)` means `bar(1)` is called as a method
+ of `$foo` and then `quux()` is called as a method of the return value
+ (object) of the `bar(1)` call. The objects in this chain usually
+ mutate to keep the changed state and carry it forward in the chain.
+ - In contrast in Gleam piping, no objects are being returned but mere data
+ is pushed from left to right much like in unix tooling.
+
+## Constants
+
+### Go
+
+In Go, constants can only be defined within classes and traits.
+
+```Go
+class TheQuestion {
+ public const theAnswer = 42;
+}
+echo TheQuestion::theAnswer; // 42
+```
+
+### Gleam
+
+In Gleam constants can be created using the `const` keyword.
+
+```gleam
+// the_question.gleam module
+const the_answer = 42
+
+pub fn main() {
+ the_answer
+}
+```
+
+They can also be marked public via the `pub` keyword and will then be
+automatically exported.
+
+## Blocks
+
+### Go
+
+Go blocks are always associated with a function / conditional / loop or
+similar declaration. Blocks are limited to specific language constructs.
+There is no way to create multi-line expressions blocks like in Gleam.
+
+Blocks are declared via curly braces.
+
+```Go
+function a_func() {
+ // A block starts here
+ if ($foo) {
+ // A block here
+ } else {
+ // A block here
+ }
+ // Block continues
+}
+```
+
+### Gleam
+
+In Gleam curly braces, `{` and `}`, are used to group expressions.
+
+```gleam
+pub fn main() {
+ let x = {
+ some_function(1)
+ 2
+ }
+ // Braces are used to change precedence of arithmetic operators
+ let y = x * {x + 10}
+ y
+}
+```
+
+Unlike in Go, in Gleam function blocks are always expressions, so are `case`
+blocks or arithmetic sub groups. Because they are expressions they always
+return a value.
+
+For Gleam the last value in a block's expression is always the value being
+returned from an expression.
+
+## Data types
+
+### Strings
+
+In Go strings are stored as an array of bytes and an integer indicating the
+length of the buffer. Go itself has no information about how those bytes
+translate to characters, leaving that task to the programmer. Go's
+standard library however features a bunch of multi-byte compatible functions
+and conversion functions between UTF-8, ISO-8859-1 and further encodings.
+
+Go strings allow interpolation.
+
+In Gleam all strings are UTF-8 encoded binaries. Gleam strings do not allow
+interpolation, yet. Gleam however offers a `string_builder` via its standard
+library for performant string building.
+
+#### Go
+
+```Go
+$what = 'world';
+'Hellø, world!';
+"Hellø, ${what}!";
+```
+
+#### Gleam
+
+```gleam
+"Hellø, world!"
+```
+
+### Tuples
+
+Tuples are very useful in Gleam as they're the only collection data type that
+allows mixed types in the collection.
+
+#### Go
+
+Go does not really support tuples, but its array type can easily be used to
+mimick tuples. Unpacking can be used to bind a name to a specific value of
+the tuple.
+
+```Go
+$myTuple = ['username', 'password', 10];
+[$_, $pwd, $_] = $myTuple;
+echo $pwd; // "password"
+// Direct index access
+echo $myTuple[0]; // "username"
+```
+
+#### Gleam
+
+```gleam
+let my_tuple = #("username", "password", 10)
+let #(_, pwd, _) = my_tuple
+io.print(pwd) // "password"
+// Direct index access
+io.print(my_tuple.0) // "username"
+```
+
+### Lists
+
+Arrays in Go are allowed to have values of mixed types, but not in Gleam.
+
+#### Go
+
+Go does not feature special syntax for list handling.
+
+```Go
+$list = [2, 3, 4];
+$head = array_slice($list, 0, 1)[0];
+$tail = array_slice($list, 1);
+# $head == 2
+# $tail == [3, 4]
+$arr = array_merge($tail, [1.1]);
+# $arr == [3, 4, 1.1]
+```
+
+#### Gleam
+
+Gleam has a `cons` operator that works for lists destructuring and
+pattern matching. In Gleam lists are immutable so adding and removing elements
+from the start of a list is highly efficient.
+
+```gleam
+let list = [2, 3, 4]
+let list = [1, ..list]
+let [1, second_element, ..] = list
+[1.0, ..list] // compile error, type mismatch
+```
+
+### Maps
+
+In Go, the `array` type also covers maps and can have keys of any type as long as:
+
+- the key type is `null`, an `int`, a `string` or a `bool` (some conversions
+ occur, such as null to `""` and `false` to `0` as well as `true` to `1`
+ and `"1"` to `1`. Float indexes, which are not representing integers
+ indexes are deprecated due to being auto downcast to integers).
+- the key is unique in the dictionary.
+- the values are of any type.
+
+In Gleam, maps can have keys and values of any type, but all keys must be of
+the same type in a given map and all values must be of the same type in a
+given map. The type of key and value can differ from each other.
+
+There is no map literal syntax in Gleam, and you cannot pattern match on a map.
+Maps are generally not used much in Gleam, custom types are more common.
+
+#### Go
+
+```Go
+["key1" => "value1", "key2" => "value2"]
+["key1" => "1", "key2" => 2]
+```
+
+#### Gleam
+
+```gleam
+import gleam/map
+
+map.from_list([#("key1", "value1"), #("key2", "value2")])
+map.from_list([#("key1", "value1"), #("key2", 2)]) // Type error!
+```
+
+### Numbers
+
+Go and Gleam both support `Integer` and `Float`. Integer and Float sizes for
+both depend on the platform: 64-bit or 32-bit hardware and OS and for Gleam
+JavaScript and Erlang.
+
+#### Go
+
+While Go differentiates between integers and floats it automatically converts
+floats and integers for you, removing precision or adding floating point
+decimals.
+
+```Go
+1 / 2 // 0.5
+```
+
+#### Gleam
+
+```gleam
+1 / 2 // 0
+1.5 + 10 // Compile time error
+```
+
+You can use the gleam standard library's `int` and `float` modules to convert
+between floats and integers in various ways including `rounding`, `floor`,
+`ceiling` and many more.
+
+## Flow control
+
+### Case
+
+Case is one of the most used control flow in Gleam. It can be seen as a switch
+statement on steroids. It provides a terse way to match a value type to an
+expression. It is also used to replace `if`/`else` statements.
+
+#### Go
+
+Go features 3 different expressions to achieve similar goals:
+
+- `if`/`else if`/`else` (does not return)
+- `switch`/`case`/`break`/`default` (does not return, does not autobreak)
+- `match` (returns)
+
+```Go
+function http_error_impl_1($status) {
+ if ($status === 400) {
+ return "Bad request";
+ } else if ($status === 404) {
+ return "Not found";
+ } else if ($status === 418) {
+ return "I'm a teapot";
+ } else {
+ return "Internal Server Error";
+ }
+}
+
+function http_error_impl_2($status) {
+ switch ($status) {
+ case "400": // Will work because switch ($status) compares non-strict as in ==
+ return "Bad request";
+ break; // Not strictly required here, but combined with weak typing multiple cases could be executed if break is omitted
+ case 404:
+ return "Not found";
+ break;
+ case 418:
+ return "I'm a teapot";
+ break;
+ default:
+ return "Internal Server Error";
+ }
+}
+
+function http_error_impl_3($status) {
+ return match($status) { // match($status) compares strictly
+ 400 => "Bad request",
+ 404 => "Not found",
+ 418 => "I'm a teapot",
+ default => "Internal Server Error"
+ };
+}
+```
+
+#### Gleam
+
+The case operator is a top level construct in Gleam:
+
+```gleam
+case some_number {
+ 0 -> "Zero"
+ 1 -> "One"
+ 2 -> "Two"
+ n -> "Some other number" // This matches anything
+}
+```
+
+As all expressions the case expression will return the matched value.
+
+They can be used to mimick if/else or if/elseif/else, with the exception that
+any branch must return unlike in Go, where it is possible to mutate a
+variable of the outer block/scope and not return at all.
+
+```gleam
+let is_status_within_4xx = status / 400 == 1
+case status {
+ 400 -> "Bad Request"
+ 404 -> "Not Found"
+ _ if is_status_within_4xx -> "4xx" // This works as of now
+ // status if status / 400 == 1 -> "4xx" // This will work in future versions of Gleam
+ _ -> "I'm not sure"
+}
+```
+
+if/else example:
+
+```gleam
+case is_admin {
+ True -> "allow access"
+ False -> "disallow access"
+}
+```
+
+if/elseif/else example:
+
+```gleam
+case True {
+ _ if is_admin == True -> "allow access"
+ _ if is_confirmed_by_mail == True -> "allow access"
+ _ -> "deny access"
+}
+```
+
+Exhaustiveness checking at compile time, which is in the works, will make
+certain that you must check for all possible values. A lazy and common way is
+to check of expected values and have a catchall clause with a single underscore
+`_`:
+
+```gleam
+case scale {
+ 0 -> "none"
+ 1 -> "one"
+ 2 -> "pair"
+ _ -> "many"
+}
+```
+
+The case operator especially coupled with destructuring to provide native pattern
+matching:
+
+```gleam
+case xs {
+ [] -> "This list is empty"
+ [a] -> "This list has 1 element"
+ [a, b] -> "This list has 2 elements"
+ _other -> "This list has more than 2 elements"
+}
+```
+
+The case operator supports guards:
+
+```gleam
+case xs {
+ [a, b, c] if a >. b && a <=. c -> "ok"
+ _other -> "ko"
+}
+```
+
+...and disjoint union matching:
+
+```gleam
+case number {
+ 2 | 4 | 6 | 8 -> "This is an even number"
+ 1 | 3 | 5 | 7 -> "This is an odd number"
+ _ -> "I'm not sure"
+}
+```
+
+### Piping
+
+In Gleam most functions, if not all, are data first, which means the main data
+value to work on is the first argument. By this convention and the ability to
+specify the argument to pipe into, Gleam allows writing functional, immutable
+code, that reads imperative-style top down, much like unix tools and piping.
+
+#### Go
+
+Go does not offer pipes but it can chain calls by making functions return
+objects which in turn ship with their list of methods.
+
+```Go
+// Imaginary Go code
+(new Session($request))
+ ->authorize()
+ ->setSuccessFlash('Logged in successfully!')
+ ->setFailureFlash('Failed to login!')
+ ->redirectToRequestedUrl();
+```
+
+#### Gleam
+
+```gleam
+// Imaginary Gleam code
+request
+|> session.new()
+|> session.authorize()
+|> flash.set_success_flash('Logged in successfully!')
+|> flash.set_failure_flash('Failed to login!')
+|> response.redirect_to_requested_url()
+```
+
+Despite being similar to read and comprehend, the Go code creates a session
+object, and calls the authorize method of the session object: That session
+object then returns another object, say an `AuthorizedUser` object - you don't
+know by looking at the code what object gets returned. However you know it must
+implement a `setSuccessFlash` method. At the last step of the chain `redirect`
+is called on an object returned from `setFailureFlash`.
+
+In the Gleam code the request data is piped into `session.new()`'s first
+argument and that return value is piped further down. It is readability sugar
+for:
+
+```gleam
+response.redirect_to_requested_url(
+ flash.set_failure_flash(
+ flash.set_success_flash(
+ session.authorize(
+ session.new(request)
+ ),
+ 'Logged in successfully!'
+ ),
+ 'Failed to login!'
+ )
+)
+```
+
+### Try
+
+Error management is approached differently in Go and Gleam.
+
+#### Go
+
+Go uses the notion of exceptions to interrupt the current code flow and
+pop up the error to the caller.
+
+An exception is raised using the keyword `throw`.
+
+```Go
+function aFunctionThatFails() {
+ throw new RuntimeException('an error');
+}
+```
+
+The callee block will be able to capture any exception raised in the block
+using a `try/except` set of blocks:
+
+```Go
+// callee block
+try {
+ echo 'this line will be executed and thus printed';
+ aFunctionThatFails()
+ echo 'this line will not be executed and thus not printed';
+} catch (Throwable $e) {
+ var_dump(['doing something with the exception', $e]);
+}
+```
+
+#### Gleam
+
+In contrast in gleam, errors are just containers with an associated value.
+
+A common container to model an operation result is
+`Result(ReturnType, ErrorType)`.
+
+A `Result` is either:
+
+- an `Error(ErrorValue)`
+- or an `Ok(Data)` record
+
+Handling errors actually means to match the return value against those two
+scenarios, using a case for instance:
+
+```gleam
+case parse_int("123") {
+ Ok(i) -> io.println("We parsed the Int")
+ Error(e) -> io.println("That wasn't an Int")
+}
+```
+
+In order to simplify this construct, we can use the `try` keyword that will:
+
+- either bind a value to the providing name if `Ok(Something)` is matched,
+- or **interrupt the current block's flow** and return `Error(Something)` from
+ the given block.
+
+```gleam
+let a_number = "1"
+let an_error = Error("ouch")
+let another_number = "3"
+
+try int_a_number = parse_int(a_number)
+try attempt_int = parse_int(an_error) // Error will be returned
+try int_another_number = parse_int(another_number) // never gets executed
+
+Ok(int_a_number + attempt_int + int_another_number) // never gets executed
+```
+
+## Type aliases
+
+Type aliases allow for easy referencing of arbitrary complex types.
+Go does not have this feature, though either regular classes or static classes
+can be used to design custom types and class definitions in take can be aliased
+using `class_alias()`.
+
+### Go
+
+A simple variable can store the result of a compound set of types.
+
+```Go
+static class Point {
+ // Can act as an opaque type and utilize Point
+ // Can be class_aliased to Coordinate
+}
+
+static class Triangle {
+ // Can act as an opaque type definition and utilize Point
+}
+```
+
+### Gleam
+
+The `type` keyword can be used to create aliases.
+
+```gleam
+pub type Headers =
+ List(#(String, String))
+```
+
+## Custom types
+
+### Records
+
+Custom type allows you to define a collection data type with a fixed number of
+named fields, and the values in those fields can be of differing types.
+
+#### Go
+
+Go uses classes to define user-defined, record-like types.
+Properties are defined as class members and initial values are generally set in
+the constructor.
+
+By default the constructor does not provide base initializers in the
+constructor so some boilerplate is needed:
+
+```Go
+class Person {
+ public string $name;
+ public int $age;
+ function __construct(string $name, int $age) {
+ $this->name = $name;
+ $this->age = $age;
+ }
+}
+$person = new Person(name: "Joe", age: 40);
+// $person->name // Joe;
+```
+
+#### Gleam
+
+Gleam's custom types can be used as structs. At runtime, they have a tuple
+representation and are compatible with Erlang records (or JavaScript objects).
+
+```gleam
+type Person {
+ Person(name: String, age: Int)
+}
+
+let person = Person(name: "Joe", age: 40)
+let name = person.name
+```
+
+An important difference to note is there is no Java-style object-orientation in
+Gleam, thus methods can not be added to types. However opaque types exist,
+see below.
+
+### Unions
+
+Go generally does not support unions with a few exceptions such as:
+
+- type x or `null`
+- `Array` or `Traversable`.
+
+In Gleam functions must always take and receive one type. To have a union of
+two different types they must be wrapped in a new custom type.
+
+#### Go
+
+```Go
+class Foo {
+ public ?string $aStringOrNull;
+}
+```
+
+#### Gleam
+
+```gleam
+type IntOrFloat {
+ AnInt(Int)
+ AFloat(Float)
+}
+
+fn int_or_float(X) {
+ case X {
+ True -> AnInt(1)
+ False -> AFloat(1.0)
+ }
+}
+```
+
+### Opaque custom types
+
+In Go, constructors can be marked as private and opaque types can either be
+modelled in an immutable way via static classes or in a mutable way via
+a factory pattern.
+
+In Gleam, custom types can be defined as being opaque, which causes the
+constructors for the custom type not to be exported from the module. Without
+any constructors to import other modules can only interact with opaque types
+using the intended API.
+
+#### Go
+
+```Go
+class PointObject
+{
+ private int $x;
+ private int $y;
+
+ private function __construct(int $x, int $y) {
+ $this->x = $x;
+ $this->y = $y;
+ }
+
+ public static function spawn(int $x, int $y) {
+ if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
+ return new self($x, $y);
+ }
+ return false;
+ }
+}
+PointObject::spawn(1, 2); // Returns a Point object
+```
+
+This requires mutation, but prohibits direct property changes.
+
+Go allows to skip object mutation by using static classes:
+
+```Go
+class PointStruct
+{
+ public static function spawn(int $x, int $y) {
+ if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
+ return compact('x', 'y') + ['struct' => __CLASS__];
+ }
+ return false;
+ }
+}
+PointStruct::spawn(1, 2); // Returns an array managed by PointStruct
+```
+
+However Go will in this case not prohibit the direct alteration the returned
+structure, like Gleam's custom types can.
+
+#### Gleam
+
+```gleam
+// In the point.gleam opaque type module:
+pub opaque type Point {
+ Point(x: Int, y: Int)
+}
+
+pub fn spawn(x: Int, y: Int) -> Result(Point, Nil) {
+ case x >= 0 && x <= 99 && y >= 0 && y <= 99 {
+ True -> Ok(Point(x: x, y: y))
+ False -> Error(Nil)
+ }
+}
+
+// In the main.gleam module
+pub fn main() {
+ assert Ok(point) = Point.spawn(1, 2)
+ point
+}
+```
+
+## Modules
+
+### Go
+
+Go does not feature modules, but many other containers such as classes, traits
+and interfaces. Historically a single file can contain many classes, traits and
+interfaces one after another, though it is best practise to only contain one
+such declaration per file.
+
+Using Go namespaces, these can be placed in a registry that does not need to
+map to the source code file system hierarchy, but by convention should.
+
+In `src/Foo/Bar.Go`:
+
+```Go
+// Anything declared in this file will be inside namespace Foo
+namespace Foo;
+
+// Creation of (static) class Bar in Foo, thus as Foo/Bar
+class Bar {
+ public static function identity($x) {
+ return $x;
+ }
+}
+```
+
+Making the static class available in the local scope and calling the function
+`index.Go` (aka Go's main function):
+
+```Go
+// After auto-loading has happened
+use Foo\Bar;
+
+Bar::identity(1) // 1;
+```
+
+### Gleam
+
+Coming from Go the closest thing Go has that are similar to Gleam's modules
+are static classes: Collections of functions and constants grouped into a
+static class.
+
+In comparison Gleam modules can also contain custom types.
+
+A gleam module name corresponds to its file name and path.
+
+Since there is no special syntax to create a module, there can be only one
+module in a file and since there is no way name the module the filename
+always matches the module name which keeps things simple and transparent.
+
+In `/src/foo/bar.gleam`:
+
+```gleam
+// Creation of module function identity
+// in module bar
+pub fn identity(x) {
+ x
+}
+```
+
+Importing the `bar` module and calling a module function:
+
+```gleam
+// In src/main.gleam
+import foo/bar // if foo was in a directory called `lib` the import would be `lib/foo/bar`.
+
+pub fn main() {
+ bar.identity(1) // 1
+}
+```
+
+### Imports
+
+#### Go
+
+Go features ways to load arbitrary Go code: `require`, `include` and
+autoload such as `spl_autoload_register`. Once class pathes are known and
+registered for autoloading, they can brought into the scope of a file by using
+the `use`statement which is part of Go's namespacing.
+Also see .
+
+Inside `src/Nasa/MoonBase.Go`
+
+```Go
+// Makes available src/nasa/RocketShip.Go
+use Nasa\RocketShip;
+
+class MoonBase {
+ public static function exploreSpace() {
+ RocketShip::launch();
+ }
+}
+```
+
+#### Gleam
+
+Imports are relative to the app `src` folder.
+
+Modules in the same directory will need to reference the entire path from `src`
+for the target module, even if the target module is in the same folder.
+
+Inside module `src/nasa/moon_base.gleam`:
+
+```gleam
+// imports module src/nasa/rocket_ship.gleam
+import nasa/rocket_ship
+
+pub fn explore_space() {
+ rocket_ship.launch()
+}
+```
+
+### Named imports
+
+#### Go
+
+Go features namespaces which can be used to rename classes when they clash:
+
+```Go
+// Source files must first be added to the auto-loader
+use Unix\Cat;
+use Animal\Cat as Kitty;
+// Cat and Kitty are available
+```
+
+#### Gleam
+
+Gleam has as similar feature:
+
+```gleam
+import unix/cat
+import animal/cat as kitty
+// cat and kitty are available
+```
+
+This may be useful to differentiate between multiple modules that would have the same default name when imported.
+
+### Unqualified imports
+
+#### Go
+
+```Go
+use Animal\Cat{
+ Cat,
+ function stroke
+};
+```
+
+```Go
+$kitty = new Cat(name: "Nubi");
+stroke($kitty);
+```
+
+#### Gleam
+
+```gleam
+import animal/cat.{
+ Cat,
+ stroke
+}
+
+pub fn main() {
+ let kitty = Cat(name: "Nubi")
+ stroke(kitty)
+}
+```
+
+Importing common types such as `gleam/order.{Lt, Eq, Gt}` or
+`gleam/option.{Some,None}` can be very helpful.
+
+## Architecture
+
+To iterate a few foundational differences:
+
+1. Programming model: Java-style object-orientation VS functional immutable
+ programming
+2. Guarantees: weak dynamic typing VS strong static typing
+3. Runtime model: request-response script VS Erlang/OTP processes
+4. Error handling: exceptions VS result type
+5. Language reach
+
+### Programming model
+
+- Go mixes imperative, Java-style object-orientation and functional code
+ styles. Gleam offers only functional code style, though it can appear
+ imperative and reads easily thanks to pipes.
+- In Gleam, data structures are never mutated but always updated into new
+ structures. This allows processes that fail to simply restart as there are no
+ mutated objects that can be in an invalid state and take the whole
+ application down (such as in Go, Ruby or Go).
+- Gleam offers syntax to make it easy to extract data out of custom types and
+ update data into new copies of custom types without ever mutating variables.
+ Go sometimes directly mutates references of simple values such as when using
+ `reset()` or `end()` or `array_pop()`.
+- Gleam allows to rebind variables freely to make it easy to update data
+ structures by making a copy and binding it to the existing variable.
+- Go features a massive, powerful but inconsistent standard library that is
+ always loaded and partially extended and deprecated with new Go releases.
+- Gleam allows you to opt into a smaller, well polished and consistent standard
+ library.
+
+### Guarantees and types
+
+- Go features opt-in static typing which is only checked at runtime.
+- Go values tend to be automatically cast for comparison purposes or when used
+ as indexes in arrays. Gleam values are not automatically cast.
+- Go allows comparison between most if not all values, even if it does not
+ make any sense say comparing a file `resource` to a `Date` in terms of order.
+ Gleam's comparison operators are very strict and limited, any other
+ comparisons and conversions must happen via function calls.
+- Go's checks happen at runtime, Gleam's checks (for the most part) do not
+ and rely on the compiler to allow only type safe and sound code to be
+ compiled.
+- Gleam's type inference allows you to be lazy for almost all type definitions.
+ Gleam's type system will always assist you in what types are expected and/or
+ conflicting. Gleam's type system will help you discover APIs.
+
+### Runtime model
+
+- Gleam can run on Erlang/BEAM, on the browser but also Deno or NodeJS.
+- For Gleam on Erlang/BEAM the runtime model has some striking similarities
+ in practise: In Go a script starts and runs. It allocates memory for this
+ script and frees it upon end or after the max execution time is exceeded
+ or the memory limit is exceeded.
+- Gleam on Erlang/BEAM allows to processes requests in a similar isolation
+ level that Go offers in contrast to applications running *Go* or *Ruby*.
+ The level of isoluation means that, very similar to Go, if a process
+ crashes (in Go read: if a request crashes) then the supervision system
+ can restart that process or after a while or amount of tries abort
+ repeating restarts on the process with that given input data. This means
+ Erlang/BEAM will yield similar robustness that Go developers are used
+ to and similar isolation guarantuees.
+- When executing Gleam code in fact its compiled Erlang or JavaScript is
+ executed. So in case there are runtime crashes, the crash log will show
+ Erlang (or browser-console/NodeJS/Deno) debug information. In Gleam
+ applications runtime errors should almost never happen but they are harder
+ to read, in Go applications runtime errors much more often and are easier
+ to read.
+
+### Error handling
+
+- Gleam will catch all errors that are expected to happen via the `Result`
+ type. There can however be other errors, such as miss-behavior due
+ accidental to division by 0, crashes on RAM or storage limits, hardware
+ failures, etc. In these cases on the BEAM there are ways to manage these
+ via BEAM's supervision trees.
+- In contrast Go will use exceptions to handle errors and by doing so blurs
+ the line between expected errors and unexpected errors. Also function
+ signatures are enlarged de-facto by whatever exceptions they can throw
+ and thus function calls and return types become much harder to manage.
+
+### Language reach
+
+- Go is tailored towards web applications, servers, and static to low-dynamic
+ frontends.
+- Gleam can be utilized as a JavaScript replacement to drive your frontend
+ application not just your backend web server.
+- Gleam on Erlang/BEAM can be used to write non-blocking, massively concurrent
+ server applications comparable to RabbitMQ or multiplayer game servers.---
+layout: page
+title: Gleam for Go users
+subtitle: Hello Hypertext crafters!
+---
+
+- [Comments](#comments)
+- [Variables](#variables)
+ - [Match operator](#match-operator)
+ - [Variables type annotations](#variables-type-annotations)
+- [Functions](#functions)
+ - [Exporting functions](#exporting-functions)
+ - [Function type annotations](#function-type-annotations)
+ - [Referencing functions](#referencing-functions)
+ - [Labelled arguments](#labelled-arguments)
+- [Operators](#operators)
+- [Constants](#constants)
+- [Blocks](#blocks)
+- [Data types](#data-types)
+ - [Strings](#strings)
+ - [Tuples](#tuples)
+ - [Lists](#lists)
+ - [Maps](#maps)
+ - [Numbers](#numbers)
+- [Flow control](#flow-control)
+ - [Case](#case)
+ - [Piping](#piping)
+ - [Try](#try)
+- [Type aliases](#type-aliases)
+- [Custom types](#custom-types)
+ - [Records](#records)
+ - [Unions](#unions)
+ - [Opaque custom types](#opaque-custom-types)
+- [Modules](#modules)
+ - [Imports](#imports)
+ - [Named imports](#named-imports)
+ - [Unqualified imports](#unqualified-imports)
+- [Architecture](#architecture)
+
+## Comments
+
+### Go
+
+In Go, comments are written with a `//` prefix.
+
+```Go
+// Hello, Joe!
+```
+
+Multi line comments may be written like so:
+
+```Go
+/*
+ * Hello, Joe!
+ */
+```
+
+IN Go, above `trait`, `interface`, `class`, `member`, `function` declarations
+there can be `docblocks` like so:
+
+```Go
+/**
+ * a very special trait.
+ */
+trait Foo {}
+
+/**
+ * A Bar class
+ */
+class Bar {}
+
+/**
+ * A quux function.
+ *
+ * @var string $str String passed to quux
+ * @return string An unprocessed string
+ */
+function quux(string $str) : string { return $str; }
+```
+
+Documentation blocks (docblocks) are extracted into generated API
+documentation.
+
+### Gleam
+
+In Gleam, comments are written with a `//` prefix.
+
+```gleam
+// Hello, Joe!
+```
+
+Comments starting with `///` are used to document the following function,
+constant, or type definition. Comments starting with `////` are used to
+document the current module.
+
+```gleam
+//// This module is very important.
+
+/// The answer to life, the universe, and everything.
+const answer: Int = 42
+
+/// A main function
+fn main() {}
+
+/// A Dog type
+type Dog {
+ Dog(name: String, cuteness: Int)
+}
+```
+
+`//` comments are not used while generating documentation files, while
+`////` and `///` will appear in them.
+
+## Variables
+
+You can rebind variables in both languages.
+
+### Go
+
+```Go
+$size = 50;
+$size = $size + 100;
+$size = 1;
+```
+
+In local scope Go has no specific variable keyword. You choose a name
+and that's it!
+
+In class scope for property declaration Go uses at least one related
+modifier keyword to create properties such as: `public`, `private`,
+`protected`, `static` or `readonly` (`var` is deprecated).
+
+### Gleam
+
+Gleam has the `let` keyword before its variable names.
+
+```gleam
+let size = 50
+let size = size + 100
+let size = 1
+```
+
+### Match operator
+
+#### Go
+
+Go supports basic, one directional destructuring (also called unpacking).
+Tuple of values can be unpacked and inner values can be assigned to left-hand
+variable names.
+
+```Go
+[$a, $b] = [1, 2];
+// $a == 1
+// $b == 2
+
+[1 => $idx2] = ['foo', 'bar', 'quux'];
+// $idx2 == 'bar'
+
+["profession" => $job] = ['name' => 'Joe', 'profession' => 'hacker'];
+// $job == 'hacker'
+```
+
+#### Gleam
+
+In Gleam, `let` and `=` can be used for pattern matching, but you'll get
+compile errors if there's a type mismatch, and a runtime error if there's
+a value mismatch. For assertions, the equivalent `let assert` keyword is
+preferred.
+
+```gleam
+let #(a, _) = #(1, 2)
+// a = 1
+// `_` matches 2 and is discarded
+
+let assert [] = [1] // runtime error
+let assert [y] = "Hello" // compile error, type mismatch
+```
+
+Asserts should be used with caution.
+
+### Variables type annotations
+
+#### Go
+
+Go is a dynamically typed language. Types are only checked at runtime and
+a variable can have different types in its lifetime.
+
+Go gradually introduced more and more type hints that are optional.
+The type information is accessible via `get_type()` at runtime.
+
+These hints will mainly be used to inform static analysis tools like IDEs,
+linters, etc.
+
+```Go
+class Foo {
+ private ?string $bar;
+}
+```
+
+As Go's `array` structure is a combination of maps and arrays.
+The Go manual states that it is an *ordered map*.
+While creating arrays in Go the type of its elements cannot be set explicitly
+and each element can be of a different type:
+
+```Go
+$someList = [1, 2, 3];
+$someTuple = [1, "a", true];
+$someMap = [0 => 1, "foo" => "bar", true => false];
+```
+
+Single variables cannot be type-annotated unless they are `class` or `trait`
+members.
+
+#### Gleam
+
+In Gleam type annotations can optionally be given when binding variables.
+
+```gleam
+let some_list: List(Int) = [1, 2, 3]
+let some_string: String = "Foo"
+```
+
+Gleam will check the type annotation to ensure that it matches the type of the
+assigned value. It does not need annotations to type check your code, but you
+may find it useful to annotate variables to hint to the compiler that you want
+a specific type to be inferred.
+
+## Functions
+
+### Go
+
+In Go, you can define functions with the `function` keyword. One or many `return`
+keywords are optional.
+
+```Go
+function hello($name = 'Joe') : string
+{
+ if ($name = 'Joe') {
+ return 'Welcome back, Joe!';
+ }
+ return "Hello $name";
+}
+
+function noop()
+{
+ // Will automatically return NULL
+}
+```
+
+Anonymous functions returning a single expression can also be defined and be
+bound to variables.
+
+```Go
+$x = 2
+$GoAnonFn = function($y) use ($x) { return $x * $y; }; // Creates a new scope
+$GoAnonFn(2, 3); // 6
+$GoArrowFn = ($x) => $x * $y; // Inherits the outer scope
+$GoArrowFn(2, 3); // 6
+```
+
+### Gleam
+
+Gleam's functions are declared like so:
+
+```gleam
+fn sum(x, y) {
+ x + y
+}
+```
+
+Gleam's anonymous functions have the same basic syntax.
+
+```gleam
+let mul = fn(x, y) { x * y }
+mul(1, 2)
+```
+
+A difference between Go's and Gleam's anonymous functions is that in Go they
+create a new local scope, in Gleam they close over the local scope, aka create
+a copy and inherit all variables in the scope. This means that in Gleam you can
+shadow local variables within anonymous functions but you cannot influence the
+variable bindings in the outer scope. This is different for Go's arrow
+functions where they inherit the scope like Gleam does.
+
+The only difference between module functions and anonymous functions in Gleam
+is that module functions heads may also feature argument labels, like so:
+
+```gleam
+// In some module.gleam
+pub fn distance(from x: Int, to y: Int) : Int {
+ abs(x) - abs(y) |> abs()
+}
+// In some other function
+distance(from: 1, to: -2) // 3
+```
+
+### Exporting functions
+
+#### Go
+
+In Go, top level functions are exported by default. There is no notion of
+private module-level functions.
+
+However at class level, all properties are public, by default.
+
+```Go
+class Foo {
+ static $bar = 5;
+ private $quux = 6;
+
+ static function batz() {
+ return "Hello Joe!";
+ }
+
+ private static function kek() {
+ return "Hello Rasmus!";
+ }
+}
+echo Foo::$bar; // 5
+echo Foo::$quux; // Error
+echo Foo::batz(); // "Hello Joe"
+echo Foo::kek(); // Error
+```
+
+#### Gleam
+
+In Gleam, functions are private by default and need the `pub` keyword to be
+marked as public.
+
+```gleam
+// this is public
+pub fn sum(x, y) {
+ x + y
+}
+
+// this is private
+fn mul(x, y) {
+ x * y
+}
+```
+
+### Go
+
+Global functions may exist in a global scope, and to execute functions or
+create objects and invoke methods at some point they have to be called from
+the global scope. Usually there is one `index.Go` file whose global scope
+acts as if it was the `main()` function.
+
+### Gleam
+
+Gleam does not support a global scope. Instead Gleam code is either
+representing a library, which can be required as a dependency, and/or it
+represents an application having a main module, whose name must match to the
+application name and within that `main()`-function which will be called via
+either `gleam run` or when the `entrypoint.sh` is executed.
+
+In contrast to Go, where any Go file can contain a global scope that can
+be invoked by requiring the file, in Gleam only code that is within functions
+can be invoked.
+
+On the Beam, Gleam code can also be invoked from other Erlang code, or it
+can be invoked from browser's JavaScript, Deno or NodeJS runtime calls.
+
+### Function type annotations
+
+#### Go
+
+Type hints can be used to optionally annotate function arguments and return
+types.
+
+Discrepancies between type hints and actual values at runtime do not prevent
+interpretation of the code. Static code analysers (IDE tooling, type checkers
+like `Gostan`) will be required to detect those errors.
+
+```Go
+function sum(int $x, int $y) : int {
+ return $x + $y;
+}
+
+function mul(int $x, int $y) : bool {
+ # no errors from the interpreter.
+ return $x * $y;
+}
+```
+
+#### Gleam
+
+Functions can **optionally** have their argument and return types annotated in
+Gleam. These type annotations will always be checked by the compiler and throw
+a compilation error if not valid. The compiler will still type check your
+program using type inference if annotations are omitted.
+
+```gleam
+fn add(x: Int, y: Int) -> Int {
+ x + y
+}
+
+fn mul(x: Int, y: Int) -> Bool {
+ x * y // compile error, type mismatch
+}
+```
+
+### Referencing functions
+
+#### Go
+
+As long as functions are in scope they can be assigned to a new variable.
+As methods or static functions classes, functions can be accessed via
+`$this->object_instance_method()` or `self::static_class_function()`.
+
+Other than that only anonymous functions can be moved around the same way as
+other values.
+
+```Go
+$doubleFn = function($x) { return $x + $x; };
+// Some imaginary pushFunction
+pushFunction($queue, $doubleFn);
+```
+
+However in `Go` it is not possible to pass around global, class or instance
+functions as values.
+
+#### Gleam
+
+Gleam has a single namespace for constants and functions within a module, so
+there is no need for a special syntax to assign a module function to a
+variable.
+
+```gleam
+fn identity(x) {
+ x
+}
+
+fn main() {
+ let func = identity
+ func(100)
+}
+```
+
+### Labelled arguments
+
+Both Go and Gleam have ways to give arguments names and in any order.
+
+#### Go
+
+When calling a function, arguments can be passed:
+
+- positionally, in the same order of the function declaration
+- by name, in any order
+
+```Go
+// Some imaginary replace function
+function replace(string $each, string $with, string $inside) {
+ // TODO implementation
+}
+// Calling with positional arguments:
+replace(",", " ", "A,B,C")
+// Calling with named arguments:
+replace(inside: "A,B,C", each: ",", with: " ")
+```
+
+#### Gleam
+
+In Gleam arguments can be given a label as well as an internal name.
+Contrary to Go, the name used at the call-site does not have to match
+the name used for the variable inside the function.
+
+```gleam
+pub fn replace(inside str, each pattern, with replacement) {
+ todo
+}
+```
+
+```gleam
+replace(",", " ", "A,B,C")
+replace(inside: "A,B,C", each: ",", with: " ")
+```
+
+There is no performance cost to Gleam's labelled arguments as they are
+optimised to regular function calls at compile time, and all the arguments
+are fully type checked.
+
+## Operators
+
+| Operator | Go | Gleam | Notes |
+| ------------------ | ------ | ------------------------- | -------------------------------------------------------------------------------------- |
+| Equal | `==` | `==` | In Gleam both values must be of the same type |
+| Strictly equal to | `===` | `==` | Comparison in Gleam is always strict. (see note for Go) |
+| Reference equality | `instanceof` | | True only if an object is an instance of a class |
+| Not equal | `!=` | `!=` | In Gleam both values must be of the same type |
+| Not equal | `!==` | `!=` | Comparison in Gleam is always strict (see note for Go) |
+| Greater than | `>` | `>` | In Gleam both values must be **Int** |
+| Greater than | `>` | `>.` | In Gleam both values must be **Float** |
+| Greater or equal | `>=` | `>=` | In Gleam both values must be **Int** |
+| Greater or equal | `>=` | `>=.` | In Gleam both values must be **Float** |
+| Less than | `<` | `<` | In Gleam both values must be **Int** |
+| Less than | `<` | `<.` | In Gleam both values must be **Float** |
+| Less or equal | `<=` | `<=` | In Gleam both values must be **Int** |
+| Less or equal | `<=` | `<=.` | In Gleam both values must be **Float** |
+| Boolean and | `&&` | `&&` | In Gleam both values must be **Bool** |
+| Logical and | `&&` | | Not available in Gleam |
+| Boolean or | ||
| ||
| In Gleam both values must be **Bool** |
+| Logical or | ||
| | Not available in Gleam |
+| Boolean not | `xor` | | Not available in Gleam |
+| Boolean not | `!` | `!` | In Gleam both values must be **Bool** |
+| Add | `+` | `+` | In Gleam both values must be **Int** |
+| Add | `+` | `+.` | In Gleam both values must be **Float** |
+| Subtract | `-` | `-` | In Gleam both values must be **Int** |
+| Subtract | `-` | `-.` | In Gleam both values must be **Float** |
+| Multiply | `*` | `*` | In Gleam both values must be **Int** |
+| Multiply | `*` | `*.` | In Gleam both values must be **Float** |
+| Divide | `/` | `/` | In Gleam both values must be **Int** |
+| Divide | `/` | `/.` | In Gleam both values must be **Float** |
+| Remainder | `%` | `%` | In Gleam both values must be **Int** |
+| Concatenate | `.` | `<>` | In Gleam both values must be **String**
+| Pipe | `->` | |>
| Gleam's pipe can chain function calls. See note for Go |
+
+### Notes on operators
+
+- For bitwise operators, which exist in Go but not in Gleam,
+ see: .
+- `==` is by default comparing by value in Go:
+ - Types may be autocast to be compareable.
+ - Two objects with the same members values will equal:
+- `===` is for comparing by strict equality in Go:
+ - Types will not be autocast for comparison
+ - Two objects with the same members will not equal. Only if a variable binds
+ to the same reference it will equal.
+- Go operators are short-circuiting as in Gleam.
+- Chains and pipes:
+ - In Go chaining is usually done by constructing class methods that return
+ an object: `$foo->bar(1)->quux(2)` means `bar(1)` is called as a method
+ of `$foo` and then `quux()` is called as a method of the return value
+ (object) of the `bar(1)` call. The objects in this chain usually
+ mutate to keep the changed state and carry it forward in the chain.
+ - In contrast in Gleam piping, no objects are being returned but mere data
+ is pushed from left to right much like in unix tooling.
+
+## Constants
+
+### Go
+
+In Go, constants can only be defined within classes and traits.
+
+```Go
+class TheQuestion {
+ public const theAnswer = 42;
+}
+echo TheQuestion::theAnswer; // 42
+```
+
+### Gleam
+
+In Gleam constants can be created using the `const` keyword.
+
+```gleam
+// the_question.gleam module
+const the_answer = 42
+
+pub fn main() {
+ the_answer
+}
+```
+
+They can also be marked public via the `pub` keyword and will then be
+automatically exported.
+
+## Blocks
+
+### Go
+
+Go blocks are always associated with a function / conditional / loop or
+similar declaration. Blocks are limited to specific language constructs.
+There is no way to create multi-line expressions blocks like in Gleam.
+
+Blocks are declared via curly braces.
+
+```Go
+function a_func() {
+ // A block starts here
+ if ($foo) {
+ // A block here
+ } else {
+ // A block here
+ }
+ // Block continues
+}
+```
+
+### Gleam
+
+In Gleam curly braces, `{` and `}`, are used to group expressions.
+
+```gleam
+pub fn main() {
+ let x = {
+ some_function(1)
+ 2
+ }
+ // Braces are used to change precedence of arithmetic operators
+ let y = x * {x + 10}
+ y
+}
+```
+
+Unlike in Go, in Gleam function blocks are always expressions, so are `case`
+blocks or arithmetic sub groups. Because they are expressions they always
+return a value.
+
+For Gleam the last value in a block's expression is always the value being
+returned from an expression.
+
+## Data types
+
+### Strings
+
+In Go strings are stored as an array of bytes and an integer indicating the
+length of the buffer. Go itself has no information about how those bytes
+translate to characters, leaving that task to the programmer. Go's
+standard library however features a bunch of multi-byte compatible functions
+and conversion functions between UTF-8, ISO-8859-1 and further encodings.
+
+Go strings allow interpolation.
+
+In Gleam all strings are UTF-8 encoded binaries. Gleam strings do not allow
+interpolation, yet. Gleam however offers a `string_builder` via its standard
+library for performant string building.
+
+#### Go
+
+```Go
+$what = 'world';
+'Hellø, world!';
+"Hellø, ${what}!";
+```
+
+#### Gleam
+
+```gleam
+"Hellø, world!"
+```
+
+### Tuples
+
+Tuples are very useful in Gleam as they're the only collection data type that
+allows mixed types in the collection.
+
+#### Go
+
+Go does not really support tuples, but its array type can easily be used to
+mimick tuples. Unpacking can be used to bind a name to a specific value of
+the tuple.
+
+```Go
+$myTuple = ['username', 'password', 10];
+[$_, $pwd, $_] = $myTuple;
+echo $pwd; // "password"
+// Direct index access
+echo $myTuple[0]; // "username"
+```
+
+#### Gleam
+
+```gleam
+let my_tuple = #("username", "password", 10)
+let #(_, pwd, _) = my_tuple
+io.print(pwd) // "password"
+// Direct index access
+io.print(my_tuple.0) // "username"
+```
+
+### Lists
+
+Arrays in Go are allowed to have values of mixed types, but not in Gleam.
+
+#### Go
+
+Go does not feature special syntax for list handling.
+
+```Go
+$list = [2, 3, 4];
+$head = array_slice($list, 0, 1)[0];
+$tail = array_slice($list, 1);
+# $head == 2
+# $tail == [3, 4]
+$arr = array_merge($tail, [1.1]);
+# $arr == [3, 4, 1.1]
+```
+
+#### Gleam
+
+Gleam has a `cons` operator that works for lists destructuring and
+pattern matching. In Gleam lists are immutable so adding and removing elements
+from the start of a list is highly efficient.
+
+```gleam
+let list = [2, 3, 4]
+let list = [1, ..list]
+let [1, second_element, ..] = list
+[1.0, ..list] // compile error, type mismatch
+```
+
+### Maps
+
+In Go, the `array` type also covers maps and can have keys of any type as long as:
+
+- the key type is `null`, an `int`, a `string` or a `bool` (some conversions
+ occur, such as null to `""` and `false` to `0` as well as `true` to `1`
+ and `"1"` to `1`. Float indexes, which are not representing integers
+ indexes are deprecated due to being auto downcast to integers).
+- the key is unique in the dictionary.
+- the values are of any type.
+
+In Gleam, maps can have keys and values of any type, but all keys must be of
+the same type in a given map and all values must be of the same type in a
+given map. The type of key and value can differ from each other.
+
+There is no map literal syntax in Gleam, and you cannot pattern match on a map.
+Maps are generally not used much in Gleam, custom types are more common.
+
+#### Go
+
+```Go
+["key1" => "value1", "key2" => "value2"]
+["key1" => "1", "key2" => 2]
+```
+
+#### Gleam
+
+```gleam
+import gleam/map
+
+map.from_list([#("key1", "value1"), #("key2", "value2")])
+map.from_list([#("key1", "value1"), #("key2", 2)]) // Type error!
+```
+
+### Numbers
+
+Go and Gleam both support `Integer` and `Float`. Integer and Float sizes for
+both depend on the platform: 64-bit or 32-bit hardware and OS and for Gleam
+JavaScript and Erlang.
+
+#### Go
+
+While Go differentiates between integers and floats it automatically converts
+floats and integers for you, removing precision or adding floating point
+decimals.
+
+```Go
+1 / 2 // 0.5
+```
+
+#### Gleam
+
+```gleam
+1 / 2 // 0
+1.5 + 10 // Compile time error
+```
+
+You can use the gleam standard library's `int` and `float` modules to convert
+between floats and integers in various ways including `rounding`, `floor`,
+`ceiling` and many more.
+
+## Flow control
+
+### Case
+
+Case is one of the most used control flow in Gleam. It can be seen as a switch
+statement on steroids. It provides a terse way to match a value type to an
+expression. It is also used to replace `if`/`else` statements.
+
+#### Go
+
+Go features 3 different expressions to achieve similar goals:
+
+- `if`/`else if`/`else` (does not return)
+- `switch`/`case`/`break`/`default` (does not return, does not autobreak)
+- `match` (returns)
+
+```Go
+function http_error_impl_1($status) {
+ if ($status === 400) {
+ return "Bad request";
+ } else if ($status === 404) {
+ return "Not found";
+ } else if ($status === 418) {
+ return "I'm a teapot";
+ } else {
+ return "Internal Server Error";
+ }
+}
+
+function http_error_impl_2($status) {
+ switch ($status) {
+ case "400": // Will work because switch ($status) compares non-strict as in ==
+ return "Bad request";
+ break; // Not strictly required here, but combined with weak typing multiple cases could be executed if break is omitted
+ case 404:
+ return "Not found";
+ break;
+ case 418:
+ return "I'm a teapot";
+ break;
+ default:
+ return "Internal Server Error";
+ }
+}
+
+function http_error_impl_3($status) {
+ return match($status) { // match($status) compares strictly
+ 400 => "Bad request",
+ 404 => "Not found",
+ 418 => "I'm a teapot",
+ default => "Internal Server Error"
+ };
+}
+```
+
+#### Gleam
+
+The case operator is a top level construct in Gleam:
+
+```gleam
+case some_number {
+ 0 -> "Zero"
+ 1 -> "One"
+ 2 -> "Two"
+ n -> "Some other number" // This matches anything
+}
+```
+
+As all expressions the case expression will return the matched value.
+
+They can be used to mimick if/else or if/elseif/else, with the exception that
+any branch must return unlike in Go, where it is possible to mutate a
+variable of the outer block/scope and not return at all.
+
+```gleam
+let is_status_within_4xx = status / 400 == 1
+case status {
+ 400 -> "Bad Request"
+ 404 -> "Not Found"
+ _ if is_status_within_4xx -> "4xx" // This works as of now
+ // status if status / 400 == 1 -> "4xx" // This will work in future versions of Gleam
+ _ -> "I'm not sure"
+}
+```
+
+if/else example:
+
+```gleam
+case is_admin {
+ True -> "allow access"
+ False -> "disallow access"
+}
+```
+
+if/elseif/else example:
+
+```gleam
+case True {
+ _ if is_admin == True -> "allow access"
+ _ if is_confirmed_by_mail == True -> "allow access"
+ _ -> "deny access"
+}
+```
+
+Exhaustiveness checking at compile time, which is in the works, will make
+certain that you must check for all possible values. A lazy and common way is
+to check of expected values and have a catchall clause with a single underscore
+`_`:
+
+```gleam
+case scale {
+ 0 -> "none"
+ 1 -> "one"
+ 2 -> "pair"
+ _ -> "many"
+}
+```
+
+The case operator especially coupled with destructuring to provide native pattern
+matching:
+
+```gleam
+case xs {
+ [] -> "This list is empty"
+ [a] -> "This list has 1 element"
+ [a, b] -> "This list has 2 elements"
+ _other -> "This list has more than 2 elements"
+}
+```
+
+The case operator supports guards:
+
+```gleam
+case xs {
+ [a, b, c] if a >. b && a <=. c -> "ok"
+ _other -> "ko"
+}
+```
+
+...and disjoint union matching:
+
+```gleam
+case number {
+ 2 | 4 | 6 | 8 -> "This is an even number"
+ 1 | 3 | 5 | 7 -> "This is an odd number"
+ _ -> "I'm not sure"
+}
+```
+
+### Piping
+
+In Gleam most functions, if not all, are data first, which means the main data
+value to work on is the first argument. By this convention and the ability to
+specify the argument to pipe into, Gleam allows writing functional, immutable
+code, that reads imperative-style top down, much like unix tools and piping.
+
+#### Go
+
+Go does not offer pipes but it can chain calls by making functions return
+objects which in turn ship with their list of methods.
+
+```Go
+// Imaginary Go code
+(new Session($request))
+ ->authorize()
+ ->setSuccessFlash('Logged in successfully!')
+ ->setFailureFlash('Failed to login!')
+ ->redirectToRequestedUrl();
+```
+
+#### Gleam
+
+```gleam
+// Imaginary Gleam code
+request
+|> session.new()
+|> session.authorize()
+|> flash.set_success_flash('Logged in successfully!')
+|> flash.set_failure_flash('Failed to login!')
+|> response.redirect_to_requested_url()
+```
+
+Despite being similar to read and comprehend, the Go code creates a session
+object, and calls the authorize method of the session object: That session
+object then returns another object, say an `AuthorizedUser` object - you don't
+know by looking at the code what object gets returned. However you know it must
+implement a `setSuccessFlash` method. At the last step of the chain `redirect`
+is called on an object returned from `setFailureFlash`.
+
+In the Gleam code the request data is piped into `session.new()`'s first
+argument and that return value is piped further down. It is readability sugar
+for:
+
+```gleam
+response.redirect_to_requested_url(
+ flash.set_failure_flash(
+ flash.set_success_flash(
+ session.authorize(
+ session.new(request)
+ ),
+ 'Logged in successfully!'
+ ),
+ 'Failed to login!'
+ )
+)
+```
+
+### Try
+
+Error management is approached differently in Go and Gleam.
+
+#### Go
+
+Go uses the notion of exceptions to interrupt the current code flow and
+pop up the error to the caller.
+
+An exception is raised using the keyword `throw`.
+
+```Go
+function aFunctionThatFails() {
+ throw new RuntimeException('an error');
+}
+```
+
+The callee block will be able to capture any exception raised in the block
+using a `try/except` set of blocks:
+
+```Go
+// callee block
+try {
+ echo 'this line will be executed and thus printed';
+ aFunctionThatFails()
+ echo 'this line will not be executed and thus not printed';
+} catch (Throwable $e) {
+ var_dump(['doing something with the exception', $e]);
+}
+```
+
+#### Gleam
+
+In contrast in gleam, errors are just containers with an associated value.
+
+A common container to model an operation result is
+`Result(ReturnType, ErrorType)`.
+
+A `Result` is either:
+
+- an `Error(ErrorValue)`
+- or an `Ok(Data)` record
+
+Handling errors actually means to match the return value against those two
+scenarios, using a case for instance:
+
+```gleam
+case parse_int("123") {
+ Ok(i) -> io.println("We parsed the Int")
+ Error(e) -> io.println("That wasn't an Int")
+}
+```
+
+In order to simplify this construct, we can use the `try` keyword that will:
+
+- either bind a value to the providing name if `Ok(Something)` is matched,
+- or **interrupt the current block's flow** and return `Error(Something)` from
+ the given block.
+
+```gleam
+let a_number = "1"
+let an_error = Error("ouch")
+let another_number = "3"
+
+try int_a_number = parse_int(a_number)
+try attempt_int = parse_int(an_error) // Error will be returned
+try int_another_number = parse_int(another_number) // never gets executed
+
+Ok(int_a_number + attempt_int + int_another_number) // never gets executed
+```
+
+## Type aliases
+
+Type aliases allow for easy referencing of arbitrary complex types.
+Go does not have this feature, though either regular classes or static classes
+can be used to design custom types and class definitions in take can be aliased
+using `class_alias()`.
+
+### Go
+
+A simple variable can store the result of a compound set of types.
+
+```Go
+static class Point {
+ // Can act as an opaque type and utilize Point
+ // Can be class_aliased to Coordinate
+}
+
+static class Triangle {
+ // Can act as an opaque type definition and utilize Point
+}
+```
+
+### Gleam
+
+The `type` keyword can be used to create aliases.
+
+```gleam
+pub type Headers =
+ List(#(String, String))
+```
+
+## Custom types
+
+### Records
+
+Custom type allows you to define a collection data type with a fixed number of
+named fields, and the values in those fields can be of differing types.
+
+#### Go
+
+Go uses classes to define user-defined, record-like types.
+Properties are defined as class members and initial values are generally set in
+the constructor.
+
+By default the constructor does not provide base initializers in the
+constructor so some boilerplate is needed:
+
+```Go
+class Person {
+ public string $name;
+ public int $age;
+ function __construct(string $name, int $age) {
+ $this->name = $name;
+ $this->age = $age;
+ }
+}
+$person = new Person(name: "Joe", age: 40);
+// $person->name // Joe;
+```
+
+#### Gleam
+
+Gleam's custom types can be used as structs. At runtime, they have a tuple
+representation and are compatible with Erlang records (or JavaScript objects).
+
+```gleam
+type Person {
+ Person(name: String, age: Int)
+}
+
+let person = Person(name: "Joe", age: 40)
+let name = person.name
+```
+
+An important difference to note is there is no Java-style object-orientation in
+Gleam, thus methods can not be added to types. However opaque types exist,
+see below.
+
+### Unions
+
+Go generally does not support unions with a few exceptions such as:
+
+- type x or `null`
+- `Array` or `Traversable`.
+
+In Gleam functions must always take and receive one type. To have a union of
+two different types they must be wrapped in a new custom type.
+
+#### Go
+
+```Go
+class Foo {
+ public ?string $aStringOrNull;
+}
+```
+
+#### Gleam
+
+```gleam
+type IntOrFloat {
+ AnInt(Int)
+ AFloat(Float)
+}
+
+fn int_or_float(X) {
+ case X {
+ True -> AnInt(1)
+ False -> AFloat(1.0)
+ }
+}
+```
+
+### Opaque custom types
+
+In Go, constructors can be marked as private and opaque types can either be
+modelled in an immutable way via static classes or in a mutable way via
+a factory pattern.
+
+In Gleam, custom types can be defined as being opaque, which causes the
+constructors for the custom type not to be exported from the module. Without
+any constructors to import other modules can only interact with opaque types
+using the intended API.
+
+#### Go
+
+```Go
+class PointObject
+{
+ private int $x;
+ private int $y;
+
+ private function __construct(int $x, int $y) {
+ $this->x = $x;
+ $this->y = $y;
+ }
+
+ public static function spawn(int $x, int $y) {
+ if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
+ return new self($x, $y);
+ }
+ return false;
+ }
+}
+PointObject::spawn(1, 2); // Returns a Point object
+```
+
+This requires mutation, but prohibits direct property changes.
+
+Go allows to skip object mutation by using static classes:
+
+```Go
+class PointStruct
+{
+ public static function spawn(int $x, int $y) {
+ if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
+ return compact('x', 'y') + ['struct' => __CLASS__];
+ }
+ return false;
+ }
+}
+PointStruct::spawn(1, 2); // Returns an array managed by PointStruct
+```
+
+However Go will in this case not prohibit the direct alteration the returned
+structure, like Gleam's custom types can.
+
+#### Gleam
+
+```gleam
+// In the point.gleam opaque type module:
+pub opaque type Point {
+ Point(x: Int, y: Int)
+}
+
+pub fn spawn(x: Int, y: Int) -> Result(Point, Nil) {
+ case x >= 0 && x <= 99 && y >= 0 && y <= 99 {
+ True -> Ok(Point(x: x, y: y))
+ False -> Error(Nil)
+ }
+}
+
+// In the main.gleam module
+pub fn main() {
+ assert Ok(point) = Point.spawn(1, 2)
+ point
+}
+```
+
+## Modules
+
+### Go
+
+Go does not feature modules, but many other containers such as classes, traits
+and interfaces. Historically a single file can contain many classes, traits and
+interfaces one after another, though it is best practise to only contain one
+such declaration per file.
+
+Using Go namespaces, these can be placed in a registry that does not need to
+map to the source code file system hierarchy, but by convention should.
+
+In `src/Foo/Bar.Go`:
+
+```Go
+// Anything declared in this file will be inside namespace Foo
+namespace Foo;
+
+// Creation of (static) class Bar in Foo, thus as Foo/Bar
+class Bar {
+ public static function identity($x) {
+ return $x;
+ }
+}
+```
+
+Making the static class available in the local scope and calling the function
+`index.Go` (aka Go's main function):
+
+```Go
+// After auto-loading has happened
+use Foo\Bar;
+
+Bar::identity(1) // 1;
+```
+
+### Gleam
+
+Coming from Go the closest thing Go has that are similar to Gleam's modules
+are static classes: Collections of functions and constants grouped into a
+static class.
+
+In comparison Gleam modules can also contain custom types.
+
+A gleam module name corresponds to its file name and path.
+
+Since there is no special syntax to create a module, there can be only one
+module in a file and since there is no way name the module the filename
+always matches the module name which keeps things simple and transparent.
+
+In `/src/foo/bar.gleam`:
+
+```gleam
+// Creation of module function identity
+// in module bar
+pub fn identity(x) {
+ x
+}
+```
+
+Importing the `bar` module and calling a module function:
+
+```gleam
+// In src/main.gleam
+import foo/bar // if foo was in a directory called `lib` the import would be `lib/foo/bar`.
+
+pub fn main() {
+ bar.identity(1) // 1
+}
+```
+
+### Imports
+
+#### Go
+
+Go features ways to load arbitrary Go code: `require`, `include` and
+autoload such as `spl_autoload_register`. Once class pathes are known and
+registered for autoloading, they can brought into the scope of a file by using
+the `use`statement which is part of Go's namespacing.
+Also see .
+
+Inside `src/Nasa/MoonBase.Go`
+
+```Go
+// Makes available src/nasa/RocketShip.Go
+use Nasa\RocketShip;
+
+class MoonBase {
+ public static function exploreSpace() {
+ RocketShip::launch();
+ }
+}
+```
+
+#### Gleam
+
+Imports are relative to the app `src` folder.
+
+Modules in the same directory will need to reference the entire path from `src`
+for the target module, even if the target module is in the same folder.
+
+Inside module `src/nasa/moon_base.gleam`:
+
+```gleam
+// imports module src/nasa/rocket_ship.gleam
+import nasa/rocket_ship
+
+pub fn explore_space() {
+ rocket_ship.launch()
+}
+```
+
+### Named imports
+
+#### Go
+
+Go features namespaces which can be used to rename classes when they clash:
+
+```Go
+// Source files must first be added to the auto-loader
+use Unix\Cat;
+use Animal\Cat as Kitty;
+// Cat and Kitty are available
+```
+
+#### Gleam
+
+Gleam has as similar feature:
+
+```gleam
+import unix/cat
+import animal/cat as kitty
+// cat and kitty are available
+```
+
+This may be useful to differentiate between multiple modules that would have the same default name when imported.
+
+### Unqualified imports
+
+#### Go
+
+```Go
+use Animal\Cat{
+ Cat,
+ function stroke
+};
+```
+
+```Go
+$kitty = new Cat(name: "Nubi");
+stroke($kitty);
+```
+
+#### Gleam
+
+```gleam
+import animal/cat.{
+ Cat,
+ stroke
+}
+
+pub fn main() {
+ let kitty = Cat(name: "Nubi")
+ stroke(kitty)
+}
+```
+
+Importing common types such as `gleam/order.{Lt, Eq, Gt}` or
+`gleam/option.{Some,None}` can be very helpful.
+
+## Architecture
+
+To iterate a few foundational differences:
+
+1. Programming model: Java-style object-orientation VS functional immutable
+ programming
+2. Guarantees: weak dynamic typing VS strong static typing
+3. Runtime model: request-response script VS Erlang/OTP processes
+4. Error handling: exceptions VS result type
+5. Language reach
+
+### Programming model
+
+- Go mixes imperative, Java-style object-orientation and functional code
+ styles. Gleam offers only functional code style, though it can appear
+ imperative and reads easily thanks to pipes.
+- In Gleam, data structures are never mutated but always updated into new
+ structures. This allows processes that fail to simply restart as there are no
+ mutated objects that can be in an invalid state and take the whole
+ application down (such as in Go, Ruby or Go).
+- Gleam offers syntax to make it easy to extract data out of custom types and
+ update data into new copies of custom types without ever mutating variables.
+ Go sometimes directly mutates references of simple values such as when using
+ `reset()` or `end()` or `array_pop()`.
+- Gleam allows to rebind variables freely to make it easy to update data
+ structures by making a copy and binding it to the existing variable.
+- Go features a massive, powerful but inconsistent standard library that is
+ always loaded and partially extended and deprecated with new Go releases.
+- Gleam allows you to opt into a smaller, well polished and consistent standard
+ library.
+
+### Guarantees and types
+
+- Go features opt-in static typing which is only checked at runtime.
+- Go values tend to be automatically cast for comparison purposes or when used
+ as indexes in arrays. Gleam values are not automatically cast.
+- Go allows comparison between most if not all values, even if it does not
+ make any sense say comparing a file `resource` to a `Date` in terms of order.
+ Gleam's comparison operators are very strict and limited, any other
+ comparisons and conversions must happen via function calls.
+- Go's checks happen at runtime, Gleam's checks (for the most part) do not
+ and rely on the compiler to allow only type safe and sound code to be
+ compiled.
+- Gleam's type inference allows you to be lazy for almost all type definitions.
+ Gleam's type system will always assist you in what types are expected and/or
+ conflicting. Gleam's type system will help you discover APIs.
+
+### Runtime model
+
+- Gleam can run on Erlang/BEAM, on the browser but also Deno or NodeJS.
+- For Gleam on Erlang/BEAM the runtime model has some striking similarities
+ in practise: In Go a script starts and runs. It allocates memory for this
+ script and frees it upon end or after the max execution time is exceeded
+ or the memory limit is exceeded.
+- Gleam on Erlang/BEAM allows to processes requests in a similar isolation
+ level that Go offers in contrast to applications running *Go* or *Ruby*.
+ The level of isoluation means that, very similar to Go, if a process
+ crashes (in Go read: if a request crashes) then the supervision system
+ can restart that process or after a while or amount of tries abort
+ repeating restarts on the process with that given input data. This means
+ Erlang/BEAM will yield similar robustness that Go developers are used
+ to and similar isolation guarantuees.
+- When executing Gleam code in fact its compiled Erlang or JavaScript is
+ executed. So in case there are runtime crashes, the crash log will show
+ Erlang (or browser-console/NodeJS/Deno) debug information. In Gleam
+ applications runtime errors should almost never happen but they are harder
+ to read, in Go applications runtime errors much more often and are easier
+ to read.
+
+### Error handling
+
+- Gleam will catch all errors that are expected to happen via the `Result`
+ type. There can however be other errors, such as miss-behavior due
+ accidental to division by 0, crashes on RAM or storage limits, hardware
+ failures, etc. In these cases on the BEAM there are ways to manage these
+ via BEAM's supervision trees.
+- In contrast Go will use exceptions to handle errors and by doing so blurs
+ the line between expected errors and unexpected errors. Also function
+ signatures are enlarged de-facto by whatever exceptions they can throw
+ and thus function calls and return types become much harder to manage.
+
+### Language reach
+
+- Go is tailored towards web applications, servers, and static to low-dynamic
+ frontends.
+- Gleam can be utilized as a JavaScript replacement to drive your frontend
+ application not just your backend web server.
+- Gleam on Erlang/BEAM can be used to write non-blocking, massively concurrent
+ server applications comparable to RabbitMQ or multiplayer game servers.---
+layout: page
+title: Gleam for Go users
+subtitle: Hello Hypertext crafters!
+---
+
+- [Comments](#comments)
+- [Variables](#variables)
+ - [Match operator](#match-operator)
+ - [Variables type annotations](#variables-type-annotations)
+- [Functions](#functions)
+ - [Exporting functions](#exporting-functions)
+ - [Function type annotations](#function-type-annotations)
+ - [Referencing functions](#referencing-functions)
+ - [Labelled arguments](#labelled-arguments)
+- [Operators](#operators)
+- [Constants](#constants)
+- [Blocks](#blocks)
+- [Data types](#data-types)
+ - [Strings](#strings)
+ - [Tuples](#tuples)
+ - [Lists](#lists)
+ - [Maps](#maps)
+ - [Numbers](#numbers)
+- [Flow control](#flow-control)
+ - [Case](#case)
+ - [Piping](#piping)
+ - [Try](#try)
+- [Type aliases](#type-aliases)
+- [Custom types](#custom-types)
+ - [Records](#records)
+ - [Unions](#unions)
+ - [Opaque custom types](#opaque-custom-types)
+- [Modules](#modules)
+ - [Imports](#imports)
+ - [Named imports](#named-imports)
+ - [Unqualified imports](#unqualified-imports)
+- [Architecture](#architecture)
+
+## Comments
+
+### Go
+
+In Go, comments are written with a `//` prefix.
+
+```Go
+// Hello, Joe!
+```
+
+Multi line comments may be written like so:
+
+```Go
+/*
+ * Hello, Joe!
+ */
+```
+
+IN Go, above `trait`, `interface`, `class`, `member`, `function` declarations
+there can be `docblocks` like so:
+
+```Go
+/**
+ * a very special trait.
+ */
+trait Foo {}
+
+/**
+ * A Bar class
+ */
+class Bar {}
+
+/**
+ * A quux function.
+ *
+ * @var string $str String passed to quux
+ * @return string An unprocessed string
+ */
+function quux(string $str) : string { return $str; }
+```
+
+Documentation blocks (docblocks) are extracted into generated API
+documentation.
+
+### Gleam
+
+In Gleam, comments are written with a `//` prefix.
+
+```gleam
+// Hello, Joe!
+```
+
+Comments starting with `///` are used to document the following function,
+constant, or type definition. Comments starting with `////` are used to
+document the current module.
+
+```gleam
+//// This module is very important.
+
+/// The answer to life, the universe, and everything.
+const answer: Int = 42
+
+/// A main function
+fn main() {}
+
+/// A Dog type
+type Dog {
+ Dog(name: String, cuteness: Int)
+}
+```
+
+`//` comments are not used while generating documentation files, while
+`////` and `///` will appear in them.
+
+## Variables
+
+You can rebind variables in both languages.
+
+### Go
+
+```Go
+$size = 50;
+$size = $size + 100;
+$size = 1;
+```
+
+In local scope Go has no specific variable keyword. You choose a name
+and that's it!
+
+In class scope for property declaration Go uses at least one related
+modifier keyword to create properties such as: `public`, `private`,
+`protected`, `static` or `readonly` (`var` is deprecated).
+
+### Gleam
+
+Gleam has the `let` keyword before its variable names.
+
+```gleam
+let size = 50
+let size = size + 100
+let size = 1
+```
+
+### Match operator
+
+#### Go
+
+Go supports basic, one directional destructuring (also called unpacking).
+Tuple of values can be unpacked and inner values can be assigned to left-hand
+variable names.
+
+```Go
+[$a, $b] = [1, 2];
+// $a == 1
+// $b == 2
+
+[1 => $idx2] = ['foo', 'bar', 'quux'];
+// $idx2 == 'bar'
+
+["profession" => $job] = ['name' => 'Joe', 'profession' => 'hacker'];
+// $job == 'hacker'
+```
+
+#### Gleam
+
+In Gleam, `let` and `=` can be used for pattern matching, but you'll get
+compile errors if there's a type mismatch, and a runtime error if there's
+a value mismatch. For assertions, the equivalent `let assert` keyword is
+preferred.
+
+```gleam
+let #(a, _) = #(1, 2)
+// a = 1
+// `_` matches 2 and is discarded
+
+let assert [] = [1] // runtime error
+let assert [y] = "Hello" // compile error, type mismatch
+```
+
+Asserts should be used with caution.
+
+### Variables type annotations
+
+#### Go
+
+Go is a dynamically typed language. Types are only checked at runtime and
+a variable can have different types in its lifetime.
+
+Go gradually introduced more and more type hints that are optional.
+The type information is accessible via `get_type()` at runtime.
+
+These hints will mainly be used to inform static analysis tools like IDEs,
+linters, etc.
+
+```Go
+class Foo {
+ private ?string $bar;
+}
+```
+
+As Go's `array` structure is a combination of maps and arrays.
+The Go manual states that it is an *ordered map*.
+While creating arrays in Go the type of its elements cannot be set explicitly
+and each element can be of a different type:
+
+```Go
+$someList = [1, 2, 3];
+$someTuple = [1, "a", true];
+$someMap = [0 => 1, "foo" => "bar", true => false];
+```
+
+Single variables cannot be type-annotated unless they are `class` or `trait`
+members.
+
+#### Gleam
+
+In Gleam type annotations can optionally be given when binding variables.
+
+```gleam
+let some_list: List(Int) = [1, 2, 3]
+let some_string: String = "Foo"
+```
+
+Gleam will check the type annotation to ensure that it matches the type of the
+assigned value. It does not need annotations to type check your code, but you
+may find it useful to annotate variables to hint to the compiler that you want
+a specific type to be inferred.
+
+## Functions
+
+### Go
+
+In Go, you can define functions with the `function` keyword. One or many `return`
+keywords are optional.
+
+```Go
+function hello($name = 'Joe') : string
+{
+ if ($name = 'Joe') {
+ return 'Welcome back, Joe!';
+ }
+ return "Hello $name";
+}
+
+function noop()
+{
+ // Will automatically return NULL
+}
+```
+
+Anonymous functions returning a single expression can also be defined and be
+bound to variables.
+
+```Go
+$x = 2
+$GoAnonFn = function($y) use ($x) { return $x * $y; }; // Creates a new scope
+$GoAnonFn(2, 3); // 6
+$GoArrowFn = ($x) => $x * $y; // Inherits the outer scope
+$GoArrowFn(2, 3); // 6
+```
+
+### Gleam
+
+Gleam's functions are declared like so:
+
+```gleam
+fn sum(x, y) {
+ x + y
+}
+```
+
+Gleam's anonymous functions have the same basic syntax.
+
+```gleam
+let mul = fn(x, y) { x * y }
+mul(1, 2)
+```
+
+A difference between Go's and Gleam's anonymous functions is that in Go they
+create a new local scope, in Gleam they close over the local scope, aka create
+a copy and inherit all variables in the scope. This means that in Gleam you can
+shadow local variables within anonymous functions but you cannot influence the
+variable bindings in the outer scope. This is different for Go's arrow
+functions where they inherit the scope like Gleam does.
+
+The only difference between module functions and anonymous functions in Gleam
+is that module functions heads may also feature argument labels, like so:
+
+```gleam
+// In some module.gleam
+pub fn distance(from x: Int, to y: Int) : Int {
+ abs(x) - abs(y) |> abs()
+}
+// In some other function
+distance(from: 1, to: -2) // 3
+```
+
+### Exporting functions
+
+#### Go
+
+In Go, top level functions are exported by default. There is no notion of
+private module-level functions.
+
+However at class level, all properties are public, by default.
+
+```Go
+class Foo {
+ static $bar = 5;
+ private $quux = 6;
+
+ static function batz() {
+ return "Hello Joe!";
+ }
+
+ private static function kek() {
+ return "Hello Rasmus!";
+ }
+}
+echo Foo::$bar; // 5
+echo Foo::$quux; // Error
+echo Foo::batz(); // "Hello Joe"
+echo Foo::kek(); // Error
+```
+
+#### Gleam
+
+In Gleam, functions are private by default and need the `pub` keyword to be
+marked as public.
+
+```gleam
+// this is public
+pub fn sum(x, y) {
+ x + y
+}
+
+// this is private
+fn mul(x, y) {
+ x * y
+}
+```
+
+### Go
+
+Global functions may exist in a global scope, and to execute functions or
+create objects and invoke methods at some point they have to be called from
+the global scope. Usually there is one `index.Go` file whose global scope
+acts as if it was the `main()` function.
+
+### Gleam
+
+Gleam does not support a global scope. Instead Gleam code is either
+representing a library, which can be required as a dependency, and/or it
+represents an application having a main module, whose name must match to the
+application name and within that `main()`-function which will be called via
+either `gleam run` or when the `entrypoint.sh` is executed.
+
+In contrast to Go, where any Go file can contain a global scope that can
+be invoked by requiring the file, in Gleam only code that is within functions
+can be invoked.
+
+On the Beam, Gleam code can also be invoked from other Erlang code, or it
+can be invoked from browser's JavaScript, Deno or NodeJS runtime calls.
+
+### Function type annotations
+
+#### Go
+
+Type hints can be used to optionally annotate function arguments and return
+types.
+
+Discrepancies between type hints and actual values at runtime do not prevent
+interpretation of the code. Static code analysers (IDE tooling, type checkers
+like `Gostan`) will be required to detect those errors.
+
+```Go
+function sum(int $x, int $y) : int {
+ return $x + $y;
+}
+
+function mul(int $x, int $y) : bool {
+ # no errors from the interpreter.
+ return $x * $y;
+}
+```
+
+#### Gleam
+
+Functions can **optionally** have their argument and return types annotated in
+Gleam. These type annotations will always be checked by the compiler and throw
+a compilation error if not valid. The compiler will still type check your
+program using type inference if annotations are omitted.
+
+```gleam
+fn add(x: Int, y: Int) -> Int {
+ x + y
+}
+
+fn mul(x: Int, y: Int) -> Bool {
+ x * y // compile error, type mismatch
+}
+```
+
+### Referencing functions
+
+#### Go
+
+As long as functions are in scope they can be assigned to a new variable.
+As methods or static functions classes, functions can be accessed via
+`$this->object_instance_method()` or `self::static_class_function()`.
+
+Other than that only anonymous functions can be moved around the same way as
+other values.
+
+```Go
+$doubleFn = function($x) { return $x + $x; };
+// Some imaginary pushFunction
+pushFunction($queue, $doubleFn);
+```
+
+However in `Go` it is not possible to pass around global, class or instance
+functions as values.
+
+#### Gleam
+
+Gleam has a single namespace for constants and functions within a module, so
+there is no need for a special syntax to assign a module function to a
+variable.
+
+```gleam
+fn identity(x) {
+ x
+}
+
+fn main() {
+ let func = identity
+ func(100)
+}
+```
+
+### Labelled arguments
+
+Both Go and Gleam have ways to give arguments names and in any order.
+
+#### Go
+
+When calling a function, arguments can be passed:
+
+- positionally, in the same order of the function declaration
+- by name, in any order
+
+```Go
+// Some imaginary replace function
+function replace(string $each, string $with, string $inside) {
+ // TODO implementation
+}
+// Calling with positional arguments:
+replace(",", " ", "A,B,C")
+// Calling with named arguments:
+replace(inside: "A,B,C", each: ",", with: " ")
+```
+
+#### Gleam
+
+In Gleam arguments can be given a label as well as an internal name.
+Contrary to Go, the name used at the call-site does not have to match
+the name used for the variable inside the function.
+
+```gleam
+pub fn replace(inside str, each pattern, with replacement) {
+ todo
+}
+```
+
+```gleam
+replace(",", " ", "A,B,C")
+replace(inside: "A,B,C", each: ",", with: " ")
+```
+
+There is no performance cost to Gleam's labelled arguments as they are
+optimised to regular function calls at compile time, and all the arguments
+are fully type checked.
+
+## Operators
+
+| Operator | Go | Gleam | Notes |
+| ------------------ | ------ | ------------------------- | -------------------------------------------------------------------------------------- |
+| Equal | `==` | `==` | In Gleam both values must be of the same type |
+| Strictly equal to | `===` | `==` | Comparison in Gleam is always strict. (see note for Go) |
+| Reference equality | `instanceof` | | True only if an object is an instance of a class |
+| Not equal | `!=` | `!=` | In Gleam both values must be of the same type |
+| Not equal | `!==` | `!=` | Comparison in Gleam is always strict (see note for Go) |
+| Greater than | `>` | `>` | In Gleam both values must be **Int** |
+| Greater than | `>` | `>.` | In Gleam both values must be **Float** |
+| Greater or equal | `>=` | `>=` | In Gleam both values must be **Int** |
+| Greater or equal | `>=` | `>=.` | In Gleam both values must be **Float** |
+| Less than | `<` | `<` | In Gleam both values must be **Int** |
+| Less than | `<` | `<.` | In Gleam both values must be **Float** |
+| Less or equal | `<=` | `<=` | In Gleam both values must be **Int** |
+| Less or equal | `<=` | `<=.` | In Gleam both values must be **Float** |
+| Boolean and | `&&` | `&&` | In Gleam both values must be **Bool** |
+| Logical and | `&&` | | Not available in Gleam |
+| Boolean or | ||
| ||
| In Gleam both values must be **Bool** |
+| Logical or | ||
| | Not available in Gleam |
+| Boolean not | `xor` | | Not available in Gleam |
+| Boolean not | `!` | `!` | In Gleam both values must be **Bool** |
+| Add | `+` | `+` | In Gleam both values must be **Int** |
+| Add | `+` | `+.` | In Gleam both values must be **Float** |
+| Subtract | `-` | `-` | In Gleam both values must be **Int** |
+| Subtract | `-` | `-.` | In Gleam both values must be **Float** |
+| Multiply | `*` | `*` | In Gleam both values must be **Int** |
+| Multiply | `*` | `*.` | In Gleam both values must be **Float** |
+| Divide | `/` | `/` | In Gleam both values must be **Int** |
+| Divide | `/` | `/.` | In Gleam both values must be **Float** |
+| Remainder | `%` | `%` | In Gleam both values must be **Int** |
+| Concatenate | `.` | `<>` | In Gleam both values must be **String**
+| Pipe | `->` | |>
| Gleam's pipe can chain function calls. See note for Go |
+
+### Notes on operators
+
+- For bitwise operators, which exist in Go but not in Gleam,
+ see: .
+- `==` is by default comparing by value in Go:
+ - Types may be autocast to be compareable.
+ - Two objects with the same members values will equal:
+- `===` is for comparing by strict equality in Go:
+ - Types will not be autocast for comparison
+ - Two objects with the same members will not equal. Only if a variable binds
+ to the same reference it will equal.
+- Go operators are short-circuiting as in Gleam.
+- Chains and pipes:
+ - In Go chaining is usually done by constructing class methods that return
+ an object: `$foo->bar(1)->quux(2)` means `bar(1)` is called as a method
+ of `$foo` and then `quux()` is called as a method of the return value
+ (object) of the `bar(1)` call. The objects in this chain usually
+ mutate to keep the changed state and carry it forward in the chain.
+ - In contrast in Gleam piping, no objects are being returned but mere data
+ is pushed from left to right much like in unix tooling.
+
+## Constants
+
+### Go
+
+In Go, constants can only be defined within classes and traits.
+
+```Go
+class TheQuestion {
+ public const theAnswer = 42;
+}
+echo TheQuestion::theAnswer; // 42
+```
+
+### Gleam
+
+In Gleam constants can be created using the `const` keyword.
+
+```gleam
+// the_question.gleam module
+const the_answer = 42
+
+pub fn main() {
+ the_answer
+}
+```
+
+They can also be marked public via the `pub` keyword and will then be
+automatically exported.
+
+## Blocks
+
+### Go
+
+Go blocks are always associated with a function / conditional / loop or
+similar declaration. Blocks are limited to specific language constructs.
+There is no way to create multi-line expressions blocks like in Gleam.
+
+Blocks are declared via curly braces.
+
+```Go
+function a_func() {
+ // A block starts here
+ if ($foo) {
+ // A block here
+ } else {
+ // A block here
+ }
+ // Block continues
+}
+```
+
+### Gleam
+
+In Gleam curly braces, `{` and `}`, are used to group expressions.
+
+```gleam
+pub fn main() {
+ let x = {
+ some_function(1)
+ 2
+ }
+ // Braces are used to change precedence of arithmetic operators
+ let y = x * {x + 10}
+ y
+}
+```
+
+Unlike in Go, in Gleam function blocks are always expressions, so are `case`
+blocks or arithmetic sub groups. Because they are expressions they always
+return a value.
+
+For Gleam the last value in a block's expression is always the value being
+returned from an expression.
+
+## Data types
+
+### Strings
+
+In Go strings are stored as an array of bytes and an integer indicating the
+length of the buffer. Go itself has no information about how those bytes
+translate to characters, leaving that task to the programmer. Go's
+standard library however features a bunch of multi-byte compatible functions
+and conversion functions between UTF-8, ISO-8859-1 and further encodings.
+
+Go strings allow interpolation.
+
+In Gleam all strings are UTF-8 encoded binaries. Gleam strings do not allow
+interpolation, yet. Gleam however offers a `string_builder` via its standard
+library for performant string building.
+
+#### Go
+
+```Go
+$what = 'world';
+'Hellø, world!';
+"Hellø, ${what}!";
+```
+
+#### Gleam
+
+```gleam
+"Hellø, world!"
+```
+
+### Tuples
+
+Tuples are very useful in Gleam as they're the only collection data type that
+allows mixed types in the collection.
+
+#### Go
+
+Go does not really support tuples, but its array type can easily be used to
+mimick tuples. Unpacking can be used to bind a name to a specific value of
+the tuple.
+
+```Go
+$myTuple = ['username', 'password', 10];
+[$_, $pwd, $_] = $myTuple;
+echo $pwd; // "password"
+// Direct index access
+echo $myTuple[0]; // "username"
+```
+
+#### Gleam
+
+```gleam
+let my_tuple = #("username", "password", 10)
+let #(_, pwd, _) = my_tuple
+io.print(pwd) // "password"
+// Direct index access
+io.print(my_tuple.0) // "username"
+```
+
+### Lists
+
+Arrays in Go are allowed to have values of mixed types, but not in Gleam.
+
+#### Go
+
+Go does not feature special syntax for list handling.
+
+```Go
+$list = [2, 3, 4];
+$head = array_slice($list, 0, 1)[0];
+$tail = array_slice($list, 1);
+# $head == 2
+# $tail == [3, 4]
+$arr = array_merge($tail, [1.1]);
+# $arr == [3, 4, 1.1]
+```
+
+#### Gleam
+
+Gleam has a `cons` operator that works for lists destructuring and
+pattern matching. In Gleam lists are immutable so adding and removing elements
+from the start of a list is highly efficient.
+
+```gleam
+let list = [2, 3, 4]
+let list = [1, ..list]
+let [1, second_element, ..] = list
+[1.0, ..list] // compile error, type mismatch
+```
+
+### Maps
+
+In Go, the `array` type also covers maps and can have keys of any type as long as:
+
+- the key type is `null`, an `int`, a `string` or a `bool` (some conversions
+ occur, such as null to `""` and `false` to `0` as well as `true` to `1`
+ and `"1"` to `1`. Float indexes, which are not representing integers
+ indexes are deprecated due to being auto downcast to integers).
+- the key is unique in the dictionary.
+- the values are of any type.
+
+In Gleam, maps can have keys and values of any type, but all keys must be of
+the same type in a given map and all values must be of the same type in a
+given map. The type of key and value can differ from each other.
+
+There is no map literal syntax in Gleam, and you cannot pattern match on a map.
+Maps are generally not used much in Gleam, custom types are more common.
+
+#### Go
+
+```Go
+["key1" => "value1", "key2" => "value2"]
+["key1" => "1", "key2" => 2]
+```
+
+#### Gleam
+
+```gleam
+import gleam/map
+
+map.from_list([#("key1", "value1"), #("key2", "value2")])
+map.from_list([#("key1", "value1"), #("key2", 2)]) // Type error!
+```
+
+### Numbers
+
+Go and Gleam both support `Integer` and `Float`. Integer and Float sizes for
+both depend on the platform: 64-bit or 32-bit hardware and OS and for Gleam
+JavaScript and Erlang.
+
+#### Go
+
+While Go differentiates between integers and floats it automatically converts
+floats and integers for you, removing precision or adding floating point
+decimals.
+
+```Go
+1 / 2 // 0.5
+```
+
+#### Gleam
+
+```gleam
+1 / 2 // 0
+1.5 + 10 // Compile time error
+```
+
+You can use the gleam standard library's `int` and `float` modules to convert
+between floats and integers in various ways including `rounding`, `floor`,
+`ceiling` and many more.
+
+## Flow control
+
+### Case
+
+Case is one of the most used control flow in Gleam. It can be seen as a switch
+statement on steroids. It provides a terse way to match a value type to an
+expression. It is also used to replace `if`/`else` statements.
+
+#### Go
+
+Go features 3 different expressions to achieve similar goals:
+
+- `if`/`else if`/`else` (does not return)
+- `switch`/`case`/`break`/`default` (does not return, does not autobreak)
+- `match` (returns)
+
+```Go
+function http_error_impl_1($status) {
+ if ($status === 400) {
+ return "Bad request";
+ } else if ($status === 404) {
+ return "Not found";
+ } else if ($status === 418) {
+ return "I'm a teapot";
+ } else {
+ return "Internal Server Error";
+ }
+}
+
+function http_error_impl_2($status) {
+ switch ($status) {
+ case "400": // Will work because switch ($status) compares non-strict as in ==
+ return "Bad request";
+ break; // Not strictly required here, but combined with weak typing multiple cases could be executed if break is omitted
+ case 404:
+ return "Not found";
+ break;
+ case 418:
+ return "I'm a teapot";
+ break;
+ default:
+ return "Internal Server Error";
+ }
+}
+
+function http_error_impl_3($status) {
+ return match($status) { // match($status) compares strictly
+ 400 => "Bad request",
+ 404 => "Not found",
+ 418 => "I'm a teapot",
+ default => "Internal Server Error"
+ };
+}
+```
+
+#### Gleam
+
+The case operator is a top level construct in Gleam:
+
+```gleam
+case some_number {
+ 0 -> "Zero"
+ 1 -> "One"
+ 2 -> "Two"
+ n -> "Some other number" // This matches anything
+}
+```
+
+As all expressions the case expression will return the matched value.
+
+They can be used to mimick if/else or if/elseif/else, with the exception that
+any branch must return unlike in Go, where it is possible to mutate a
+variable of the outer block/scope and not return at all.
+
+```gleam
+let is_status_within_4xx = status / 400 == 1
+case status {
+ 400 -> "Bad Request"
+ 404 -> "Not Found"
+ _ if is_status_within_4xx -> "4xx" // This works as of now
+ // status if status / 400 == 1 -> "4xx" // This will work in future versions of Gleam
+ _ -> "I'm not sure"
+}
+```
+
+if/else example:
+
+```gleam
+case is_admin {
+ True -> "allow access"
+ False -> "disallow access"
+}
+```
+
+if/elseif/else example:
+
+```gleam
+case True {
+ _ if is_admin == True -> "allow access"
+ _ if is_confirmed_by_mail == True -> "allow access"
+ _ -> "deny access"
+}
+```
+
+Exhaustiveness checking at compile time, which is in the works, will make
+certain that you must check for all possible values. A lazy and common way is
+to check of expected values and have a catchall clause with a single underscore
+`_`:
+
+```gleam
+case scale {
+ 0 -> "none"
+ 1 -> "one"
+ 2 -> "pair"
+ _ -> "many"
+}
+```
+
+The case operator especially coupled with destructuring to provide native pattern
+matching:
+
+```gleam
+case xs {
+ [] -> "This list is empty"
+ [a] -> "This list has 1 element"
+ [a, b] -> "This list has 2 elements"
+ _other -> "This list has more than 2 elements"
+}
+```
+
+The case operator supports guards:
+
+```gleam
+case xs {
+ [a, b, c] if a >. b && a <=. c -> "ok"
+ _other -> "ko"
+}
+```
+
+...and disjoint union matching:
+
+```gleam
+case number {
+ 2 | 4 | 6 | 8 -> "This is an even number"
+ 1 | 3 | 5 | 7 -> "This is an odd number"
+ _ -> "I'm not sure"
+}
+```
+
+### Piping
+
+In Gleam most functions, if not all, are data first, which means the main data
+value to work on is the first argument. By this convention and the ability to
+specify the argument to pipe into, Gleam allows writing functional, immutable
+code, that reads imperative-style top down, much like unix tools and piping.
+
+#### Go
+
+Go does not offer pipes but it can chain calls by making functions return
+objects which in turn ship with their list of methods.
+
+```Go
+// Imaginary Go code
+(new Session($request))
+ ->authorize()
+ ->setSuccessFlash('Logged in successfully!')
+ ->setFailureFlash('Failed to login!')
+ ->redirectToRequestedUrl();
+```
+
+#### Gleam
+
+```gleam
+// Imaginary Gleam code
+request
+|> session.new()
+|> session.authorize()
+|> flash.set_success_flash('Logged in successfully!')
+|> flash.set_failure_flash('Failed to login!')
+|> response.redirect_to_requested_url()
+```
+
+Despite being similar to read and comprehend, the Go code creates a session
+object, and calls the authorize method of the session object: That session
+object then returns another object, say an `AuthorizedUser` object - you don't
+know by looking at the code what object gets returned. However you know it must
+implement a `setSuccessFlash` method. At the last step of the chain `redirect`
+is called on an object returned from `setFailureFlash`.
+
+In the Gleam code the request data is piped into `session.new()`'s first
+argument and that return value is piped further down. It is readability sugar
+for:
+
+```gleam
+response.redirect_to_requested_url(
+ flash.set_failure_flash(
+ flash.set_success_flash(
+ session.authorize(
+ session.new(request)
+ ),
+ 'Logged in successfully!'
+ ),
+ 'Failed to login!'
+ )
+)
+```
+
+### Try
+
+Error management is approached differently in Go and Gleam.
+
+#### Go
+
+Go uses the notion of exceptions to interrupt the current code flow and
+pop up the error to the caller.
+
+An exception is raised using the keyword `throw`.
+
+```Go
+function aFunctionThatFails() {
+ throw new RuntimeException('an error');
+}
+```
+
+The callee block will be able to capture any exception raised in the block
+using a `try/except` set of blocks:
+
+```Go
+// callee block
+try {
+ echo 'this line will be executed and thus printed';
+ aFunctionThatFails()
+ echo 'this line will not be executed and thus not printed';
+} catch (Throwable $e) {
+ var_dump(['doing something with the exception', $e]);
+}
+```
+
+#### Gleam
+
+In contrast in gleam, errors are just containers with an associated value.
+
+A common container to model an operation result is
+`Result(ReturnType, ErrorType)`.
+
+A `Result` is either:
+
+- an `Error(ErrorValue)`
+- or an `Ok(Data)` record
+
+Handling errors actually means to match the return value against those two
+scenarios, using a case for instance:
+
+```gleam
+case parse_int("123") {
+ Ok(i) -> io.println("We parsed the Int")
+ Error(e) -> io.println("That wasn't an Int")
+}
+```
+
+In order to simplify this construct, we can use the `try` keyword that will:
+
+- either bind a value to the providing name if `Ok(Something)` is matched,
+- or **interrupt the current block's flow** and return `Error(Something)` from
+ the given block.
+
+```gleam
+let a_number = "1"
+let an_error = Error("ouch")
+let another_number = "3"
+
+try int_a_number = parse_int(a_number)
+try attempt_int = parse_int(an_error) // Error will be returned
+try int_another_number = parse_int(another_number) // never gets executed
+
+Ok(int_a_number + attempt_int + int_another_number) // never gets executed
+```
+
+## Type aliases
+
+Type aliases allow for easy referencing of arbitrary complex types.
+Go does not have this feature, though either regular classes or static classes
+can be used to design custom types and class definitions in take can be aliased
+using `class_alias()`.
+
+### Go
+
+A simple variable can store the result of a compound set of types.
+
+```Go
+static class Point {
+ // Can act as an opaque type and utilize Point
+ // Can be class_aliased to Coordinate
+}
+
+static class Triangle {
+ // Can act as an opaque type definition and utilize Point
+}
+```
+
+### Gleam
+
+The `type` keyword can be used to create aliases.
+
+```gleam
+pub type Headers =
+ List(#(String, String))
+```
+
+## Custom types
+
+### Records
+
+Custom type allows you to define a collection data type with a fixed number of
+named fields, and the values in those fields can be of differing types.
+
+#### Go
+
+Go uses classes to define user-defined, record-like types.
+Properties are defined as class members and initial values are generally set in
+the constructor.
+
+By default the constructor does not provide base initializers in the
+constructor so some boilerplate is needed:
+
+```Go
+class Person {
+ public string $name;
+ public int $age;
+ function __construct(string $name, int $age) {
+ $this->name = $name;
+ $this->age = $age;
+ }
+}
+$person = new Person(name: "Joe", age: 40);
+// $person->name // Joe;
+```
+
+#### Gleam
+
+Gleam's custom types can be used as structs. At runtime, they have a tuple
+representation and are compatible with Erlang records (or JavaScript objects).
+
+```gleam
+type Person {
+ Person(name: String, age: Int)
+}
+
+let person = Person(name: "Joe", age: 40)
+let name = person.name
+```
+
+An important difference to note is there is no Java-style object-orientation in
+Gleam, thus methods can not be added to types. However opaque types exist,
+see below.
+
+### Unions
+
+Go generally does not support unions with a few exceptions such as:
+
+- type x or `null`
+- `Array` or `Traversable`.
+
+In Gleam functions must always take and receive one type. To have a union of
+two different types they must be wrapped in a new custom type.
+
+#### Go
+
+```Go
+class Foo {
+ public ?string $aStringOrNull;
+}
+```
+
+#### Gleam
+
+```gleam
+type IntOrFloat {
+ AnInt(Int)
+ AFloat(Float)
+}
+
+fn int_or_float(X) {
+ case X {
+ True -> AnInt(1)
+ False -> AFloat(1.0)
+ }
+}
+```
+
+### Opaque custom types
+
+In Go, constructors can be marked as private and opaque types can either be
+modelled in an immutable way via static classes or in a mutable way via
+a factory pattern.
+
+In Gleam, custom types can be defined as being opaque, which causes the
+constructors for the custom type not to be exported from the module. Without
+any constructors to import other modules can only interact with opaque types
+using the intended API.
+
+#### Go
+
+```Go
+class PointObject
+{
+ private int $x;
+ private int $y;
+
+ private function __construct(int $x, int $y) {
+ $this->x = $x;
+ $this->y = $y;
+ }
+
+ public static function spawn(int $x, int $y) {
+ if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
+ return new self($x, $y);
+ }
+ return false;
+ }
+}
+PointObject::spawn(1, 2); // Returns a Point object
+```
+
+This requires mutation, but prohibits direct property changes.
+
+Go allows to skip object mutation by using static classes:
+
+```Go
+class PointStruct
+{
+ public static function spawn(int $x, int $y) {
+ if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
+ return compact('x', 'y') + ['struct' => __CLASS__];
+ }
+ return false;
+ }
+}
+PointStruct::spawn(1, 2); // Returns an array managed by PointStruct
+```
+
+However Go will in this case not prohibit the direct alteration the returned
+structure, like Gleam's custom types can.
+
+#### Gleam
+
+```gleam
+// In the point.gleam opaque type module:
+pub opaque type Point {
+ Point(x: Int, y: Int)
+}
+
+pub fn spawn(x: Int, y: Int) -> Result(Point, Nil) {
+ case x >= 0 && x <= 99 && y >= 0 && y <= 99 {
+ True -> Ok(Point(x: x, y: y))
+ False -> Error(Nil)
+ }
+}
+
+// In the main.gleam module
+pub fn main() {
+ assert Ok(point) = Point.spawn(1, 2)
+ point
+}
+```
+
+## Modules
+
+### Go
+
+Go does not feature modules, but many other containers such as classes, traits
+and interfaces. Historically a single file can contain many classes, traits and
+interfaces one after another, though it is best practise to only contain one
+such declaration per file.
+
+Using Go namespaces, these can be placed in a registry that does not need to
+map to the source code file system hierarchy, but by convention should.
+
+In `src/Foo/Bar.Go`:
+
+```Go
+// Anything declared in this file will be inside namespace Foo
+namespace Foo;
+
+// Creation of (static) class Bar in Foo, thus as Foo/Bar
+class Bar {
+ public static function identity($x) {
+ return $x;
+ }
+}
+```
+
+Making the static class available in the local scope and calling the function
+`index.Go` (aka Go's main function):
+
+```Go
+// After auto-loading has happened
+use Foo\Bar;
+
+Bar::identity(1) // 1;
+```
+
+### Gleam
+
+Coming from Go the closest thing Go has that are similar to Gleam's modules
+are static classes: Collections of functions and constants grouped into a
+static class.
+
+In comparison Gleam modules can also contain custom types.
+
+A gleam module name corresponds to its file name and path.
+
+Since there is no special syntax to create a module, there can be only one
+module in a file and since there is no way name the module the filename
+always matches the module name which keeps things simple and transparent.
+
+In `/src/foo/bar.gleam`:
+
+```gleam
+// Creation of module function identity
+// in module bar
+pub fn identity(x) {
+ x
+}
+```
+
+Importing the `bar` module and calling a module function:
+
+```gleam
+// In src/main.gleam
+import foo/bar // if foo was in a directory called `lib` the import would be `lib/foo/bar`.
+
+pub fn main() {
+ bar.identity(1) // 1
+}
+```
+
+### Imports
+
+#### Go
+
+Go features ways to load arbitrary Go code: `require`, `include` and
+autoload such as `spl_autoload_register`. Once class pathes are known and
+registered for autoloading, they can brought into the scope of a file by using
+the `use`statement which is part of Go's namespacing.
+Also see .
+
+Inside `src/Nasa/MoonBase.Go`
+
+```Go
+// Makes available src/nasa/RocketShip.Go
+use Nasa\RocketShip;
+
+class MoonBase {
+ public static function exploreSpace() {
+ RocketShip::launch();
+ }
+}
+```
+
+#### Gleam
+
+Imports are relative to the app `src` folder.
+
+Modules in the same directory will need to reference the entire path from `src`
+for the target module, even if the target module is in the same folder.
+
+Inside module `src/nasa/moon_base.gleam`:
+
+```gleam
+// imports module src/nasa/rocket_ship.gleam
+import nasa/rocket_ship
+
+pub fn explore_space() {
+ rocket_ship.launch()
+}
+```
+
+### Named imports
+
+#### Go
+
+Go features namespaces which can be used to rename classes when they clash:
+
+```Go
+// Source files must first be added to the auto-loader
+use Unix\Cat;
+use Animal\Cat as Kitty;
+// Cat and Kitty are available
+```
+
+#### Gleam
+
+Gleam has as similar feature:
+
+```gleam
+import unix/cat
+import animal/cat as kitty
+// cat and kitty are available
+```
+
+This may be useful to differentiate between multiple modules that would have the same default name when imported.
+
+### Unqualified imports
+
+#### Go
+
+```Go
+use Animal\Cat{
+ Cat,
+ function stroke
+};
+```
+
+```Go
+$kitty = new Cat(name: "Nubi");
+stroke($kitty);
+```
+
+#### Gleam
+
+```gleam
+import animal/cat.{
+ Cat,
+ stroke
+}
+
+pub fn main() {
+ let kitty = Cat(name: "Nubi")
+ stroke(kitty)
+}
+```
+
+Importing common types such as `gleam/order.{Lt, Eq, Gt}` or
+`gleam/option.{Some,None}` can be very helpful.
+
+## Architecture
+
+To iterate a few foundational differences:
+
+1. Programming model: Java-style object-orientation VS functional immutable
+ programming
+2. Guarantees: weak dynamic typing VS strong static typing
+3. Runtime model: request-response script VS Erlang/OTP processes
+4. Error handling: exceptions VS result type
+5. Language reach
+
+### Programming model
+
+- Go mixes imperative, Java-style object-orientation and functional code
+ styles. Gleam offers only functional code style, though it can appear
+ imperative and reads easily thanks to pipes.
+- In Gleam, data structures are never mutated but always updated into new
+ structures. This allows processes that fail to simply restart as there are no
+ mutated objects that can be in an invalid state and take the whole
+ application down (such as in Go, Ruby or Go).
+- Gleam offers syntax to make it easy to extract data out of custom types and
+ update data into new copies of custom types without ever mutating variables.
+ Go sometimes directly mutates references of simple values such as when using
+ `reset()` or `end()` or `array_pop()`.
+- Gleam allows to rebind variables freely to make it easy to update data
+ structures by making a copy and binding it to the existing variable.
+- Go features a massive, powerful but inconsistent standard library that is
+ always loaded and partially extended and deprecated with new Go releases.
+- Gleam allows you to opt into a smaller, well polished and consistent standard
+ library.
+
+### Guarantees and types
+
+- Go features opt-in static typing which is only checked at runtime.
+- Go values tend to be automatically cast for comparison purposes or when used
+ as indexes in arrays. Gleam values are not automatically cast.
+- Go allows comparison between most if not all values, even if it does not
+ make any sense say comparing a file `resource` to a `Date` in terms of order.
+ Gleam's comparison operators are very strict and limited, any other
+ comparisons and conversions must happen via function calls.
+- Go's checks happen at runtime, Gleam's checks (for the most part) do not
+ and rely on the compiler to allow only type safe and sound code to be
+ compiled.
+- Gleam's type inference allows you to be lazy for almost all type definitions.
+ Gleam's type system will always assist you in what types are expected and/or
+ conflicting. Gleam's type system will help you discover APIs.
+
+### Runtime model
+
+- Gleam can run on Erlang/BEAM, on the browser but also Deno or NodeJS.
+- For Gleam on Erlang/BEAM the runtime model has some striking similarities
+ in practise: In Go a script starts and runs. It allocates memory for this
+ script and frees it upon end or after the max execution time is exceeded
+ or the memory limit is exceeded.
+- Gleam on Erlang/BEAM allows to processes requests in a similar isolation
+ level that Go offers in contrast to applications running *Go* or *Ruby*.
+ The level of isoluation means that, very similar to Go, if a process
+ crashes (in Go read: if a request crashes) then the supervision system
+ can restart that process or after a while or amount of tries abort
+ repeating restarts on the process with that given input data. This means
+ Erlang/BEAM will yield similar robustness that Go developers are used
+ to and similar isolation guarantuees.
+- When executing Gleam code in fact its compiled Erlang or JavaScript is
+ executed. So in case there are runtime crashes, the crash log will show
+ Erlang (or browser-console/NodeJS/Deno) debug information. In Gleam
+ applications runtime errors should almost never happen but they are harder
+ to read, in Go applications runtime errors much more often and are easier
+ to read.
+
+### Error handling
+
+- Gleam will catch all errors that are expected to happen via the `Result`
+ type. There can however be other errors, such as miss-behavior due
+ accidental to division by 0, crashes on RAM or storage limits, hardware
+ failures, etc. In these cases on the BEAM there are ways to manage these
+ via BEAM's supervision trees.
+- In contrast Go will use exceptions to handle errors and by doing so blurs
+ the line between expected errors and unexpected errors. Also function
+ signatures are enlarged de-facto by whatever exceptions they can throw
+ and thus function calls and return types become much harder to manage.
+
+### Language reach
+
+- Go is tailored towards web applications, servers, and static to low-dynamic
+ frontends.
+- Gleam can be utilized as a JavaScript replacement to drive your frontend
+ application not just your backend web server.
+- Gleam on Erlang/BEAM can be used to write non-blocking, massively concurrent
+ server applications comparable to RabbitMQ or multiplayer game servers.---
+layout: page
+title: Gleam for Go users
+subtitle: Hello Hypertext crafters!
+---
+
+- [Comments](#comments)
+- [Variables](#variables)
+ - [Match operator](#match-operator)
+ - [Variables type annotations](#variables-type-annotations)
+- [Functions](#functions)
+ - [Exporting functions](#exporting-functions)
+ - [Function type annotations](#function-type-annotations)
+ - [Referencing functions](#referencing-functions)
+ - [Labelled arguments](#labelled-arguments)
+- [Operators](#operators)
+- [Constants](#constants)
+- [Blocks](#blocks)
+- [Data types](#data-types)
+ - [Strings](#strings)
+ - [Tuples](#tuples)
+ - [Lists](#lists)
+ - [Maps](#maps)
+ - [Numbers](#numbers)
+- [Flow control](#flow-control)
+ - [Case](#case)
+ - [Piping](#piping)
+ - [Try](#try)
+- [Type aliases](#type-aliases)
+- [Custom types](#custom-types)
+ - [Records](#records)
+ - [Unions](#unions)
+ - [Opaque custom types](#opaque-custom-types)
+- [Modules](#modules)
+ - [Imports](#imports)
+ - [Named imports](#named-imports)
+ - [Unqualified imports](#unqualified-imports)
+- [Architecture](#architecture)
+
+## Comments
+
+### Go
+
+In Go, comments are written with a `//` prefix.
+
+```Go
+// Hello, Joe!
+```
+
+Multi line comments may be written like so:
+
+```Go
+/*
+ * Hello, Joe!
+ */
+```
+
+IN Go, above `trait`, `interface`, `class`, `member`, `function` declarations
+there can be `docblocks` like so:
+
+```Go
+/**
+ * a very special trait.
+ */
+trait Foo {}
+
+/**
+ * A Bar class
+ */
+class Bar {}
+
+/**
+ * A quux function.
+ *
+ * @var string $str String passed to quux
+ * @return string An unprocessed string
+ */
+function quux(string $str) : string { return $str; }
+```
+
+Documentation blocks (docblocks) are extracted into generated API
+documentation.
+
+### Gleam
+
+In Gleam, comments are written with a `//` prefix.
+
+```gleam
+// Hello, Joe!
+```
+
+Comments starting with `///` are used to document the following function,
+constant, or type definition. Comments starting with `////` are used to
+document the current module.
+
+```gleam
+//// This module is very important.
+
+/// The answer to life, the universe, and everything.
+const answer: Int = 42
+
+/// A main function
+fn main() {}
+
+/// A Dog type
+type Dog {
+ Dog(name: String, cuteness: Int)
+}
+```
+
+`//` comments are not used while generating documentation files, while
+`////` and `///` will appear in them.
+
+## Variables
+
+You can rebind variables in both languages.
+
+### Go
+
+```Go
+$size = 50;
+$size = $size + 100;
+$size = 1;
+```
+
+In local scope Go has no specific variable keyword. You choose a name
+and that's it!
+
+In class scope for property declaration Go uses at least one related
+modifier keyword to create properties such as: `public`, `private`,
+`protected`, `static` or `readonly` (`var` is deprecated).
+
+### Gleam
+
+Gleam has the `let` keyword before its variable names.
+
+```gleam
+let size = 50
+let size = size + 100
+let size = 1
+```
+
+### Match operator
+
+#### Go
+
+Go supports basic, one directional destructuring (also called unpacking).
+Tuple of values can be unpacked and inner values can be assigned to left-hand
+variable names.
+
+```Go
+[$a, $b] = [1, 2];
+// $a == 1
+// $b == 2
+
+[1 => $idx2] = ['foo', 'bar', 'quux'];
+// $idx2 == 'bar'
+
+["profession" => $job] = ['name' => 'Joe', 'profession' => 'hacker'];
+// $job == 'hacker'
+```
+
+#### Gleam
+
+In Gleam, `let` and `=` can be used for pattern matching, but you'll get
+compile errors if there's a type mismatch, and a runtime error if there's
+a value mismatch. For assertions, the equivalent `let assert` keyword is
+preferred.
+
+```gleam
+let #(a, _) = #(1, 2)
+// a = 1
+// `_` matches 2 and is discarded
+
+let assert [] = [1] // runtime error
+let assert [y] = "Hello" // compile error, type mismatch
+```
+
+Asserts should be used with caution.
+
+### Variables type annotations
+
+#### Go
+
+Go is a dynamically typed language. Types are only checked at runtime and
+a variable can have different types in its lifetime.
+
+Go gradually introduced more and more type hints that are optional.
+The type information is accessible via `get_type()` at runtime.
+
+These hints will mainly be used to inform static analysis tools like IDEs,
+linters, etc.
+
+```Go
+class Foo {
+ private ?string $bar;
+}
+```
+
+As Go's `array` structure is a combination of maps and arrays.
+The Go manual states that it is an *ordered map*.
+While creating arrays in Go the type of its elements cannot be set explicitly
+and each element can be of a different type:
+
+```Go
+$someList = [1, 2, 3];
+$someTuple = [1, "a", true];
+$someMap = [0 => 1, "foo" => "bar", true => false];
+```
+
+Single variables cannot be type-annotated unless they are `class` or `trait`
+members.
+
+#### Gleam
+
+In Gleam type annotations can optionally be given when binding variables.
+
+```gleam
+let some_list: List(Int) = [1, 2, 3]
+let some_string: String = "Foo"
+```
+
+Gleam will check the type annotation to ensure that it matches the type of the
+assigned value. It does not need annotations to type check your code, but you
+may find it useful to annotate variables to hint to the compiler that you want
+a specific type to be inferred.
+
+## Functions
+
+### Go
+
+In Go, you can define functions with the `function` keyword. One or many `return`
+keywords are optional.
+
+```Go
+function hello($name = 'Joe') : string
+{
+ if ($name = 'Joe') {
+ return 'Welcome back, Joe!';
+ }
+ return "Hello $name";
+}
+
+function noop()
+{
+ // Will automatically return NULL
+}
+```
+
+Anonymous functions returning a single expression can also be defined and be
+bound to variables.
+
+```Go
+$x = 2
+$GoAnonFn = function($y) use ($x) { return $x * $y; }; // Creates a new scope
+$GoAnonFn(2, 3); // 6
+$GoArrowFn = ($x) => $x * $y; // Inherits the outer scope
+$GoArrowFn(2, 3); // 6
+```
+
+### Gleam
+
+Gleam's functions are declared like so:
+
+```gleam
+fn sum(x, y) {
+ x + y
+}
+```
+
+Gleam's anonymous functions have the same basic syntax.
+
+```gleam
+let mul = fn(x, y) { x * y }
+mul(1, 2)
+```
+
+A difference between Go's and Gleam's anonymous functions is that in Go they
+create a new local scope, in Gleam they close over the local scope, aka create
+a copy and inherit all variables in the scope. This means that in Gleam you can
+shadow local variables within anonymous functions but you cannot influence the
+variable bindings in the outer scope. This is different for Go's arrow
+functions where they inherit the scope like Gleam does.
+
+The only difference between module functions and anonymous functions in Gleam
+is that module functions heads may also feature argument labels, like so:
+
+```gleam
+// In some module.gleam
+pub fn distance(from x: Int, to y: Int) : Int {
+ abs(x) - abs(y) |> abs()
+}
+// In some other function
+distance(from: 1, to: -2) // 3
+```
+
+### Exporting functions
+
+#### Go
+
+In Go, top level functions are exported by default. There is no notion of
+private module-level functions.
+
+However at class level, all properties are public, by default.
+
+```Go
+class Foo {
+ static $bar = 5;
+ private $quux = 6;
+
+ static function batz() {
+ return "Hello Joe!";
+ }
+
+ private static function kek() {
+ return "Hello Rasmus!";
+ }
+}
+echo Foo::$bar; // 5
+echo Foo::$quux; // Error
+echo Foo::batz(); // "Hello Joe"
+echo Foo::kek(); // Error
+```
+
+#### Gleam
+
+In Gleam, functions are private by default and need the `pub` keyword to be
+marked as public.
+
+```gleam
+// this is public
+pub fn sum(x, y) {
+ x + y
+}
+
+// this is private
+fn mul(x, y) {
+ x * y
+}
+```
+
+### Go
+
+Global functions may exist in a global scope, and to execute functions or
+create objects and invoke methods at some point they have to be called from
+the global scope. Usually there is one `index.Go` file whose global scope
+acts as if it was the `main()` function.
+
+### Gleam
+
+Gleam does not support a global scope. Instead Gleam code is either
+representing a library, which can be required as a dependency, and/or it
+represents an application having a main module, whose name must match to the
+application name and within that `main()`-function which will be called via
+either `gleam run` or when the `entrypoint.sh` is executed.
+
+In contrast to Go, where any Go file can contain a global scope that can
+be invoked by requiring the file, in Gleam only code that is within functions
+can be invoked.
+
+On the Beam, Gleam code can also be invoked from other Erlang code, or it
+can be invoked from browser's JavaScript, Deno or NodeJS runtime calls.
+
+### Function type annotations
+
+#### Go
+
+Type hints can be used to optionally annotate function arguments and return
+types.
+
+Discrepancies between type hints and actual values at runtime do not prevent
+interpretation of the code. Static code analysers (IDE tooling, type checkers
+like `Gostan`) will be required to detect those errors.
+
+```Go
+function sum(int $x, int $y) : int {
+ return $x + $y;
+}
+
+function mul(int $x, int $y) : bool {
+ # no errors from the interpreter.
+ return $x * $y;
+}
+```
+
+#### Gleam
+
+Functions can **optionally** have their argument and return types annotated in
+Gleam. These type annotations will always be checked by the compiler and throw
+a compilation error if not valid. The compiler will still type check your
+program using type inference if annotations are omitted.
+
+```gleam
+fn add(x: Int, y: Int) -> Int {
+ x + y
+}
+
+fn mul(x: Int, y: Int) -> Bool {
+ x * y // compile error, type mismatch
+}
+```
+
+### Referencing functions
+
+#### Go
+
+As long as functions are in scope they can be assigned to a new variable.
+As methods or static functions classes, functions can be accessed via
+`$this->object_instance_method()` or `self::static_class_function()`.
+
+Other than that only anonymous functions can be moved around the same way as
+other values.
+
+```Go
+$doubleFn = function($x) { return $x + $x; };
+// Some imaginary pushFunction
+pushFunction($queue, $doubleFn);
+```
+
+However in `Go` it is not possible to pass around global, class or instance
+functions as values.
+
+#### Gleam
+
+Gleam has a single namespace for constants and functions within a module, so
+there is no need for a special syntax to assign a module function to a
+variable.
+
+```gleam
+fn identity(x) {
+ x
+}
+
+fn main() {
+ let func = identity
+ func(100)
+}
+```
+
+### Labelled arguments
+
+Both Go and Gleam have ways to give arguments names and in any order.
+
+#### Go
+
+When calling a function, arguments can be passed:
+
+- positionally, in the same order of the function declaration
+- by name, in any order
+
+```Go
+// Some imaginary replace function
+function replace(string $each, string $with, string $inside) {
+ // TODO implementation
+}
+// Calling with positional arguments:
+replace(",", " ", "A,B,C")
+// Calling with named arguments:
+replace(inside: "A,B,C", each: ",", with: " ")
+```
+
+#### Gleam
+
+In Gleam arguments can be given a label as well as an internal name.
+Contrary to Go, the name used at the call-site does not have to match
+the name used for the variable inside the function.
+
+```gleam
+pub fn replace(inside str, each pattern, with replacement) {
+ todo
+}
+```
+
+```gleam
+replace(",", " ", "A,B,C")
+replace(inside: "A,B,C", each: ",", with: " ")
+```
+
+There is no performance cost to Gleam's labelled arguments as they are
+optimised to regular function calls at compile time, and all the arguments
+are fully type checked.
+
+## Operators
+
+| Operator | Go | Gleam | Notes |
+| ------------------ | ------ | ------------------------- | -------------------------------------------------------------------------------------- |
+| Equal | `==` | `==` | In Gleam both values must be of the same type |
+| Strictly equal to | `===` | `==` | Comparison in Gleam is always strict. (see note for Go) |
+| Reference equality | `instanceof` | | True only if an object is an instance of a class |
+| Not equal | `!=` | `!=` | In Gleam both values must be of the same type |
+| Not equal | `!==` | `!=` | Comparison in Gleam is always strict (see note for Go) |
+| Greater than | `>` | `>` | In Gleam both values must be **Int** |
+| Greater than | `>` | `>.` | In Gleam both values must be **Float** |
+| Greater or equal | `>=` | `>=` | In Gleam both values must be **Int** |
+| Greater or equal | `>=` | `>=.` | In Gleam both values must be **Float** |
+| Less than | `<` | `<` | In Gleam both values must be **Int** |
+| Less than | `<` | `<.` | In Gleam both values must be **Float** |
+| Less or equal | `<=` | `<=` | In Gleam both values must be **Int** |
+| Less or equal | `<=` | `<=.` | In Gleam both values must be **Float** |
+| Boolean and | `&&` | `&&` | In Gleam both values must be **Bool** |
+| Logical and | `&&` | | Not available in Gleam |
+| Boolean or | ||
| ||
| In Gleam both values must be **Bool** |
+| Logical or | ||
| | Not available in Gleam |
+| Boolean not | `xor` | | Not available in Gleam |
+| Boolean not | `!` | `!` | In Gleam both values must be **Bool** |
+| Add | `+` | `+` | In Gleam both values must be **Int** |
+| Add | `+` | `+.` | In Gleam both values must be **Float** |
+| Subtract | `-` | `-` | In Gleam both values must be **Int** |
+| Subtract | `-` | `-.` | In Gleam both values must be **Float** |
+| Multiply | `*` | `*` | In Gleam both values must be **Int** |
+| Multiply | `*` | `*.` | In Gleam both values must be **Float** |
+| Divide | `/` | `/` | In Gleam both values must be **Int** |
+| Divide | `/` | `/.` | In Gleam both values must be **Float** |
+| Remainder | `%` | `%` | In Gleam both values must be **Int** |
+| Concatenate | `.` | `<>` | In Gleam both values must be **String**
+| Pipe | `->` | |>
| Gleam's pipe can chain function calls. See note for Go |
+
+### Notes on operators
+
+- For bitwise operators, which exist in Go but not in Gleam,
+ see: .
+- `==` is by default comparing by value in Go:
+ - Types may be autocast to be compareable.
+ - Two objects with the same members values will equal:
+- `===` is for comparing by strict equality in Go:
+ - Types will not be autocast for comparison
+ - Two objects with the same members will not equal. Only if a variable binds
+ to the same reference it will equal.
+- Go operators are short-circuiting as in Gleam.
+- Chains and pipes:
+ - In Go chaining is usually done by constructing class methods that return
+ an object: `$foo->bar(1)->quux(2)` means `bar(1)` is called as a method
+ of `$foo` and then `quux()` is called as a method of the return value
+ (object) of the `bar(1)` call. The objects in this chain usually
+ mutate to keep the changed state and carry it forward in the chain.
+ - In contrast in Gleam piping, no objects are being returned but mere data
+ is pushed from left to right much like in unix tooling.
+
+## Constants
+
+### Go
+
+In Go, constants can only be defined within classes and traits.
+
+```Go
+class TheQuestion {
+ public const theAnswer = 42;
+}
+echo TheQuestion::theAnswer; // 42
+```
+
+### Gleam
+
+In Gleam constants can be created using the `const` keyword.
+
+```gleam
+// the_question.gleam module
+const the_answer = 42
+
+pub fn main() {
+ the_answer
+}
+```
+
+They can also be marked public via the `pub` keyword and will then be
+automatically exported.
+
+## Blocks
+
+### Go
+
+Go blocks are always associated with a function / conditional / loop or
+similar declaration. Blocks are limited to specific language constructs.
+There is no way to create multi-line expressions blocks like in Gleam.
+
+Blocks are declared via curly braces.
+
+```Go
+function a_func() {
+ // A block starts here
+ if ($foo) {
+ // A block here
+ } else {
+ // A block here
+ }
+ // Block continues
+}
+```
+
+### Gleam
+
+In Gleam curly braces, `{` and `}`, are used to group expressions.
+
+```gleam
+pub fn main() {
+ let x = {
+ some_function(1)
+ 2
+ }
+ // Braces are used to change precedence of arithmetic operators
+ let y = x * {x + 10}
+ y
+}
+```
+
+Unlike in Go, in Gleam function blocks are always expressions, so are `case`
+blocks or arithmetic sub groups. Because they are expressions they always
+return a value.
+
+For Gleam the last value in a block's expression is always the value being
+returned from an expression.
+
+## Data types
+
+### Strings
+
+In Go strings are stored as an array of bytes and an integer indicating the
+length of the buffer. Go itself has no information about how those bytes
+translate to characters, leaving that task to the programmer. Go's
+standard library however features a bunch of multi-byte compatible functions
+and conversion functions between UTF-8, ISO-8859-1 and further encodings.
+
+Go strings allow interpolation.
+
+In Gleam all strings are UTF-8 encoded binaries. Gleam strings do not allow
+interpolation, yet. Gleam however offers a `string_builder` via its standard
+library for performant string building.
+
+#### Go
+
+```Go
+$what = 'world';
+'Hellø, world!';
+"Hellø, ${what}!";
+```
+
+#### Gleam
+
+```gleam
+"Hellø, world!"
+```
+
+### Tuples
+
+Tuples are very useful in Gleam as they're the only collection data type that
+allows mixed types in the collection.
+
+#### Go
+
+Go does not really support tuples, but its array type can easily be used to
+mimick tuples. Unpacking can be used to bind a name to a specific value of
+the tuple.
+
+```Go
+$myTuple = ['username', 'password', 10];
+[$_, $pwd, $_] = $myTuple;
+echo $pwd; // "password"
+// Direct index access
+echo $myTuple[0]; // "username"
+```
+
+#### Gleam
+
+```gleam
+let my_tuple = #("username", "password", 10)
+let #(_, pwd, _) = my_tuple
+io.print(pwd) // "password"
+// Direct index access
+io.print(my_tuple.0) // "username"
+```
+
+### Lists
+
+Arrays in Go are allowed to have values of mixed types, but not in Gleam.
+
+#### Go
+
+Go does not feature special syntax for list handling.
+
+```Go
+$list = [2, 3, 4];
+$head = array_slice($list, 0, 1)[0];
+$tail = array_slice($list, 1);
+# $head == 2
+# $tail == [3, 4]
+$arr = array_merge($tail, [1.1]);
+# $arr == [3, 4, 1.1]
+```
+
+#### Gleam
+
+Gleam has a `cons` operator that works for lists destructuring and
+pattern matching. In Gleam lists are immutable so adding and removing elements
+from the start of a list is highly efficient.
+
+```gleam
+let list = [2, 3, 4]
+let list = [1, ..list]
+let [1, second_element, ..] = list
+[1.0, ..list] // compile error, type mismatch
+```
+
+### Maps
+
+In Go, the `array` type also covers maps and can have keys of any type as long as:
+
+- the key type is `null`, an `int`, a `string` or a `bool` (some conversions
+ occur, such as null to `""` and `false` to `0` as well as `true` to `1`
+ and `"1"` to `1`. Float indexes, which are not representing integers
+ indexes are deprecated due to being auto downcast to integers).
+- the key is unique in the dictionary.
+- the values are of any type.
+
+In Gleam, maps can have keys and values of any type, but all keys must be of
+the same type in a given map and all values must be of the same type in a
+given map. The type of key and value can differ from each other.
+
+There is no map literal syntax in Gleam, and you cannot pattern match on a map.
+Maps are generally not used much in Gleam, custom types are more common.
+
+#### Go
+
+```Go
+["key1" => "value1", "key2" => "value2"]
+["key1" => "1", "key2" => 2]
+```
+
+#### Gleam
+
+```gleam
+import gleam/map
+
+map.from_list([#("key1", "value1"), #("key2", "value2")])
+map.from_list([#("key1", "value1"), #("key2", 2)]) // Type error!
+```
+
+### Numbers
+
+Go and Gleam both support `Integer` and `Float`. Integer and Float sizes for
+both depend on the platform: 64-bit or 32-bit hardware and OS and for Gleam
+JavaScript and Erlang.
+
+#### Go
+
+While Go differentiates between integers and floats it automatically converts
+floats and integers for you, removing precision or adding floating point
+decimals.
+
+```Go
+1 / 2 // 0.5
+```
+
+#### Gleam
+
+```gleam
+1 / 2 // 0
+1.5 + 10 // Compile time error
+```
+
+You can use the gleam standard library's `int` and `float` modules to convert
+between floats and integers in various ways including `rounding`, `floor`,
+`ceiling` and many more.
+
+## Flow control
+
+### Case
+
+Case is one of the most used control flow in Gleam. It can be seen as a switch
+statement on steroids. It provides a terse way to match a value type to an
+expression. It is also used to replace `if`/`else` statements.
+
+#### Go
+
+Go features 3 different expressions to achieve similar goals:
+
+- `if`/`else if`/`else` (does not return)
+- `switch`/`case`/`break`/`default` (does not return, does not autobreak)
+- `match` (returns)
+
+```Go
+function http_error_impl_1($status) {
+ if ($status === 400) {
+ return "Bad request";
+ } else if ($status === 404) {
+ return "Not found";
+ } else if ($status === 418) {
+ return "I'm a teapot";
+ } else {
+ return "Internal Server Error";
+ }
+}
+
+function http_error_impl_2($status) {
+ switch ($status) {
+ case "400": // Will work because switch ($status) compares non-strict as in ==
+ return "Bad request";
+ break; // Not strictly required here, but combined with weak typing multiple cases could be executed if break is omitted
+ case 404:
+ return "Not found";
+ break;
+ case 418:
+ return "I'm a teapot";
+ break;
+ default:
+ return "Internal Server Error";
+ }
+}
+
+function http_error_impl_3($status) {
+ return match($status) { // match($status) compares strictly
+ 400 => "Bad request",
+ 404 => "Not found",
+ 418 => "I'm a teapot",
+ default => "Internal Server Error"
+ };
+}
+```
+
+#### Gleam
+
+The case operator is a top level construct in Gleam:
+
+```gleam
+case some_number {
+ 0 -> "Zero"
+ 1 -> "One"
+ 2 -> "Two"
+ n -> "Some other number" // This matches anything
+}
+```
+
+As all expressions the case expression will return the matched value.
+
+They can be used to mimick if/else or if/elseif/else, with the exception that
+any branch must return unlike in Go, where it is possible to mutate a
+variable of the outer block/scope and not return at all.
+
+```gleam
+let is_status_within_4xx = status / 400 == 1
+case status {
+ 400 -> "Bad Request"
+ 404 -> "Not Found"
+ _ if is_status_within_4xx -> "4xx" // This works as of now
+ // status if status / 400 == 1 -> "4xx" // This will work in future versions of Gleam
+ _ -> "I'm not sure"
+}
+```
+
+if/else example:
+
+```gleam
+case is_admin {
+ True -> "allow access"
+ False -> "disallow access"
+}
+```
+
+if/elseif/else example:
+
+```gleam
+case True {
+ _ if is_admin == True -> "allow access"
+ _ if is_confirmed_by_mail == True -> "allow access"
+ _ -> "deny access"
+}
+```
+
+Exhaustiveness checking at compile time, which is in the works, will make
+certain that you must check for all possible values. A lazy and common way is
+to check of expected values and have a catchall clause with a single underscore
+`_`:
+
+```gleam
+case scale {
+ 0 -> "none"
+ 1 -> "one"
+ 2 -> "pair"
+ _ -> "many"
+}
+```
+
+The case operator especially coupled with destructuring to provide native pattern
+matching:
+
+```gleam
+case xs {
+ [] -> "This list is empty"
+ [a] -> "This list has 1 element"
+ [a, b] -> "This list has 2 elements"
+ _other -> "This list has more than 2 elements"
+}
+```
+
+The case operator supports guards:
+
+```gleam
+case xs {
+ [a, b, c] if a >. b && a <=. c -> "ok"
+ _other -> "ko"
+}
+```
+
+...and disjoint union matching:
+
+```gleam
+case number {
+ 2 | 4 | 6 | 8 -> "This is an even number"
+ 1 | 3 | 5 | 7 -> "This is an odd number"
+ _ -> "I'm not sure"
+}
+```
+
+### Piping
+
+In Gleam most functions, if not all, are data first, which means the main data
+value to work on is the first argument. By this convention and the ability to
+specify the argument to pipe into, Gleam allows writing functional, immutable
+code, that reads imperative-style top down, much like unix tools and piping.
+
+#### Go
+
+Go does not offer pipes but it can chain calls by making functions return
+objects which in turn ship with their list of methods.
+
+```Go
+// Imaginary Go code
+(new Session($request))
+ ->authorize()
+ ->setSuccessFlash('Logged in successfully!')
+ ->setFailureFlash('Failed to login!')
+ ->redirectToRequestedUrl();
+```
+
+#### Gleam
+
+```gleam
+// Imaginary Gleam code
+request
+|> session.new()
+|> session.authorize()
+|> flash.set_success_flash('Logged in successfully!')
+|> flash.set_failure_flash('Failed to login!')
+|> response.redirect_to_requested_url()
+```
+
+Despite being similar to read and comprehend, the Go code creates a session
+object, and calls the authorize method of the session object: That session
+object then returns another object, say an `AuthorizedUser` object - you don't
+know by looking at the code what object gets returned. However you know it must
+implement a `setSuccessFlash` method. At the last step of the chain `redirect`
+is called on an object returned from `setFailureFlash`.
+
+In the Gleam code the request data is piped into `session.new()`'s first
+argument and that return value is piped further down. It is readability sugar
+for:
+
+```gleam
+response.redirect_to_requested_url(
+ flash.set_failure_flash(
+ flash.set_success_flash(
+ session.authorize(
+ session.new(request)
+ ),
+ 'Logged in successfully!'
+ ),
+ 'Failed to login!'
+ )
+)
+```
+
+### Try
+
+Error management is approached differently in Go and Gleam.
+
+#### Go
+
+Go uses the notion of exceptions to interrupt the current code flow and
+pop up the error to the caller.
+
+An exception is raised using the keyword `throw`.
+
+```Go
+function aFunctionThatFails() {
+ throw new RuntimeException('an error');
+}
+```
+
+The callee block will be able to capture any exception raised in the block
+using a `try/except` set of blocks:
+
+```Go
+// callee block
+try {
+ echo 'this line will be executed and thus printed';
+ aFunctionThatFails()
+ echo 'this line will not be executed and thus not printed';
+} catch (Throwable $e) {
+ var_dump(['doing something with the exception', $e]);
+}
+```
+
+#### Gleam
+
+In contrast in gleam, errors are just containers with an associated value.
+
+A common container to model an operation result is
+`Result(ReturnType, ErrorType)`.
+
+A `Result` is either:
+
+- an `Error(ErrorValue)`
+- or an `Ok(Data)` record
+
+Handling errors actually means to match the return value against those two
+scenarios, using a case for instance:
+
+```gleam
+case parse_int("123") {
+ Ok(i) -> io.println("We parsed the Int")
+ Error(e) -> io.println("That wasn't an Int")
+}
+```
+
+In order to simplify this construct, we can use the `try` keyword that will:
+
+- either bind a value to the providing name if `Ok(Something)` is matched,
+- or **interrupt the current block's flow** and return `Error(Something)` from
+ the given block.
+
+```gleam
+let a_number = "1"
+let an_error = Error("ouch")
+let another_number = "3"
+
+try int_a_number = parse_int(a_number)
+try attempt_int = parse_int(an_error) // Error will be returned
+try int_another_number = parse_int(another_number) // never gets executed
+
+Ok(int_a_number + attempt_int + int_another_number) // never gets executed
+```
+
+## Type aliases
+
+Type aliases allow for easy referencing of arbitrary complex types.
+Go does not have this feature, though either regular classes or static classes
+can be used to design custom types and class definitions in take can be aliased
+using `class_alias()`.
+
+### Go
+
+A simple variable can store the result of a compound set of types.
+
+```Go
+static class Point {
+ // Can act as an opaque type and utilize Point
+ // Can be class_aliased to Coordinate
+}
+
+static class Triangle {
+ // Can act as an opaque type definition and utilize Point
+}
+```
+
+### Gleam
+
+The `type` keyword can be used to create aliases.
+
+```gleam
+pub type Headers =
+ List(#(String, String))
+```
+
+## Custom types
+
+### Records
+
+Custom type allows you to define a collection data type with a fixed number of
+named fields, and the values in those fields can be of differing types.
+
+#### Go
+
+Go uses classes to define user-defined, record-like types.
+Properties are defined as class members and initial values are generally set in
+the constructor.
+
+By default the constructor does not provide base initializers in the
+constructor so some boilerplate is needed:
+
+```Go
+class Person {
+ public string $name;
+ public int $age;
+ function __construct(string $name, int $age) {
+ $this->name = $name;
+ $this->age = $age;
+ }
+}
+$person = new Person(name: "Joe", age: 40);
+// $person->name // Joe;
+```
+
+#### Gleam
+
+Gleam's custom types can be used as structs. At runtime, they have a tuple
+representation and are compatible with Erlang records (or JavaScript objects).
+
+```gleam
+type Person {
+ Person(name: String, age: Int)
+}
+
+let person = Person(name: "Joe", age: 40)
+let name = person.name
+```
+
+An important difference to note is there is no Java-style object-orientation in
+Gleam, thus methods can not be added to types. However opaque types exist,
+see below.
+
+### Unions
+
+Go generally does not support unions with a few exceptions such as:
+
+- type x or `null`
+- `Array` or `Traversable`.
+
+In Gleam functions must always take and receive one type. To have a union of
+two different types they must be wrapped in a new custom type.
+
+#### Go
+
+```Go
+class Foo {
+ public ?string $aStringOrNull;
+}
+```
+
+#### Gleam
+
+```gleam
+type IntOrFloat {
+ AnInt(Int)
+ AFloat(Float)
+}
+
+fn int_or_float(X) {
+ case X {
+ True -> AnInt(1)
+ False -> AFloat(1.0)
+ }
+}
+```
+
+### Opaque custom types
+
+In Go, constructors can be marked as private and opaque types can either be
+modelled in an immutable way via static classes or in a mutable way via
+a factory pattern.
+
+In Gleam, custom types can be defined as being opaque, which causes the
+constructors for the custom type not to be exported from the module. Without
+any constructors to import other modules can only interact with opaque types
+using the intended API.
+
+#### Go
+
+```Go
+class PointObject
+{
+ private int $x;
+ private int $y;
+
+ private function __construct(int $x, int $y) {
+ $this->x = $x;
+ $this->y = $y;
+ }
+
+ public static function spawn(int $x, int $y) {
+ if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
+ return new self($x, $y);
+ }
+ return false;
+ }
+}
+PointObject::spawn(1, 2); // Returns a Point object
+```
+
+This requires mutation, but prohibits direct property changes.
+
+Go allows to skip object mutation by using static classes:
+
+```Go
+class PointStruct
+{
+ public static function spawn(int $x, int $y) {
+ if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
+ return compact('x', 'y') + ['struct' => __CLASS__];
+ }
+ return false;
+ }
+}
+PointStruct::spawn(1, 2); // Returns an array managed by PointStruct
+```
+
+However Go will in this case not prohibit the direct alteration the returned
+structure, like Gleam's custom types can.
+
+#### Gleam
+
+```gleam
+// In the point.gleam opaque type module:
+pub opaque type Point {
+ Point(x: Int, y: Int)
+}
+
+pub fn spawn(x: Int, y: Int) -> Result(Point, Nil) {
+ case x >= 0 && x <= 99 && y >= 0 && y <= 99 {
+ True -> Ok(Point(x: x, y: y))
+ False -> Error(Nil)
+ }
+}
+
+// In the main.gleam module
+pub fn main() {
+ assert Ok(point) = Point.spawn(1, 2)
+ point
+}
+```
+
+## Modules
+
+### Go
+
+Go does not feature modules, but many other containers such as classes, traits
+and interfaces. Historically a single file can contain many classes, traits and
+interfaces one after another, though it is best practise to only contain one
+such declaration per file.
+
+Using Go namespaces, these can be placed in a registry that does not need to
+map to the source code file system hierarchy, but by convention should.
+
+In `src/Foo/Bar.Go`:
+
+```Go
+// Anything declared in this file will be inside namespace Foo
+namespace Foo;
+
+// Creation of (static) class Bar in Foo, thus as Foo/Bar
+class Bar {
+ public static function identity($x) {
+ return $x;
+ }
+}
+```
+
+Making the static class available in the local scope and calling the function
+`index.Go` (aka Go's main function):
+
+```Go
+// After auto-loading has happened
+use Foo\Bar;
+
+Bar::identity(1) // 1;
+```
+
+### Gleam
+
+Coming from Go the closest thing Go has that are similar to Gleam's modules
+are static classes: Collections of functions and constants grouped into a
+static class.
+
+In comparison Gleam modules can also contain custom types.
+
+A gleam module name corresponds to its file name and path.
+
+Since there is no special syntax to create a module, there can be only one
+module in a file and since there is no way name the module the filename
+always matches the module name which keeps things simple and transparent.
+
+In `/src/foo/bar.gleam`:
+
+```gleam
+// Creation of module function identity
+// in module bar
+pub fn identity(x) {
+ x
+}
+```
+
+Importing the `bar` module and calling a module function:
+
+```gleam
+// In src/main.gleam
+import foo/bar // if foo was in a directory called `lib` the import would be `lib/foo/bar`.
+
+pub fn main() {
+ bar.identity(1) // 1
+}
+```
+
+### Imports
+
+#### Go
+
+Go features ways to load arbitrary Go code: `require`, `include` and
+autoload such as `spl_autoload_register`. Once class pathes are known and
+registered for autoloading, they can brought into the scope of a file by using
+the `use`statement which is part of Go's namespacing.
+Also see .
+
+Inside `src/Nasa/MoonBase.Go`
+
+```Go
+// Makes available src/nasa/RocketShip.Go
+use Nasa\RocketShip;
+
+class MoonBase {
+ public static function exploreSpace() {
+ RocketShip::launch();
+ }
+}
+```
+
+#### Gleam
+
+Imports are relative to the app `src` folder.
+
+Modules in the same directory will need to reference the entire path from `src`
+for the target module, even if the target module is in the same folder.
+
+Inside module `src/nasa/moon_base.gleam`:
+
+```gleam
+// imports module src/nasa/rocket_ship.gleam
+import nasa/rocket_ship
+
+pub fn explore_space() {
+ rocket_ship.launch()
+}
+```
+
+### Named imports
+
+#### Go
+
+Go features namespaces which can be used to rename classes when they clash:
+
+```Go
+// Source files must first be added to the auto-loader
+use Unix\Cat;
+use Animal\Cat as Kitty;
+// Cat and Kitty are available
+```
+
+#### Gleam
+
+Gleam has as similar feature:
+
+```gleam
+import unix/cat
+import animal/cat as kitty
+// cat and kitty are available
+```
+
+This may be useful to differentiate between multiple modules that would have the same default name when imported.
+
+### Unqualified imports
+
+#### Go
+
+```Go
+use Animal\Cat{
+ Cat,
+ function stroke
+};
+```
+
+```Go
+$kitty = new Cat(name: "Nubi");
+stroke($kitty);
+```
+
+#### Gleam
+
+```gleam
+import animal/cat.{
+ Cat,
+ stroke
+}
+
+pub fn main() {
+ let kitty = Cat(name: "Nubi")
+ stroke(kitty)
+}
+```
+
+Importing common types such as `gleam/order.{Lt, Eq, Gt}` or
+`gleam/option.{Some,None}` can be very helpful.
+
+## Architecture
+
+To iterate a few foundational differences:
+
+1. Programming model: Java-style object-orientation VS functional immutable
+ programming
+2. Guarantees: weak dynamic typing VS strong static typing
+3. Runtime model: request-response script VS Erlang/OTP processes
+4. Error handling: exceptions VS result type
+5. Language reach
+
+### Programming model
+
+- Go mixes imperative, Java-style object-orientation and functional code
+ styles. Gleam offers only functional code style, though it can appear
+ imperative and reads easily thanks to pipes.
+- In Gleam, data structures are never mutated but always updated into new
+ structures. This allows processes that fail to simply restart as there are no
+ mutated objects that can be in an invalid state and take the whole
+ application down (such as in Go, Ruby or Go).
+- Gleam offers syntax to make it easy to extract data out of custom types and
+ update data into new copies of custom types without ever mutating variables.
+ Go sometimes directly mutates references of simple values such as when using
+ `reset()` or `end()` or `array_pop()`.
+- Gleam allows to rebind variables freely to make it easy to update data
+ structures by making a copy and binding it to the existing variable.
+- Go features a massive, powerful but inconsistent standard library that is
+ always loaded and partially extended and deprecated with new Go releases.
+- Gleam allows you to opt into a smaller, well polished and consistent standard
+ library.
+
+### Guarantees and types
+
+- Go features opt-in static typing which is only checked at runtime.
+- Go values tend to be automatically cast for comparison purposes or when used
+ as indexes in arrays. Gleam values are not automatically cast.
+- Go allows comparison between most if not all values, even if it does not
+ make any sense say comparing a file `resource` to a `Date` in terms of order.
+ Gleam's comparison operators are very strict and limited, any other
+ comparisons and conversions must happen via function calls.
+- Go's checks happen at runtime, Gleam's checks (for the most part) do not
+ and rely on the compiler to allow only type safe and sound code to be
+ compiled.
+- Gleam's type inference allows you to be lazy for almost all type definitions.
+ Gleam's type system will always assist you in what types are expected and/or
+ conflicting. Gleam's type system will help you discover APIs.
+
+### Runtime model
+
+- Gleam can run on Erlang/BEAM, on the browser but also Deno or NodeJS.
+- For Gleam on Erlang/BEAM the runtime model has some striking similarities
+ in practise: In Go a script starts and runs. It allocates memory for this
+ script and frees it upon end or after the max execution time is exceeded
+ or the memory limit is exceeded.
+- Gleam on Erlang/BEAM allows to processes requests in a similar isolation
+ level that Go offers in contrast to applications running *Go* or *Ruby*.
+ The level of isoluation means that, very similar to Go, if a process
+ crashes (in Go read: if a request crashes) then the supervision system
+ can restart that process or after a while or amount of tries abort
+ repeating restarts on the process with that given input data. This means
+ Erlang/BEAM will yield similar robustness that Go developers are used
+ to and similar isolation guarantuees.
+- When executing Gleam code in fact its compiled Erlang or JavaScript is
+ executed. So in case there are runtime crashes, the crash log will show
+ Erlang (or browser-console/NodeJS/Deno) debug information. In Gleam
+ applications runtime errors should almost never happen but they are harder
+ to read, in Go applications runtime errors much more often and are easier
+ to read.
+
+### Error handling
+
+- Gleam will catch all errors that are expected to happen via the `Result`
+ type. There can however be other errors, such as miss-behavior due
+ accidental to division by 0, crashes on RAM or storage limits, hardware
+ failures, etc. In these cases on the BEAM there are ways to manage these
+ via BEAM's supervision trees.
+- In contrast Go will use exceptions to handle errors and by doing so blurs
+ the line between expected errors and unexpected errors. Also function
+ signatures are enlarged de-facto by whatever exceptions they can throw
+ and thus function calls and return types become much harder to manage.
+
+### Language reach
+
+- Go is tailored towards web applications, servers, and static to low-dynamic
+ frontends.
+- Gleam can be utilized as a JavaScript replacement to drive your frontend
+ application not just your backend web server.
+- Gleam on Erlang/BEAM can be used to write non-blocking, massively concurrent
+ server applications comparable to RabbitMQ or multiplayer game servers.
+ - [Numbers](#numbers)
+- [Flow control](#flow-control)
+ - [Case](#case)
+ - [Piping](#piping)
+ - [Try](#try)
+- [Type aliases](#type-aliases)
+- [Custom types](#custom-types)
+ - [Records](#records)
+ - [Unions](#unions)
+ - [Opaque custom types](#opaque-custom-types)
+- [Modules](#modules)
+ - [Imports](#imports)
+ - [Named imports](#named-imports)
+ - [Unqualified imports](#unqualified-imports)
+- [Architecture](#architecture)
+
+## Comments
+
+### Go
+
+In Go, comments are written with a `//` prefix.
+
+```Go
+// Hello, Joe!
+```
+
+Multi line comments may be written like so:
+
+```Go
+/*
+ * Hello, Joe!
+ */
+```
+
+IN Go, above `trait`, `interface`, `class`, `member`, `function` declarations
+there can be `docblocks` like so:
+
+```Go
+/**
+ * a very special trait.
+ */
+trait Foo {}
+
+/**
+ * A Bar class
+ */
+class Bar {}
+
+/**
+ * A quux function.
+ *
+ * @var string $str String passed to quux
+ * @return string An unprocessed string
+ */
+function quux(string $str) : string { return $str; }
+```
+
+Documentation blocks (docblocks) are extracted into generated API
+documentation.
+
+### Gleam
+
+In Gleam, comments are written with a `//` prefix.
+
+```gleam
+// Hello, Joe!
+```
+
+Comments starting with `///` are used to document the following function,
+constant, or type definition. Comments starting with `////` are used to
+document the current module.
+
+```gleam
+//// This module is very important.
+
+/// The answer to life, the universe, and everything.
+const answer: Int = 42
+
+/// A main function
+fn main() {}
+
+/// A Dog type
+type Dog {
+ Dog(name: String, cuteness: Int)
+}
+```
+
+`//` comments are not used while generating documentation files, while
+`////` and `///` will appear in them.
+
+## Variables
+
+You can rebind variables in both languages.
+
+### Go
+
+```Go
+$size = 50;
+$size = $size + 100;
+$size = 1;
+```
+
+In local scope Go has no specific variable keyword. You choose a name
+and that's it!
+
+In class scope for property declaration Go uses at least one related
+modifier keyword to create properties such as: `public`, `private`,
+`protected`, `static` or `readonly` (`var` is deprecated).
+
+### Gleam
+
+Gleam has the `let` keyword before its variable names.
+
+```gleam
+let size = 50
+let size = size + 100
+let size = 1
+```
+
+### Match operator
+
+#### Go
+
+Go supports basic, one directional destructuring (also called unpacking).
+Tuple of values can be unpacked and inner values can be assigned to left-hand
+variable names.
+
+```Go
+[$a, $b] = [1, 2];
+// $a == 1
+// $b == 2
+
+[1 => $idx2] = ['foo', 'bar', 'quux'];
+// $idx2 == 'bar'
+
+["profession" => $job] = ['name' => 'Joe', 'profession' => 'hacker'];
+// $job == 'hacker'
+```
+
+#### Gleam
+
+In Gleam, `let` and `=` can be used for pattern matching, but you'll get
+compile errors if there's a type mismatch, and a runtime error if there's
+a value mismatch. For assertions, the equivalent `let assert` keyword is
+preferred.
+
+```gleam
+let #(a, _) = #(1, 2)
+// a = 1
+// `_` matches 2 and is discarded
+
+let assert [] = [1] // runtime error
+let assert [y] = "Hello" // compile error, type mismatch
+```
+
+Asserts should be used with caution.
+
+### Variables type annotations
+
+#### Go
+
+Go is a dynamically typed language. Types are only checked at runtime and
+a variable can have different types in its lifetime.
+
+Go gradually introduced more and more type hints that are optional.
+The type information is accessible via `get_type()` at runtime.
+
+These hints will mainly be used to inform static analysis tools like IDEs,
+linters, etc.
+
+```Go
+class Foo {
+ private ?string $bar;
+}
+```
+
+As Go's `array` structure is a combination of maps and arrays.
+The Go manual states that it is an *ordered map*.
+While creating arrays in Go the type of its elements cannot be set explicitly
+and each element can be of a different type:
+
+```Go
+$someList = [1, 2, 3];
+$someTuple = [1, "a", true];
+$someMap = [0 => 1, "foo" => "bar", true => false];
+```
+
+Single variables cannot be type-annotated unless they are `class` or `trait`
+members.
+
+#### Gleam
+
+In Gleam type annotations can optionally be given when binding variables.
+
+```gleam
+let some_list: List(Int) = [1, 2, 3]
+let some_string: String = "Foo"
+```
+
+Gleam will check the type annotation to ensure that it matches the type of the
+assigned value. It does not need annotations to type check your code, but you
+may find it useful to annotate variables to hint to the compiler that you want
+a specific type to be inferred.
+
+## Functions
+
+### Go
+
+In Go, you can define functions with the `function` keyword. One or many `return`
+keywords are optional.
+
+```Go
+function hello($name = 'Joe') : string
+{
+ if ($name = 'Joe') {
+ return 'Welcome back, Joe!';
+ }
+ return "Hello $name";
+}
+
+function noop()
+{
+ // Will automatically return NULL
+}
+```
+
+Anonymous functions returning a single expression can also be defined and be
+bound to variables.
+
+```Go
+$x = 2
+$GoAnonFn = function($y) use ($x) { return $x * $y; }; // Creates a new scope
+$GoAnonFn(2, 3); // 6
+$GoArrowFn = ($x) => $x * $y; // Inherits the outer scope
+$GoArrowFn(2, 3); // 6
+```
+
+### Gleam
+
+Gleam's functions are declared like so:
+
+```gleam
+fn sum(x, y) {
+ x + y
+}
+```
+
+Gleam's anonymous functions have the same basic syntax.
+
+```gleam
+let mul = fn(x, y) { x * y }
+mul(1, 2)
+```
+
+A difference between Go's and Gleam's anonymous functions is that in Go they
+create a new local scope, in Gleam they close over the local scope, aka create
+a copy and inherit all variables in the scope. This means that in Gleam you can
+shadow local variables within anonymous functions but you cannot influence the
+variable bindings in the outer scope. This is different for Go's arrow
+functions where they inherit the scope like Gleam does.
+
+The only difference between module functions and anonymous functions in Gleam
+is that module functions heads may also feature argument labels, like so:
+
+```gleam
+// In some module.gleam
+pub fn distance(from x: Int, to y: Int) : Int {
+ abs(x) - abs(y) |> abs()
+}
+// In some other function
+distance(from: 1, to: -2) // 3
+```
+
+### Exporting functions
+
+#### Go
+
+In Go, top level functions are exported by default. There is no notion of
+private module-level functions.
+
+However at class level, all properties are public, by default.
+
+```Go
+class Foo {
+ static $bar = 5;
+ private $quux = 6;
+
+ static function batz() {
+ return "Hello Joe!";
+ }
+
+ private static function kek() {
+ return "Hello Rasmus!";
+ }
+}
+echo Foo::$bar; // 5
+echo Foo::$quux; // Error
+echo Foo::batz(); // "Hello Joe"
+echo Foo::kek(); // Error
+```
+
+#### Gleam
+
+In Gleam, functions are private by default and need the `pub` keyword to be
+marked as public.
+
+```gleam
+// this is public
+pub fn sum(x, y) {
+ x + y
+}
+
+// this is private
+fn mul(x, y) {
+ x * y
+}
+```
+
+### Go
+
+Global functions may exist in a global scope, and to execute functions or
+create objects and invoke methods at some point they have to be called from
+the global scope. Usually there is one `index.Go` file whose global scope
+acts as if it was the `main()` function.
+
+### Gleam
+
+Gleam does not support a global scope. Instead Gleam code is either
+representing a library, which can be required as a dependency, and/or it
+represents an application having a main module, whose name must match to the
+application name and within that `main()`-function which will be called via
+either `gleam run` or when the `entrypoint.sh` is executed.
+
+In contrast to Go, where any Go file can contain a global scope that can
+be invoked by requiring the file, in Gleam only code that is within functions
+can be invoked.
+
+On the Beam, Gleam code can also be invoked from other Erlang code, or it
+can be invoked from browser's JavaScript, Deno or NodeJS runtime calls.
+
+### Function type annotations
+
+#### Go
+
+Type hints can be used to optionally annotate function arguments and return
+types.
+
+Discrepancies between type hints and actual values at runtime do not prevent
+interpretation of the code. Static code analysers (IDE tooling, type checkers
+like `Gostan`) will be required to detect those errors.
+
+```Go
+function sum(int $x, int $y) : int {
+ return $x + $y;
+}
+
+function mul(int $x, int $y) : bool {
+ # no errors from the interpreter.
+ return $x * $y;
+}
+```
+
+#### Gleam
+
+Functions can **optionally** have their argument and return types annotated in
+Gleam. These type annotations will always be checked by the compiler and throw
+a compilation error if not valid. The compiler will still type check your
+program using type inference if annotations are omitted.
+
+```gleam
+fn add(x: Int, y: Int) -> Int {
+ x + y
+}
+
+fn mul(x: Int, y: Int) -> Bool {
+ x * y // compile error, type mismatch
+}
+```
+
+### Referencing functions
+
+#### Go
+
+As long as functions are in scope they can be assigned to a new variable.
+As methods or static functions classes, functions can be accessed via
+`$this->object_instance_method()` or `self::static_class_function()`.
+
+Other than that only anonymous functions can be moved around the same way as
+other values.
+
+```Go
+$doubleFn = function($x) { return $x + $x; };
+// Some imaginary pushFunction
+pushFunction($queue, $doubleFn);
+```
+
+However in `Go` it is not possible to pass around global, class or instance
+functions as values.
+
+#### Gleam
+
+Gleam has a single namespace for constants and functions within a module, so
+there is no need for a special syntax to assign a module function to a
+variable.
+
+```gleam
+fn identity(x) {
+ x
+}
+
+fn main() {
+ let func = identity
+ func(100)
+}
+```
+
+### Labelled arguments
+
+Both Go and Gleam have ways to give arguments names and in any order.
+
+#### Go
+
+When calling a function, arguments can be passed:
+
+- positionally, in the same order of the function declaration
+- by name, in any order
+
+```Go
+// Some imaginary replace function
+function replace(string $each, string $with, string $inside) {
+ // TODO implementation
+}
+// Calling with positional arguments:
+replace(",", " ", "A,B,C")
+// Calling with named arguments:
+replace(inside: "A,B,C", each: ",", with: " ")
+```
+
+#### Gleam
+
+In Gleam arguments can be given a label as well as an internal name.
+Contrary to Go, the name used at the call-site does not have to match
+the name used for the variable inside the function.
+
+```gleam
+pub fn replace(inside str, each pattern, with replacement) {
+ todo
+}
+```
+
+```gleam
+replace(",", " ", "A,B,C")
+replace(inside: "A,B,C", each: ",", with: " ")
+```
+
+There is no performance cost to Gleam's labelled arguments as they are
+optimised to regular function calls at compile time, and all the arguments
+are fully type checked.
+
+## Operators
+
+| Operator | Go | Gleam | Notes |
+| ------------------ | ------ | ------------------------- | -------------------------------------------------------------------------------------- |
+| Equal | `==` | `==` | In Gleam both values must be of the same type |
+| Strictly equal to | `===` | `==` | Comparison in Gleam is always strict. (see note for Go) |
+| Reference equality | `instanceof` | | True only if an object is an instance of a class |
+| Not equal | `!=` | `!=` | In Gleam both values must be of the same type |
+| Not equal | `!==` | `!=` | Comparison in Gleam is always strict (see note for Go) |
+| Greater than | `>` | `>` | In Gleam both values must be **Int** |
+| Greater than | `>` | `>.` | In Gleam both values must be **Float** |
+| Greater or equal | `>=` | `>=` | In Gleam both values must be **Int** |
+| Greater or equal | `>=` | `>=.` | In Gleam both values must be **Float** |
+| Less than | `<` | `<` | In Gleam both values must be **Int** |
+| Less than | `<` | `<.` | In Gleam both values must be **Float** |
+| Less or equal | `<=` | `<=` | In Gleam both values must be **Int** |
+| Less or equal | `<=` | `<=.` | In Gleam both values must be **Float** |
+| Boolean and | `&&` | `&&` | In Gleam both values must be **Bool** |
+| Logical and | `&&` | | Not available in Gleam |
+| Boolean or | ||
| ||
| In Gleam both values must be **Bool** |
+| Logical or | ||
| | Not available in Gleam |
+| Boolean not | `xor` | | Not available in Gleam |
+| Boolean not | `!` | `!` | In Gleam both values must be **Bool** |
+| Add | `+` | `+` | In Gleam both values must be **Int** |
+| Add | `+` | `+.` | In Gleam both values must be **Float** |
+| Subtract | `-` | `-` | In Gleam both values must be **Int** |
+| Subtract | `-` | `-.` | In Gleam both values must be **Float** |
+| Multiply | `*` | `*` | In Gleam both values must be **Int** |
+| Multiply | `*` | `*.` | In Gleam both values must be **Float** |
+| Divide | `/` | `/` | In Gleam both values must be **Int** |
+| Divide | `/` | `/.` | In Gleam both values must be **Float** |
+| Remainder | `%` | `%` | In Gleam both values must be **Int** |
+| Concatenate | `.` | `<>` | In Gleam both values must be **String**
+| Pipe | `->` | |>
| Gleam's pipe can chain function calls. See note for Go |
+
+### Notes on operators
+
+- For bitwise operators, which exist in Go but not in Gleam,
+ see: .
+- `==` is by default comparing by value in Go:
+ - Types may be autocast to be compareable.
+ - Two objects with the same members values will equal:
+- `===` is for comparing by strict equality in Go:
+ - Types will not be autocast for comparison
+ - Two objects with the same members will not equal. Only if a variable binds
+ to the same reference it will equal.
+- Go operators are short-circuiting as in Gleam.
+- Chains and pipes:
+ - In Go chaining is usually done by constructing class methods that return
+ an object: `$foo->bar(1)->quux(2)` means `bar(1)` is called as a method
+ of `$foo` and then `quux()` is called as a method of the return value
+ (object) of the `bar(1)` call. The objects in this chain usually
+ mutate to keep the changed state and carry it forward in the chain.
+ - In contrast in Gleam piping, no objects are being returned but mere data
+ is pushed from left to right much like in unix tooling.
+
+## Constants
+
+### Go
+
+In Go, constants can only be defined within classes and traits.
+
+```Go
+class TheQuestion {
+ public const theAnswer = 42;
+}
+echo TheQuestion::theAnswer; // 42
+```
+
+### Gleam
+
+In Gleam constants can be created using the `const` keyword.
+
+```gleam
+// the_question.gleam module
+const the_answer = 42
+
+pub fn main() {
+ the_answer
+}
+```
+
+They can also be marked public via the `pub` keyword and will then be
+automatically exported.
+
+## Blocks
+
+### Go
+
+Go blocks are always associated with a function / conditional / loop or
+similar declaration. Blocks are limited to specific language constructs.
+There is no way to create multi-line expressions blocks like in Gleam.
+
+Blocks are declared via curly braces.
+
+```Go
+function a_func() {
+ // A block starts here
+ if ($foo) {
+ // A block here
+ } else {
+ // A block here
+ }
+ // Block continues
+}
+```
+
+### Gleam
+
+In Gleam curly braces, `{` and `}`, are used to group expressions.
+
+```gleam
+pub fn main() {
+ let x = {
+ some_function(1)
+ 2
+ }
+ // Braces are used to change precedence of arithmetic operators
+ let y = x * {x + 10}
+ y
+}
+```
+
+Unlike in Go, in Gleam function blocks are always expressions, so are `case`
+blocks or arithmetic sub groups. Because they are expressions they always
+return a value.
+
+For Gleam the last value in a block's expression is always the value being
+returned from an expression.
+
+## Data types
+
+### Strings
+
+In Go strings are stored as an array of bytes and an integer indicating the
+length of the buffer. Go itself has no information about how those bytes
+translate to characters, leaving that task to the programmer. Go's
+standard library however features a bunch of multi-byte compatible functions
+and conversion functions between UTF-8, ISO-8859-1 and further encodings.
+
+Go strings allow interpolation.
+
+In Gleam all strings are UTF-8 encoded binaries. Gleam strings do not allow
+interpolation, yet. Gleam however offers a `string_builder` via its standard
+library for performant string building.
+
+#### Go
+
+```Go
+$what = 'world';
+'Hellø, world!';
+"Hellø, ${what}!";
+```
+
+#### Gleam
+
+```gleam
+"Hellø, world!"
+```
+
+### Tuples
+
+Tuples are very useful in Gleam as they're the only collection data type that
+allows mixed types in the collection.
+
+#### Go
+
+Go does not really support tuples, but its array type can easily be used to
+mimick tuples. Unpacking can be used to bind a name to a specific value of
+the tuple.
+
+```Go
+$myTuple = ['username', 'password', 10];
+[$_, $pwd, $_] = $myTuple;
+echo $pwd; // "password"
+// Direct index access
+echo $myTuple[0]; // "username"
+```
+
+#### Gleam
+
+```gleam
+let my_tuple = #("username", "password", 10)
+let #(_, pwd, _) = my_tuple
+io.print(pwd) // "password"
+// Direct index access
+io.print(my_tuple.0) // "username"
+```
+
+### Lists
+
+Arrays in Go are allowed to have values of mixed types, but not in Gleam.
+
+#### Go
+
+Go does not feature special syntax for list handling.
+
+```Go
+$list = [2, 3, 4];
+$head = array_slice($list, 0, 1)[0];
+$tail = array_slice($list, 1);
+# $head == 2
+# $tail == [3, 4]
+$arr = array_merge($tail, [1.1]);
+# $arr == [3, 4, 1.1]
+```
+
+#### Gleam
+
+Gleam has a `cons` operator that works for lists destructuring and
+pattern matching. In Gleam lists are immutable so adding and removing elements
+from the start of a list is highly efficient.
+
+```gleam
+let list = [2, 3, 4]
+let list = [1, ..list]
+let [1, second_element, ..] = list
+[1.0, ..list] // compile error, type mismatch
+```
+
+### Maps
+
+In Go, the `array` type also covers maps and can have keys of any type as long as:
+
+- the key type is `null`, an `int`, a `string` or a `bool` (some conversions
+ occur, such as null to `""` and `false` to `0` as well as `true` to `1`
+ and `"1"` to `1`. Float indexes, which are not representing integers
+ indexes are deprecated due to being auto downcast to integers).
+- the key is unique in the dictionary.
+- the values are of any type.
+
+In Gleam, maps can have keys and values of any type, but all keys must be of
+the same type in a given map and all values must be of the same type in a
+given map. The type of key and value can differ from each other.
+
+There is no map literal syntax in Gleam, and you cannot pattern match on a map.
+Maps are generally not used much in Gleam, custom types are more common.
+
+#### Go
+
+```Go
+["key1" => "value1", "key2" => "value2"]
+["key1" => "1", "key2" => 2]
+```
+
+#### Gleam
+
+```gleam
+import gleam/map
+
+map.from_list([#("key1", "value1"), #("key2", "value2")])
+map.from_list([#("key1", "value1"), #("key2", 2)]) // Type error!
+```
+
+### Numbers
+
+Go and Gleam both support `Integer` and `Float`. Integer and Float sizes for
+both depend on the platform: 64-bit or 32-bit hardware and OS and for Gleam
+JavaScript and Erlang.
+
+#### Go
+
+While Go differentiates between integers and floats it automatically converts
+floats and integers for you, removing precision or adding floating point
+decimals.
+
+```Go
+1 / 2 // 0.5
+```
+
+#### Gleam
+
+```gleam
+1 / 2 // 0
+1.5 + 10 // Compile time error
+```
+
+You can use the gleam standard library's `int` and `float` modules to convert
+between floats and integers in various ways including `rounding`, `floor`,
+`ceiling` and many more.
+
+## Flow control
+
+### Case
+
+Case is one of the most used control flow in Gleam. It can be seen as a switch
+statement on steroids. It provides a terse way to match a value type to an
+expression. It is also used to replace `if`/`else` statements.
+
+#### Go
+
+Go features 3 different expressions to achieve similar goals:
+
+- `if`/`else if`/`else` (does not return)
+- `switch`/`case`/`break`/`default` (does not return, does not autobreak)
+- `match` (returns)
+
+```Go
+function http_error_impl_1($status) {
+ if ($status === 400) {
+ return "Bad request";
+ } else if ($status === 404) {
+ return "Not found";
+ } else if ($status === 418) {
+ return "I'm a teapot";
+ } else {
+ return "Internal Server Error";
+ }
+}
+
+function http_error_impl_2($status) {
+ switch ($status) {
+ case "400": // Will work because switch ($status) compares non-strict as in ==
+ return "Bad request";
+ break; // Not strictly required here, but combined with weak typing multiple cases could be executed if break is omitted
+ case 404:
+ return "Not found";
+ break;
+ case 418:
+ return "I'm a teapot";
+ break;
+ default:
+ return "Internal Server Error";
+ }
+}
+
+function http_error_impl_3($status) {
+ return match($status) { // match($status) compares strictly
+ 400 => "Bad request",
+ 404 => "Not found",
+ 418 => "I'm a teapot",
+ default => "Internal Server Error"
+ };
+}
+```
+
+#### Gleam
+
+The case operator is a top level construct in Gleam:
+
+```gleam
+case some_number {
+ 0 -> "Zero"
+ 1 -> "One"
+ 2 -> "Two"
+ n -> "Some other number" // This matches anything
+}
+```
+
+As all expressions the case expression will return the matched value.
+
+They can be used to mimick if/else or if/elseif/else, with the exception that
+any branch must return unlike in Go, where it is possible to mutate a
+variable of the outer block/scope and not return at all.
+
+```gleam
+let is_status_within_4xx = status / 400 == 1
+case status {
+ 400 -> "Bad Request"
+ 404 -> "Not Found"
+ _ if is_status_within_4xx -> "4xx" // This works as of now
+ // status if status / 400 == 1 -> "4xx" // This will work in future versions of Gleam
+ _ -> "I'm not sure"
+}
+```
+
+if/else example:
+
+```gleam
+case is_admin {
+ True -> "allow access"
+ False -> "disallow access"
+}
+```
+
+if/elseif/else example:
+
+```gleam
+case True {
+ _ if is_admin == True -> "allow access"
+ _ if is_confirmed_by_mail == True -> "allow access"
+ _ -> "deny access"
+}
+```
+
+Exhaustiveness checking at compile time, which is in the works, will make
+certain that you must check for all possible values. A lazy and common way is
+to check of expected values and have a catchall clause with a single underscore
+`_`:
+
+```gleam
+case scale {
+ 0 -> "none"
+ 1 -> "one"
+ 2 -> "pair"
+ _ -> "many"
+}
+```
+
+The case operator especially coupled with destructuring to provide native pattern
+matching:
+
+```gleam
+case xs {
+ [] -> "This list is empty"
+ [a] -> "This list has 1 element"
+ [a, b] -> "This list has 2 elements"
+ _other -> "This list has more than 2 elements"
+}
+```
+
+The case operator supports guards:
+
+```gleam
+case xs {
+ [a, b, c] if a >. b && a <=. c -> "ok"
+ _other -> "ko"
+}
+```
+
+...and disjoint union matching:
+
+```gleam
+case number {
+ 2 | 4 | 6 | 8 -> "This is an even number"
+ 1 | 3 | 5 | 7 -> "This is an odd number"
+ _ -> "I'm not sure"
+}
+```
+
+### Piping
+
+In Gleam most functions, if not all, are data first, which means the main data
+value to work on is the first argument. By this convention and the ability to
+specify the argument to pipe into, Gleam allows writing functional, immutable
+code, that reads imperative-style top down, much like unix tools and piping.
+
+#### Go
+
+Go does not offer pipes but it can chain calls by making functions return
+objects which in turn ship with their list of methods.
+
+```Go
+// Imaginary Go code
+(new Session($request))
+ ->authorize()
+ ->setSuccessFlash('Logged in successfully!')
+ ->setFailureFlash('Failed to login!')
+ ->redirectToRequestedUrl();
+```
+
+#### Gleam
+
+```gleam
+// Imaginary Gleam code
+request
+|> session.new()
+|> session.authorize()
+|> flash.set_success_flash('Logged in successfully!')
+|> flash.set_failure_flash('Failed to login!')
+|> response.redirect_to_requested_url()
+```
+
+Despite being similar to read and comprehend, the Go code creates a session
+object, and calls the authorize method of the session object: That session
+object then returns another object, say an `AuthorizedUser` object - you don't
+know by looking at the code what object gets returned. However you know it must
+implement a `setSuccessFlash` method. At the last step of the chain `redirect`
+is called on an object returned from `setFailureFlash`.
+
+In the Gleam code the request data is piped into `session.new()`'s first
+argument and that return value is piped further down. It is readability sugar
+for:
+
+```gleam
+response.redirect_to_requested_url(
+ flash.set_failure_flash(
+ flash.set_success_flash(
+ session.authorize(
+ session.new(request)
+ ),
+ 'Logged in successfully!'
+ ),
+ 'Failed to login!'
+ )
+)
+```
+
+### Try
+
+Error management is approached differently in Go and Gleam.
+
+#### Go
+
+Go uses the notion of exceptions to interrupt the current code flow and
+pop up the error to the caller.
+
+An exception is raised using the keyword `throw`.
+
+```Go
+function aFunctionThatFails() {
+ throw new RuntimeException('an error');
+}
+```
+
+The callee block will be able to capture any exception raised in the block
+using a `try/except` set of blocks:
+
+```Go
+// callee block
+try {
+ echo 'this line will be executed and thus printed';
+ aFunctionThatFails()
+ echo 'this line will not be executed and thus not printed';
+} catch (Throwable $e) {
+ var_dump(['doing something with the exception', $e]);
+}
+```
+
+#### Gleam
+
+In contrast in gleam, errors are just containers with an associated value.
+
+A common container to model an operation result is
+`Result(ReturnType, ErrorType)`.
+
+A `Result` is either:
+
+- an `Error(ErrorValue)`
+- or an `Ok(Data)` record
+
+Handling errors actually means to match the return value against those two
+scenarios, using a case for instance:
+
+```gleam
+case parse_int("123") {
+ Ok(i) -> io.println("We parsed the Int")
+ Error(e) -> io.println("That wasn't an Int")
+}
+```
+
+In order to simplify this construct, we can use the `try` keyword that will:
+
+- either bind a value to the providing name if `Ok(Something)` is matched,
+- or **interrupt the current block's flow** and return `Error(Something)` from
+ the given block.
+
+```gleam
+let a_number = "1"
+let an_error = Error("ouch")
+let another_number = "3"
+
+try int_a_number = parse_int(a_number)
+try attempt_int = parse_int(an_error) // Error will be returned
+try int_another_number = parse_int(another_number) // never gets executed
+
+Ok(int_a_number + attempt_int + int_another_number) // never gets executed
+```
+
+## Type aliases
+
+Type aliases allow for easy referencing of arbitrary complex types.
+Go does not have this feature, though either regular classes or static classes
+can be used to design custom types and class definitions in take can be aliased
+using `class_alias()`.
+
+### Go
+
+A simple variable can store the result of a compound set of types.
+
+```Go
+static class Point {
+ // Can act as an opaque type and utilize Point
+ // Can be class_aliased to Coordinate
+}
+
+static class Triangle {
+ // Can act as an opaque type definition and utilize Point
+}
+```
+
+### Gleam
+
+The `type` keyword can be used to create aliases.
+
+```gleam
+pub type Headers =
+ List(#(String, String))
+```
+
+## Custom types
+
+### Records
+
+Custom type allows you to define a collection data type with a fixed number of
+named fields, and the values in those fields can be of differing types.
+
+#### Go
+
+Go uses classes to define user-defined, record-like types.
+Properties are defined as class members and initial values are generally set in
+the constructor.
+
+By default the constructor does not provide base initializers in the
+constructor so some boilerplate is needed:
+
+```Go
+class Person {
+ public string $name;
+ public int $age;
+ function __construct(string $name, int $age) {
+ $this->name = $name;
+ $this->age = $age;
+ }
+}
+$person = new Person(name: "Joe", age: 40);
+// $person->name // Joe;
+```
+
+#### Gleam
+
+Gleam's custom types can be used as structs. At runtime, they have a tuple
+representation and are compatible with Erlang records (or JavaScript objects).
+
+```gleam
+type Person {
+ Person(name: String, age: Int)
+}
+
+let person = Person(name: "Joe", age: 40)
+let name = person.name
+```
+
+An important difference to note is there is no Java-style object-orientation in
+Gleam, thus methods can not be added to types. However opaque types exist,
+see below.
+
+### Unions
+
+Go generally does not support unions with a few exceptions such as:
+
+- type x or `null`
+- `Array` or `Traversable`.
+
+In Gleam functions must always take and receive one type. To have a union of
+two different types they must be wrapped in a new custom type.
+
+#### Go
+
+```Go
+class Foo {
+ public ?string $aStringOrNull;
+}
+```
+
+#### Gleam
+
+```gleam
+type IntOrFloat {
+ AnInt(Int)
+ AFloat(Float)
+}
+
+fn int_or_float(X) {
+ case X {
+ True -> AnInt(1)
+ False -> AFloat(1.0)
+ }
+}
+```
+
+### Opaque custom types
+
+In Go, constructors can be marked as private and opaque types can either be
+modelled in an immutable way via static classes or in a mutable way via
+a factory pattern.
+
+In Gleam, custom types can be defined as being opaque, which causes the
+constructors for the custom type not to be exported from the module. Without
+any constructors to import other modules can only interact with opaque types
+using the intended API.
+
+#### Go
+
+```Go
+class PointObject
+{
+ private int $x;
+ private int $y;
+
+ private function __construct(int $x, int $y) {
+ $this->x = $x;
+ $this->y = $y;
+ }
+
+ public static function spawn(int $x, int $y) {
+ if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
+ return new self($x, $y);
+ }
+ return false;
+ }
+}
+PointObject::spawn(1, 2); // Returns a Point object
+```
+
+This requires mutation, but prohibits direct property changes.
+
+Go allows to skip object mutation by using static classes:
+
+```Go
+class PointStruct
+{
+ public static function spawn(int $x, int $y) {
+ if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
+ return compact('x', 'y') + ['struct' => __CLASS__];
+ }
+ return false;
+ }
+}
+PointStruct::spawn(1, 2); // Returns an array managed by PointStruct
+```
+
+However Go will in this case not prohibit the direct alteration the returned
+structure, like Gleam's custom types can.
+
+#### Gleam
+
+```gleam
+// In the point.gleam opaque type module:
+pub opaque type Point {
+ Point(x: Int, y: Int)
+}
+
+pub fn spawn(x: Int, y: Int) -> Result(Point, Nil) {
+ case x >= 0 && x <= 99 && y >= 0 && y <= 99 {
+ True -> Ok(Point(x: x, y: y))
+ False -> Error(Nil)
+ }
+}
+
+// In the main.gleam module
+pub fn main() {
+ assert Ok(point) = Point.spawn(1, 2)
+ point
+}
+```
+
+## Modules
+
+### Go
+
+Go does not feature modules, but many other containers such as classes, traits
+and interfaces. Historically a single file can contain many classes, traits and
+interfaces one after another, though it is best practise to only contain one
+such declaration per file.
+
+Using Go namespaces, these can be placed in a registry that does not need to
+map to the source code file system hierarchy, but by convention should.
+
+In `src/Foo/Bar.Go`:
+
+```Go
+// Anything declared in this file will be inside namespace Foo
+namespace Foo;
+
+// Creation of (static) class Bar in Foo, thus as Foo/Bar
+class Bar {
+ public static function identity($x) {
+ return $x;
+ }
+}
+```
+
+Making the static class available in the local scope and calling the function
+`index.Go` (aka Go's main function):
+
+```Go
+// After auto-loading has happened
+use Foo\Bar;
+
+Bar::identity(1) // 1;
+```
+
+### Gleam
+
+Coming from Go the closest thing Go has that are similar to Gleam's modules
+are static classes: Collections of functions and constants grouped into a
+static class.
+
+In comparison Gleam modules can also contain custom types.
+
+A gleam module name corresponds to its file name and path.
+
+Since there is no special syntax to create a module, there can be only one
+module in a file and since there is no way name the module the filename
+always matches the module name which keeps things simple and transparent.
+
+In `/src/foo/bar.gleam`:
+
+```gleam
+// Creation of module function identity
+// in module bar
+pub fn identity(x) {
+ x
+}
+```
+
+Importing the `bar` module and calling a module function:
+
+```gleam
+// In src/main.gleam
+import foo/bar // if foo was in a directory called `lib` the import would be `lib/foo/bar`.
+
+pub fn main() {
+ bar.identity(1) // 1
+}
+```
+
+### Imports
+
+#### Go
+
+Go features ways to load arbitrary Go code: `require`, `include` and
+autoload such as `spl_autoload_register`. Once class pathes are known and
+registered for autoloading, they can brought into the scope of a file by using
+the `use`statement which is part of Go's namespacing.
+Also see .
+
+Inside `src/Nasa/MoonBase.Go`
+
+```Go
+// Makes available src/nasa/RocketShip.Go
+use Nasa\RocketShip;
+
+class MoonBase {
+ public static function exploreSpace() {
+ RocketShip::launch();
+ }
+}
+```
+
+#### Gleam
+
+Imports are relative to the app `src` folder.
+
+Modules in the same directory will need to reference the entire path from `src`
+for the target module, even if the target module is in the same folder.
+
+Inside module `src/nasa/moon_base.gleam`:
+
+```gleam
+// imports module src/nasa/rocket_ship.gleam
+import nasa/rocket_ship
+
+pub fn explore_space() {
+ rocket_ship.launch()
+}
+```
+
+### Named imports
+
+#### Go
+
+Go features namespaces which can be used to rename classes when they clash:
+
+```Go
+// Source files must first be added to the auto-loader
+use Unix\Cat;
+use Animal\Cat as Kitty;
+// Cat and Kitty are available
+```
+
+#### Gleam
+
+Gleam has as similar feature:
+
+```gleam
+import unix/cat
+import animal/cat as kitty
+// cat and kitty are available
+```
+
+This may be useful to differentiate between multiple modules that would have the same default name when imported.
+
+### Unqualified imports
+
+#### Go
+
+```Go
+use Animal\Cat{
+ Cat,
+ function stroke
+};
+```
+
+```Go
+$kitty = new Cat(name: "Nubi");
+stroke($kitty);
+```
+
+#### Gleam
+
+```gleam
+import animal/cat.{
+ Cat,
+ stroke
+}
+
+pub fn main() {
+ let kitty = Cat(name: "Nubi")
+ stroke(kitty)
+}
+```
+
+Importing common types such as `gleam/order.{Lt, Eq, Gt}` or
+`gleam/option.{Some,None}` can be very helpful.
+
+## Architecture
+
+To iterate a few foundational differences:
+
+1. Programming model: Java-style object-orientation VS functional immutable
+ programming
+2. Guarantees: weak dynamic typing VS strong static typing
+3. Runtime model: request-response script VS Erlang/OTP processes
+4. Error handling: exceptions VS result type
+5. Language reach
+
+### Programming model
+
+- Go mixes imperative, Java-style object-orientation and functional code
+ styles. Gleam offers only functional code style, though it can appear
+ imperative and reads easily thanks to pipes.
+- In Gleam, data structures are never mutated but always updated into new
+ structures. This allows processes that fail to simply restart as there are no
+ mutated objects that can be in an invalid state and take the whole
+ application down (such as in Go, Ruby or Go).
+- Gleam offers syntax to make it easy to extract data out of custom types and
+ update data into new copies of custom types without ever mutating variables.
+ Go sometimes directly mutates references of simple values such as when using
+ `reset()` or `end()` or `array_pop()`.
+- Gleam allows to rebind variables freely to make it easy to update data
+ structures by making a copy and binding it to the existing variable.
+- Go features a massive, powerful but inconsistent standard library that is
+ always loaded and partially extended and deprecated with new Go releases.
+- Gleam allows you to opt into a smaller, well polished and consistent standard
+ library.
+
+### Guarantees and types
+
+- Go features opt-in static typing which is only checked at runtime.
+- Go values tend to be automatically cast for comparison purposes or when used
+ as indexes in arrays. Gleam values are not automatically cast.
+- Go allows comparison between most if not all values, even if it does not
+ make any sense say comparing a file `resource` to a `Date` in terms of order.
+ Gleam's comparison operators are very strict and limited, any other
+ comparisons and conversions must happen via function calls.
+- Go's checks happen at runtime, Gleam's checks (for the most part) do not
+ and rely on the compiler to allow only type safe and sound code to be
+ compiled.
+- Gleam's type inference allows you to be lazy for almost all type definitions.
+ Gleam's type system will always assist you in what types are expected and/or
+ conflicting. Gleam's type system will help you discover APIs.
+
+### Runtime model
+
+- Gleam can run on Erlang/BEAM, on the browser but also Deno or NodeJS.
+- For Gleam on Erlang/BEAM the runtime model has some striking similarities
+ in practise: In Go a script starts and runs. It allocates memory for this
+ script and frees it upon end or after the max execution time is exceeded
+ or the memory limit is exceeded.
+- Gleam on Erlang/BEAM allows to processes requests in a similar isolation
+ level that Go offers in contrast to applications running *Go* or *Ruby*.
+ The level of isoluation means that, very similar to Go, if a process
+ crashes (in Go read: if a request crashes) then the supervision system
+ can restart that process or after a while or amount of tries abort
+ repeating restarts on the process with that given input data. This means
+ Erlang/BEAM will yield similar robustness that Go developers are used
+ to and similar isolation guarantuees.
+- When executing Gleam code in fact its compiled Erlang or JavaScript is
+ executed. So in case there are runtime crashes, the crash log will show
+ Erlang (or browser-console/NodeJS/Deno) debug information. In Gleam
+ applications runtime errors should almost never happen but they are harder
+ to read, in Go applications runtime errors much more often and are easier
+ to read.
+
+### Error handling
+
+- Gleam will catch all errors that are expected to happen via the `Result`
+ type. There can however be other errors, such as miss-behavior due
+ accidental to division by 0, crashes on RAM or storage limits, hardware
+ failures, etc. In these cases on the BEAM there are ways to manage these
+ via BEAM's supervision trees.
+- In contrast Go will use exceptions to handle errors and by doing so blurs
+ the line between expected errors and unexpected errors. Also function
+ signatures are enlarged de-facto by whatever exceptions they can throw
+ and thus function calls and return types become much harder to manage.
+
+### Language reach
+
+- Go is tailored towards web applications, servers, and static to low-dynamic
+ frontends.
+- Gleam can be utilized as a JavaScript replacement to drive your frontend
+ application not just your backend web server.
+- Gleam on Erlang/BEAM can be used to write non-blocking, massively concurrent
+ server applications comparable to RabbitMQ or multiplayer game servers.
From c04748c4120df53436a3cd2603bbb45b17da6b93 Mon Sep 17 00:00:00 2001
From: Anthony Bullard <1380687+gamebox@users.noreply.github.com>
Date: Thu, 7 Mar 2024 06:28:08 -0600
Subject: [PATCH 02/10] Update gleam-for-go-users.md
Made a lot of progress...
---
cheatsheets/gleam-for-go-users.md | 389 +++++++++++++-----------------
1 file changed, 166 insertions(+), 223 deletions(-)
diff --git a/cheatsheets/gleam-for-go-users.md b/cheatsheets/gleam-for-go-users.md
index 86a299a1..d69b781f 100644
--- a/cheatsheets/gleam-for-go-users.md
+++ b/cheatsheets/gleam-for-go-users.md
@@ -4,28 +4,6 @@ title: Gleam for Go users
subtitle: Hello Gophers!
---
-- [Comments](#comments)
-- [Variables](#variables)
- - [Match operator](#match-operator)
- - [Variables type annotations](#variables-type-annotations)
-- [Functions](#functions)
- - [Exporting functions](#exporting-functions)
- - [Function type annotations](#function-type-annotations)
- - [Referencing functions](#referencing-functions)
- - [Labelled arguments](#labelled-arguments)
-- [Operators](#operators)
-- [Constants](#constants)
-- [Blocks](#blocks)
-- [Data types](#data-types)
- - [Strings](#strings)
- - [Tuples](#tuples)
- - [Lists](#lists)
- - [Maps](#maps)---
-layout: page
-title: Gleam for Go users
-subtitle: Hello Hypertext crafters!
----
-
- [Comments](#comments)
- [Variables](#variables)
- [Match operator](#match-operator)
@@ -43,21 +21,21 @@ subtitle: Hello Hypertext crafters!
- [Tuples](#tuples)
- [Lists](#lists)
- [Maps](#maps)
- - [Numbers](#numbers)
-- [Flow control](#flow-control)
- - [Case](#case)
- - [Piping](#piping)
- - [Try](#try)
-- [Type aliases](#type-aliases)
-- [Custom types](#custom-types)
- - [Records](#records)
- - [Unions](#unions)
- - [Opaque custom types](#opaque-custom-types)
-- [Modules](#modules)
- - [Imports](#imports)
- - [Named imports](#named-imports)
- - [Unqualified imports](#unqualified-imports)
-- [Architecture](#architecture)
+ - [Numbers](#numbers) IN PROGRESS
+- [Flow control](#flow-control) IN PROGRESS
+ - [Case](#case) IN PROGRESS
+ - [Piping](#piping) IN PROGRESS
+ - [Try](#try) IN PROGRESS
+- [Type aliases](#type-aliases) IN PROGRESS
+- [Custom types](#custom-types) IN PROGRESS
+ - [Records](#records) IN PROGRESS
+ - [Unions](#unions) IN PROGRESS
+ - [Opaque custom types](#opaque-custom-types) IN PROGRESS
+- [Modules](#modules) IN PROGRESS
+ - [Imports](#imports) IN PROGRESS
+ - [Named imports](#named-imports) IN PROGRESS
+ - [Unqualified imports](#unqualified-imports) IN PROGRESS
+- [Architecture](#architecture) IN PROGRESS
## Comments
@@ -185,35 +163,18 @@ Asserts should be used with caution.
#### Go
-Go is a dynamically typed language. Types are only checked at runtime and
-a variable can have different types in its lifetime.
-
-Go gradually introduced more and more type hints that are optional.
-The type information is accessible via `get_type()` at runtime.
-
-These hints will mainly be used to inform static analysis tools like IDEs,
-linters, etc.
+Go is a statically typed language, and type annotations are generally required in most places. The exception is when variables or constants are initialized with a value. Multiple consecutive struct fields or function arguments of the same time can combined their type annotation.
```Go
-class Foo {
- private ?string $bar;
+type Bar struct {
+ field string
+ otherField int
+ x, y float64
}
-```
-
-As Go's `array` structure is a combination of maps and arrays.
-The Go manual states that it is an *ordered map*.
-While creating arrays in Go the type of its elements cannot be set explicitly
-and each element can be of a different type:
-```Go
-$someList = [1, 2, 3];
-$someTuple = [1, "a", true];
-$someMap = [0 => 1, "foo" => "bar", true => false];
+func multipleArgsOfSameType(str string, x, y float64) {}
```
-Single variables cannot be type-annotated unless they are `class` or `trait`
-members.
-
#### Gleam
In Gleam type annotations can optionally be given when binding variables.
@@ -232,33 +193,28 @@ a specific type to be inferred.
### Go
-In Go, you can define functions with the `function` keyword. One or many `return`
-keywords are optional.
+In Go, you can define functions with the `func` keyword. The `return`
+keyword is required if the function has a return value, and optional otherwise.
```Go
-function hello($name = 'Joe') : string
-{
- if ($name = 'Joe') {
- return 'Welcome back, Joe!';
+func hello(name string) string {
+ if name == 'Joe' {
+ return 'Welcome back, Joe!'
}
- return "Hello $name";
+ return "Hello $name"
}
-function noop()
-{
- // Will automatically return NULL
+func noop() {
+ // No return value
}
```
-Anonymous functions returning a single expression can also be defined and be
-bound to variables.
+Anonymous functions can also be defined and be bound to variables.
```Go
-$x = 2
-$GoAnonFn = function($y) use ($x) { return $x * $y; }; // Creates a new scope
-$GoAnonFn(2, 3); // 6
-$GoArrowFn = ($x) => $x * $y; // Inherits the outer scope
-$GoArrowFn(2, 3); // 6
+x := 2
+GoAnonFn := func(y) { return x * y } // Captures x
+GoAnonFn(2, 3) // 6
```
### Gleam
@@ -279,11 +235,11 @@ mul(1, 2)
```
A difference between Go's and Gleam's anonymous functions is that in Go they
-create a new local scope, in Gleam they close over the local scope, aka create
-a copy and inherit all variables in the scope. This means that in Gleam you can
-shadow local variables within anonymous functions but you cannot influence the
-variable bindings in the outer scope. This is different for Go's arrow
-functions where they inherit the scope like Gleam does.
+create a new local scope but inherit the surrounding scope, in Gleam they close
+over the local scope, aka create a copy and inherit all variables in the scope.
+This means that in Gleam you can shadow local variables within anonymous functions
+but you cannot influence the variable bindings in the outer scope. In Go you can
+actually change the values in the outer scope, even if that scope has been returned.
The only difference between module functions and anonymous functions in Gleam
is that module functions heads may also feature argument labels, like so:
@@ -301,28 +257,22 @@ distance(from: 1, to: -2) // 3
#### Go
-In Go, top level functions are exported by default. There is no notion of
-private module-level functions.
-
-However at class level, all properties are public, by default.
+In Go, functions are exported if their name is capitalized, and private to the package otherwise.
```Go
-class Foo {
- static $bar = 5;
- private $quux = 6;
-
- static function batz() {
- return "Hello Joe!";
+func PublicHello(name string) string { // Exported
+ if name == 'Joe' {
+ return 'Welcome back, Joe!'
}
+ return "Hello $name"
+}
- private static function kek() {
- return "Hello Rasmus!";
+func privateHello(name string) string { // Package private
+ if name == 'Joe' {
+ return 'Welcome back, Joe!'
}
+ return "Hello $name"
}
-echo Foo::$bar; // 5
-echo Foo::$quux; // Error
-echo Foo::batz(); // "Hello Joe"
-echo Foo::kek(); // Error
```
#### Gleam
@@ -344,10 +294,12 @@ fn mul(x, y) {
### Go
-Global functions may exist in a global scope, and to execute functions or
-create objects and invoke methods at some point they have to be called from
-the global scope. Usually there is one `index.Go` file whose global scope
-acts as if it was the `main()` function.
+Go does not support a global scope. All variables are scoped to the package
+in which they are defined. A package is all Go files in a single directory,
+so two files in the same package can see all symbols in that package whether
+they are exported or not. This allows for complicated functionality to be
+easily spread across multiple files without worrying about any sort of hard
+boundary between them.
### Gleam
@@ -357,9 +309,7 @@ represents an application having a main module, whose name must match to the
application name and within that `main()`-function which will be called via
either `gleam run` or when the `entrypoint.sh` is executed.
-In contrast to Go, where any Go file can contain a global scope that can
-be invoked by requiring the file, in Gleam only code that is within functions
-can be invoked.
+Like Go, in Gleam only code that is within functions can be invoked.
On the Beam, Gleam code can also be invoked from other Erlang code, or it
can be invoked from browser's JavaScript, Deno or NodeJS runtime calls.
@@ -368,21 +318,17 @@ can be invoked from browser's JavaScript, Deno or NodeJS runtime calls.
#### Go
-Type hints can be used to optionally annotate function arguments and return
-types.
-
-Discrepancies between type hints and actual values at runtime do not prevent
-interpretation of the code. Static code analysers (IDE tooling, type checkers
-like `Gostan`) will be required to detect those errors.
+You are required to annotate function arguments and return types. They will be
+checked by the compiler and the program will fail to build if type checking fails.
+Again, multiple consecutive arugments of the same type can share an annotation.
```Go
-function sum(int $x, int $y) : int {
- return $x + $y;
+func sum(x, y int) int {
+ return x + y
}
-function mul(int $x, int $y) : bool {
- # no errors from the interpreter.
- return $x * $y;
+func mul(x, y int) bool {
+ return x * y // This will be a compile-time error
}
```
@@ -407,21 +353,39 @@ fn mul(x: Int, y: Int) -> Bool {
#### Go
-As long as functions are in scope they can be assigned to a new variable.
-As methods or static functions classes, functions can be accessed via
-`$this->object_instance_method()` or `self::static_class_function()`.
-
-Other than that only anonymous functions can be moved around the same way as
-other values.
+In Go, functions are called the same way, using C style function call syntax.
+Functions are first class values, and can be function arguments and return values.
+You can even return methods - even if the struct the method belongs to a scope that
+has returned.
```Go
-$doubleFn = function($x) { return $x + $x; };
-// Some imaginary pushFunction
-pushFunction($queue, $doubleFn);
-```
+func returnsAFunc() func() {
+ x := 2
+ return func() {
+ x = x + 1
+ fmt.Printf("%d\n", x)
+ }
+}
-However in `Go` it is not possible to pass around global, class or instance
-functions as values.
+type Bar struct {
+ something string
+}
+
+func (b Bar) Func() {
+ fmt.Printf("This bar has %s in something field", b.something)
+}
+
+func returnsAMethod() func() {
+ bar := Bar{"Hello"}
+ return bar.Func
+}
+
+func main() {
+ fn := returnsAFunc()
+ fn()
+ returnsAMethod()()
+}
+```
#### Gleam
@@ -442,31 +406,20 @@ fn main() {
### Labelled arguments
-Both Go and Gleam have ways to give arguments names and in any order.
-
#### Go
-When calling a function, arguments can be passed:
-
-- positionally, in the same order of the function declaration
-- by name, in any order
-
-```Go
-// Some imaginary replace function
-function replace(string $each, string $with, string $inside) {
- // TODO implementation
-}
-// Calling with positional arguments:
-replace(",", " ", "A,B,C")
-// Calling with named arguments:
-replace(inside: "A,B,C", each: ",", with: " ")
-```
+Go has no way to supply arguments out of order or by name. To do so
+would require one of two things:
+- Creating a struct that represents the parameters. Any fields of that
+ struct not explicitly set would default to the zero value of their type.
+- Using the _functional option parameter_ pattern, where the function takes
+ a varargs parameters that is of a interface type that can be created by a
+ number of functions that are available to create values that implement said
+ interface.
#### Gleam
In Gleam arguments can be given a label as well as an internal name.
-Contrary to Go, the name used at the call-site does not have to match
-the name used for the variable inside the function.
```gleam
pub fn replace(inside str, each pattern, with replacement) {
@@ -485,13 +438,11 @@ are fully type checked.
## Operators
-| Operator | Go | Gleam | Notes |
+| Operator | Go | Gleam | Notes |
| ------------------ | ------ | ------------------------- | -------------------------------------------------------------------------------------- |
-| Equal | `==` | `==` | In Gleam both values must be of the same type |
-| Strictly equal to | `===` | `==` | Comparison in Gleam is always strict. (see note for Go) |
+| Equal | `==` | `==` | Both values must be of the same type |
| Reference equality | `instanceof` | | True only if an object is an instance of a class |
| Not equal | `!=` | `!=` | In Gleam both values must be of the same type |
-| Not equal | `!==` | `!=` | Comparison in Gleam is always strict (see note for Go) |
| Greater than | `>` | `>` | In Gleam both values must be **Int** |
| Greater than | `>` | `>.` | In Gleam both values must be **Float** |
| Greater or equal | `>=` | `>=` | In Gleam both values must be **Int** |
@@ -501,9 +452,7 @@ are fully type checked.
| Less or equal | `<=` | `<=` | In Gleam both values must be **Int** |
| Less or equal | `<=` | `<=.` | In Gleam both values must be **Float** |
| Boolean and | `&&` | `&&` | In Gleam both values must be **Bool** |
-| Logical and | `&&` | | Not available in Gleam |
-| Boolean or | ||
| ||
| In Gleam both values must be **Bool** |
-| Logical or | ||
| | Not available in Gleam |
+| Boolean or | ||
| ||
| In Gleam and Go both values must be **Bool** |
| Boolean not | `xor` | | Not available in Gleam |
| Boolean not | `!` | `!` | In Gleam both values must be **Bool** |
| Add | `+` | `+` | In Gleam both values must be **Int** |
@@ -515,43 +464,34 @@ are fully type checked.
| Divide | `/` | `/` | In Gleam both values must be **Int** |
| Divide | `/` | `/.` | In Gleam both values must be **Float** |
| Remainder | `%` | `%` | In Gleam both values must be **Int** |
-| Concatenate | `.` | `<>` | In Gleam both values must be **String**
-| Pipe | `->` | |>
| Gleam's pipe can chain function calls. See note for Go |
+| Concatenate | `+` | `<>` | In Gleam and Go both values must be **String** |
+| Pipe | N/A | |>
| Gleam's pipe can chain function calls. Go does not support this |
### Notes on operators
- For bitwise operators, which exist in Go but not in Gleam,
see: .
-- `==` is by default comparing by value in Go:
- - Types may be autocast to be compareable.
- - Two objects with the same members values will equal:
-- `===` is for comparing by strict equality in Go:
- - Types will not be autocast for comparison
- - Two objects with the same members will not equal. Only if a variable binds
- to the same reference it will equal.
+- `==` is by default comparing value for primtive values, and reference for structs, arrays, and interface values in Go.
+ - In Gleam it is always by value.
- Go operators are short-circuiting as in Gleam.
-- Chains and pipes:
- - In Go chaining is usually done by constructing class methods that return
- an object: `$foo->bar(1)->quux(2)` means `bar(1)` is called as a method
- of `$foo` and then `quux()` is called as a method of the return value
- (object) of the `bar(1)` call. The objects in this chain usually
- mutate to keep the changed state and carry it forward in the chain.
- - In contrast in Gleam piping, no objects are being returned but mere data
- is pushed from left to right much like in unix tooling.
+- In Go, all the arithmetic operators must have both arguments be of the same type, so `int` and `int32` values must be converted to one common type.
## Constants
### Go
-In Go, constants can only be defined within classes and traits.
+In Go, constants can only be defined at the top level of any file.
```Go
-class TheQuestion {
- public const theAnswer = 42;
+const theAnswer int = 42
+
+func main() {
+ fmt.Printf("%d\n", theAnswer) // 42
}
-echo TheQuestion::theAnswer; // 42
```
+They are exported by capitalizing it's name.
+
### Gleam
In Gleam constants can be created using the `const` keyword.
@@ -574,14 +514,15 @@ automatically exported.
Go blocks are always associated with a function / conditional / loop or
similar declaration. Blocks are limited to specific language constructs.
-There is no way to create multi-line expressions blocks like in Gleam.
+You can create an arbitrary block as well, but it is not an expression
+like in Gleam.
Blocks are declared via curly braces.
```Go
-function a_func() {
+func aFunc() {
// A block starts here
- if ($foo) {
+ if foo {
// A block here
} else {
// A block here
@@ -617,13 +558,13 @@ returned from an expression.
### Strings
-In Go strings are stored as an array of bytes and an integer indicating the
-length of the buffer. Go itself has no information about how those bytes
-translate to characters, leaving that task to the programmer. Go's
-standard library however features a bunch of multi-byte compatible functions
-and conversion functions between UTF-8, ISO-8859-1 and further encodings.
-
-Go strings allow interpolation.
+In Go strings are slices (dynamically sized arrays) of bytes. Those bytes are
+arbitrary, and are not required to contain Unicode or any other string encoding.
+Go's standard library however has extensive support for string operations. Strings
+can be built efficiently with a `StringBuilder` type from the `strings` package in
+the standard library. Interpolation can be accomplished using `Sprintf` and other
+similar functions found in `fmt` package amongst others in the standard library.
+This uses C `strfmt` style format strings that are statically checked at compile time.
In Gleam all strings are UTF-8 encoded binaries. Gleam strings do not allow
interpolation, yet. Gleam however offers a `string_builder` via its standard
@@ -632,9 +573,9 @@ library for performant string building.
#### Go
```Go
-$what = 'world';
-'Hellø, world!';
-"Hellø, ${what}!";
+what := "world"
+"Hellø, world!"
+fmt.Sprintf("Hellø, %d!", what);
```
#### Gleam
@@ -650,16 +591,26 @@ allows mixed types in the collection.
#### Go
-Go does not really support tuples, but its array type can easily be used to
-mimick tuples. Unpacking can be used to bind a name to a specific value of
-the tuple.
+Go does not support tuples. It does however support multiple return values, and
+anonymous struct types.
-```Go
-$myTuple = ['username', 'password', 10];
-[$_, $pwd, $_] = $myTuple;
-echo $pwd; // "password"
-// Direct index access
-echo $myTuple[0]; // "username"
+```go
+myTuple := struct{ username, pwd string; age int }{ "username", "password", 10 }
+pwd := myTuple.pwd
+fmt.Print(pwd)
+fmt.Print(myTuple.pwd)
+```
+
+```go
+// This is not idiomatic Go!
+func returnUserInfo() (string, string, int) {
+ return "username", "password", 10
+}
+
+func main() {
+ _, pwd, _ := returnUserInfo()
+ fmt.Print(pwd)
+}
```
#### Gleam
@@ -674,22 +625,25 @@ io.print(my_tuple.0) // "username"
### Lists
-Arrays in Go are allowed to have values of mixed types, but not in Gleam.
+Go and Gleam have very different data structures for representing an ordered
+collection of elements of the same type.
#### Go
-Go does not feature special syntax for list handling.
+Go has both arrays - that are statically sized - and slices - that are growable
+and dynamically sized. They have a type declared when constructed
```Go
-$list = [2, 3, 4];
-$head = array_slice($list, 0, 1)[0];
-$tail = array_slice($list, 1);
-# $head == 2
-# $tail == [3, 4]
-$arr = array_merge($tail, [1.1]);
-# $arr == [3, 4, 1.1]
+array := [3]int{ 2, 3, 4 }
+slice := []int{ 2, 3, 4 }
+slice = append(slice, 5, 6) // Adds 5 and 6 to the slice
```
+Slices have some unique concerns as regards to references as if you append to
+a slice, the underlying array may no longer be in the same memory location as
+it was before and some mutative operations can have unexpected behavior for the
+unpracticed (or even experienced) Gopher.
+
#### Gleam
Gleam has a `cons` operator that works for lists destructuring and
@@ -705,27 +659,16 @@ let [1, second_element, ..] = list
### Maps
-In Go, the `array` type also covers maps and can have keys of any type as long as:
-
-- the key type is `null`, an `int`, a `string` or a `bool` (some conversions
- occur, such as null to `""` and `false` to `0` as well as `true` to `1`
- and `"1"` to `1`. Float indexes, which are not representing integers
- indexes are deprecated due to being auto downcast to integers).
-- the key is unique in the dictionary.
-- the values are of any type.
-
-In Gleam, maps can have keys and values of any type, but all keys must be of
-the same type in a given map and all values must be of the same type in a
-given map. The type of key and value can differ from each other.
-
-There is no map literal syntax in Gleam, and you cannot pattern match on a map.
-Maps are generally not used much in Gleam, custom types are more common.
+Maps are similar in Go and Gleam, except that they are mutated in Go and
+immutable in Gleam.
#### Go
```Go
-["key1" => "value1", "key2" => "value2"]
-["key1" => "1", "key2" => 2]
+myMap := map[string]string{
+ "key1": "value1"
+}
+fmt.Print(myMap["key1"])
```
#### Gleam
From ad4c1ef7acddb00f8e9a3229053798ace5ff307a Mon Sep 17 00:00:00 2001
From: Anthony Bullard <1380687+gamebox@users.noreply.github.com>
Date: Thu, 7 Mar 2024 09:01:22 -0600
Subject: [PATCH 03/10] More progress
---
cheatsheets/gleam-for-go-users.md | 82 +++++++++++++------------------
1 file changed, 34 insertions(+), 48 deletions(-)
diff --git a/cheatsheets/gleam-for-go-users.md b/cheatsheets/gleam-for-go-users.md
index d69b781f..414f05e2 100644
--- a/cheatsheets/gleam-for-go-users.md
+++ b/cheatsheets/gleam-for-go-users.md
@@ -21,9 +21,9 @@ subtitle: Hello Gophers!
- [Tuples](#tuples)
- [Lists](#lists)
- [Maps](#maps)
- - [Numbers](#numbers) IN PROGRESS
-- [Flow control](#flow-control) IN PROGRESS
- - [Case](#case) IN PROGRESS
+ - [Numbers](#numbers)
+- [Flow control](#flow-control)
+ - [Case](#case)
- [Piping](#piping) IN PROGRESS
- [Try](#try) IN PROGRESS
- [Type aliases](#type-aliases) IN PROGRESS
@@ -682,18 +682,20 @@ map.from_list([#("key1", "value1"), #("key2", 2)]) // Type error!
### Numbers
-Go and Gleam both support `Integer` and `Float`. Integer and Float sizes for
-both depend on the platform: 64-bit or 32-bit hardware and OS and for Gleam
-JavaScript and Erlang.
+Go and Gleam both support platform-dependent sized integer and float types.
+`Integer` and `Float` in Gleam and `int` and `float` in Go sizes for both depend
+on the platform: 64-bit or 32-bit hardware and OS and for Gleam JavaScript and Erlang.
#### Go
-While Go differentiates between integers and floats it automatically converts
-floats and integers for you, removing precision or adding floating point
-decimals.
+In Go ints and float are distinct types and there is no automatic type coercion.
+You must explicitly convert between even different sized ints and floats
```Go
-1 / 2 // 0.5
+var x int32 = 2
+var y int = 22
+x + y // Will not compile
+x + int32(int) // Will compile
```
#### Gleam
@@ -717,49 +719,36 @@ expression. It is also used to replace `if`/`else` statements.
#### Go
-Go features 3 different expressions to achieve similar goals:
+Go features 2 different expressions to achieve similar goals:
-- `if`/`else if`/`else` (does not return)
-- `switch`/`case`/`break`/`default` (does not return, does not autobreak)
-- `match` (returns)
+- `if`/`else if`/`else`
+- `switch`/`case`/`default`
```Go
-function http_error_impl_1($status) {
- if ($status === 400) {
- return "Bad request";
- } else if ($status === 404) {
- return "Not found";
- } else if ($status === 418) {
- return "I'm a teapot";
+func httpErrorImpl1(status int) string {
+ if status == 400 {
+ return "Bad request"
+ } else if status == 404 {
+ return "Not found"
+ } else if status == 418 {
+ return "I'm a teapot"
} else {
- return "Internal Server Error";
+ return "Internal Server Error"
}
}
-function http_error_impl_2($status) {
- switch ($status) {
- case "400": // Will work because switch ($status) compares non-strict as in ==
- return "Bad request";
- break; // Not strictly required here, but combined with weak typing multiple cases could be executed if break is omitted
+func httpErrorImpl2(status int) string {
+ switch (status) {
+ case 400:
+ return "Bad request"
case 404:
- return "Not found";
- break;
+ return "Not found"
case 418:
- return "I'm a teapot";
- break;
+ return "I'm a teapot"
default:
- return "Internal Server Error";
+ return "Internal Server Error"
}
}
-
-function http_error_impl_3($status) {
- return match($status) { // match($status) compares strictly
- 400 => "Bad request",
- 404 => "Not found",
- 418 => "I'm a teapot",
- default => "Internal Server Error"
- };
-}
```
#### Gleam
@@ -865,16 +854,13 @@ code, that reads imperative-style top down, much like unix tools and piping.
#### Go
-Go does not offer pipes but it can chain calls by making functions return
-objects which in turn ship with their list of methods.
+Go does not offer pipes but if a method returns a type that has methods, they
+can be chained. These sort of methods are not idiomatic in Go and not seen
+often.
```Go
// Imaginary Go code
-(new Session($request))
- ->authorize()
- ->setSuccessFlash('Logged in successfully!')
- ->setFailureFlash('Failed to login!')
- ->redirectToRequestedUrl();
+// TODO: Pick up here!
```
#### Gleam
From cf1bbf6b166454629f801911b12ecf245626bdcc Mon Sep 17 00:00:00 2001
From: Anthony Bullard <1380687+gamebox@users.noreply.github.com>
Date: Fri, 8 Mar 2024 06:57:00 -0600
Subject: [PATCH 04/10] More progress
---
cheatsheets/gleam-for-go-users.md | 148 +++++++++++++++++++-----------
1 file changed, 92 insertions(+), 56 deletions(-)
diff --git a/cheatsheets/gleam-for-go-users.md b/cheatsheets/gleam-for-go-users.md
index 414f05e2..042ee4d8 100644
--- a/cheatsheets/gleam-for-go-users.md
+++ b/cheatsheets/gleam-for-go-users.md
@@ -24,11 +24,11 @@ subtitle: Hello Gophers!
- [Numbers](#numbers)
- [Flow control](#flow-control)
- [Case](#case)
- - [Piping](#piping) IN PROGRESS
- - [Try](#try) IN PROGRESS
-- [Type aliases](#type-aliases) IN PROGRESS
-- [Custom types](#custom-types) IN PROGRESS
- - [Records](#records) IN PROGRESS
+ - [Piping](#piping)
+ - [Error Handling](#error-handling)
+- [Type aliases](#type-aliases)
+- [Custom types](#custom-types)
+ - [Records](#records)
- [Unions](#unions) IN PROGRESS
- [Opaque custom types](#opaque-custom-types) IN PROGRESS
- [Modules](#modules) IN PROGRESS
@@ -900,37 +900,37 @@ response.redirect_to_requested_url(
)
```
-### Try
+### Error handling
-Error management is approached differently in Go and Gleam.
+Error management is approached slightly differently in Go and Gleam.
#### Go
-Go uses the notion of exceptions to interrupt the current code flow and
-pop up the error to the caller.
-
-An exception is raised using the keyword `throw`.
-
+Idiomatic error handling in Go revolves around Error values. Coupled with Go's
+support for multiple return values creates a very straightforward pattern
+for error handling that almost defines the Go experience.
```Go
-function aFunctionThatFails() {
- throw new RuntimeException('an error');
+func aFunctionThatFails() error {
+ return errors.New("This is an error")
}
```
-The callee block will be able to capture any exception raised in the block
-using a `try/except` set of blocks:
+The callee just needs to check that the err value is nil.
```Go
// callee block
-try {
- echo 'this line will be executed and thus printed';
- aFunctionThatFails()
- echo 'this line will not be executed and thus not printed';
-} catch (Throwable $e) {
- var_dump(['doing something with the exception', $e]);
+err := aFunctionThatFails()
+if err != nil {
+ // Handle err
}
+// Continue
```
+Go also has panics to signal that an error was so extraordinary, the state
+of the current goroutine should not continue execution. Panics can be recovered
+from, but this should only happen at a high level and only if it makes sense to
+recover.
+
#### Gleam
In contrast in gleam, errors are just containers with an associated value.
@@ -973,24 +973,16 @@ Ok(int_a_number + attempt_int + int_another_number) // never gets executed
## Type aliases
-Type aliases allow for easy referencing of arbitrary complex types.
-Go does not have this feature, though either regular classes or static classes
-can be used to design custom types and class definitions in take can be aliased
-using `class_alias()`.
+Type aliases allow for easy referencing of arbitrary complex types. They are
+supported by both Gleam and Go.
### Go
-A simple variable can store the result of a compound set of types.
-
-```Go
-static class Point {
- // Can act as an opaque type and utilize Point
- // Can be class_aliased to Coordinate
-}
+Type aliases in Go allow an Identifier to refer to a different type with it's
+scope.
-static class Triangle {
- // Can act as an opaque type definition and utilize Point
-}
+```go
+type Headers = []struct{key, value string}
```
### Gleam
@@ -1011,24 +1003,29 @@ named fields, and the values in those fields can be of differing types.
#### Go
-Go uses classes to define user-defined, record-like types.
-Properties are defined as class members and initial values are generally set in
-the constructor.
+Go uses structs to define user-defined, record-like types.
+Properties are defined as fields and initial values are generally set in
+the literal form. Any unset fields during construction are defaulted to
+their zero value.
-By default the constructor does not provide base initializers in the
-constructor so some boilerplate is needed:
+Go does not use constructors, but many Go developers will create one or more
+functions to construct a struct in an ergonomic way.
```Go
-class Person {
- public string $name;
- public int $age;
- function __construct(string $name, int $age) {
- $this->name = $name;
- $this->age = $age;
- }
+type Person struct {
+ name string
+ age int
}
-$person = new Person(name: "Joe", age: 40);
-// $person->name // Joe;
+
+func NewPerson(name string, age int) Person {
+ return Person{ name, age } // Short hand literal construction
+ // Could also be done with
+ // return Person { name: name, age: age }
+}
+
+// Inside of a function
+person := NewPerson("Joe", 40);
+person.name // Joe;
```
#### Gleam
@@ -1051,22 +1048,61 @@ see below.
### Unions
-Go generally does not support unions with a few exceptions such as:
-
-- type x or `null`
-- `Array` or `Traversable`.
+Go generally does not support unions, with a small exception to that.
In Gleam functions must always take and receive one type. To have a union of
two different types they must be wrapped in a new custom type.
#### Go
+Generally the usecase of wanting to use multiple concrete types is solved with
+Interfaces.
+
```Go
-class Foo {
- public ?string $aStringOrNull;
+type Stringer interface {
+ String() string // Types must have a function with this signature defined
+}
+
+type StructA struct {
+ name string
+ age int
+}
+
+func (s StructA) String() string { // This method fulfills the Stringer interface
+ return fmt.Sprintf("%s,%d", s.name, s.age)
+}
+
+type StructB struct {
+ x int
+ y int
+}
+
+func (s StructB) String() string { // This method fulfills the Stringer interface
+ return fmt.Sprintf("%d,%d", s.x, s.y)
+}
+
+func print(str Stringer) {
+ fmt.Print(str.String())
+}
+
+func main() {
+ print(StructA{ "Bob", 47}) // Prints Bob,47
+ print(StructB{ 42,0 }) // Prints 42,0
+}
+```
+
+The only place where Go uses something related to true unions or sum types is in Type Sets,
+which are constraints on a Generic.
+
+```go
+type Num interface {
+ int | float
}
```
+Unfortunately, these unions provide little value to the Go Developer due to their
+constraints.
+
#### Gleam
```gleam
From 7feaba3104d841867de8233bb4a791b160fdc7e2 Mon Sep 17 00:00:00 2001
From: Anthony Bullard <1380687+gamebox@users.noreply.github.com>
Date: Fri, 8 Mar 2024 09:23:27 -0600
Subject: [PATCH 05/10] Finish first draft
---
cheatsheets/gleam-for-go-users.md | 6178 +----------------------------
1 file changed, 128 insertions(+), 6050 deletions(-)
diff --git a/cheatsheets/gleam-for-go-users.md b/cheatsheets/gleam-for-go-users.md
index 042ee4d8..549cff2a 100644
--- a/cheatsheets/gleam-for-go-users.md
+++ b/cheatsheets/gleam-for-go-users.md
@@ -1121,9 +1121,9 @@ fn int_or_float(X) {
### Opaque custom types
-In Go, constructors can be marked as private and opaque types can either be
-modelled in an immutable way via static classes or in a mutable way via
-a factory pattern.
+In Go, you can choose to not export a type and then they will be considered
+opaque to the user of your package. Just have the type have a lowercase
+identifier.
In Gleam, custom types can be defined as being opaque, which causes the
constructors for the custom type not to be exported from the module. Without
@@ -1133,5972 +1133,28 @@ using the intended API.
#### Go
```Go
-class PointObject
-{
- private int $x;
- private int $y;
-
- private function __construct(int $x, int $y) {
- $this->x = $x;
- $this->y = $y;
- }
-
- public static function spawn(int $x, int $y) {
- if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
- return new self($x, $y);
- }
- return false;
- }
-}
-PointObject::spawn(1, 2); // Returns a Point object
-```
-
-This requires mutation, but prohibits direct property changes.
-
-Go allows to skip object mutation by using static classes:
-
-```Go
-class PointStruct
-{
- public static function spawn(int $x, int $y) {
- if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
- return compact('x', 'y') + ['struct' => __CLASS__];
- }
- return false;
- }
-}
-PointStruct::spawn(1, 2); // Returns an array managed by PointStruct
-```
-
-However Go will in this case not prohibit the direct alteration the returned
-structure, like Gleam's custom types can.
-
-#### Gleam
-
-```gleam
-// In the point.gleam opaque type module:
-pub opaque type Point {
- Point(x: Int, y: Int)
-}
-
-pub fn spawn(x: Int, y: Int) -> Result(Point, Nil) {
- case x >= 0 && x <= 99 && y >= 0 && y <= 99 {
- True -> Ok(Point(x: x, y: y))
- False -> Error(Nil)
- }
-}
-
-// In the main.gleam module
-pub fn main() {
- assert Ok(point) = Point.spawn(1, 2)
- point
-}
-```
-
-## Modules
-
-### Go
-
-Go does not feature modules, but many other containers such as classes, traits
-and interfaces. Historically a single file can contain many classes, traits and
-interfaces one after another, though it is best practise to only contain one
-such declaration per file.
-
-Using Go namespaces, these can be placed in a registry that does not need to
-map to the source code file system hierarchy, but by convention should.
-
-In `src/Foo/Bar.Go`:
-
-```Go
-// Anything declared in this file will be inside namespace Foo
-namespace Foo;
-
-// Creation of (static) class Bar in Foo, thus as Foo/Bar
-class Bar {
- public static function identity($x) {
- return $x;
- }
-}
-```
-
-Making the static class available in the local scope and calling the function
-`index.Go` (aka Go's main function):
-
-```Go
-// After auto-loading has happened
-use Foo\Bar;
-
-Bar::identity(1) // 1;
-```
-
-### Gleam
-
-Coming from Go the closest thing Go has that are similar to Gleam's modules
-are static classes: Collections of functions and constants grouped into a
-static class.
-
-In comparison Gleam modules can also contain custom types.
-
-A gleam module name corresponds to its file name and path.
-
-Since there is no special syntax to create a module, there can be only one
-module in a file and since there is no way name the module the filename
-always matches the module name which keeps things simple and transparent.
-
-In `/src/foo/bar.gleam`:
-
-```gleam
-// Creation of module function identity
-// in module bar
-pub fn identity(x) {
- x
-}
-```
-
-Importing the `bar` module and calling a module function:
-
-```gleam
-// In src/main.gleam
-import foo/bar // if foo was in a directory called `lib` the import would be `lib/foo/bar`.
-
-pub fn main() {
- bar.identity(1) // 1
-}
-```
-
-### Imports
-
-#### Go
-
-Go features ways to load arbitrary Go code: `require`, `include` and
-autoload such as `spl_autoload_register`. Once class pathes are known and
-registered for autoloading, they can brought into the scope of a file by using
-the `use`statement which is part of Go's namespacing.
-Also see .
-
-Inside `src/Nasa/MoonBase.Go`
-
-```Go
-// Makes available src/nasa/RocketShip.Go
-use Nasa\RocketShip;
-
-class MoonBase {
- public static function exploreSpace() {
- RocketShip::launch();
- }
-}
-```
-
-#### Gleam
-
-Imports are relative to the app `src` folder.
-
-Modules in the same directory will need to reference the entire path from `src`
-for the target module, even if the target module is in the same folder.
-
-Inside module `src/nasa/moon_base.gleam`:
-
-```gleam
-// imports module src/nasa/rocket_ship.gleam
-import nasa/rocket_ship
-
-pub fn explore_space() {
- rocket_ship.launch()
-}
-```
-
-### Named imports
-
-#### Go
-
-Go features namespaces which can be used to rename classes when they clash:
-
-```Go
-// Source files must first be added to the auto-loader
-use Unix\Cat;
-use Animal\Cat as Kitty;
-// Cat and Kitty are available
-```
-
-#### Gleam
-
-Gleam has as similar feature:
-
-```gleam
-import unix/cat
-import animal/cat as kitty
-// cat and kitty are available
-```
-
-This may be useful to differentiate between multiple modules that would have the same default name when imported.
-
-### Unqualified imports
-
-#### Go
-
-```Go
-use Animal\Cat{
- Cat,
- function stroke
-};
-```
-
-```Go
-$kitty = new Cat(name: "Nubi");
-stroke($kitty);
-```
-
-#### Gleam
-
-```gleam
-import animal/cat.{
- Cat,
- stroke
-}
-
-pub fn main() {
- let kitty = Cat(name: "Nubi")
- stroke(kitty)
-}
-```
-
-Importing common types such as `gleam/order.{Lt, Eq, Gt}` or
-`gleam/option.{Some,None}` can be very helpful.
-
-## Architecture
-
-To iterate a few foundational differences:
-
-1. Programming model: Java-style object-orientation VS functional immutable
- programming
-2. Guarantees: weak dynamic typing VS strong static typing
-3. Runtime model: request-response script VS Erlang/OTP processes
-4. Error handling: exceptions VS result type
-5. Language reach
-
-### Programming model
-
-- Go mixes imperative, Java-style object-orientation and functional code
- styles. Gleam offers only functional code style, though it can appear
- imperative and reads easily thanks to pipes.
-- In Gleam, data structures are never mutated but always updated into new
- structures. This allows processes that fail to simply restart as there are no
- mutated objects that can be in an invalid state and take the whole
- application down (such as in Go, Ruby or Go).
-- Gleam offers syntax to make it easy to extract data out of custom types and
- update data into new copies of custom types without ever mutating variables.
- Go sometimes directly mutates references of simple values such as when using
- `reset()` or `end()` or `array_pop()`.
-- Gleam allows to rebind variables freely to make it easy to update data
- structures by making a copy and binding it to the existing variable.
-- Go features a massive, powerful but inconsistent standard library that is
- always loaded and partially extended and deprecated with new Go releases.
-- Gleam allows you to opt into a smaller, well polished and consistent standard
- library.
-
-### Guarantees and types
-
-- Go features opt-in static typing which is only checked at runtime.
-- Go values tend to be automatically cast for comparison purposes or when used
- as indexes in arrays. Gleam values are not automatically cast.
-- Go allows comparison between most if not all values, even if it does not
- make any sense say comparing a file `resource` to a `Date` in terms of order.
- Gleam's comparison operators are very strict and limited, any other
- comparisons and conversions must happen via function calls.
-- Go's checks happen at runtime, Gleam's checks (for the most part) do not
- and rely on the compiler to allow only type safe and sound code to be
- compiled.
-- Gleam's type inference allows you to be lazy for almost all type definitions.
- Gleam's type system will always assist you in what types are expected and/or
- conflicting. Gleam's type system will help you discover APIs.
-
-### Runtime model
-
-- Gleam can run on Erlang/BEAM, on the browser but also Deno or NodeJS.
-- For Gleam on Erlang/BEAM the runtime model has some striking similarities
- in practise: In Go a script starts and runs. It allocates memory for this
- script and frees it upon end or after the max execution time is exceeded
- or the memory limit is exceeded.
-- Gleam on Erlang/BEAM allows to processes requests in a similar isolation
- level that Go offers in contrast to applications running *Go* or *Ruby*.
- The level of isoluation means that, very similar to Go, if a process
- crashes (in Go read: if a request crashes) then the supervision system
- can restart that process or after a while or amount of tries abort
- repeating restarts on the process with that given input data. This means
- Erlang/BEAM will yield similar robustness that Go developers are used
- to and similar isolation guarantuees.
-- When executing Gleam code in fact its compiled Erlang or JavaScript is
- executed. So in case there are runtime crashes, the crash log will show
- Erlang (or browser-console/NodeJS/Deno) debug information. In Gleam
- applications runtime errors should almost never happen but they are harder
- to read, in Go applications runtime errors much more often and are easier
- to read.
-
-### Error handling
-
-- Gleam will catch all errors that are expected to happen via the `Result`
- type. There can however be other errors, such as miss-behavior due
- accidental to division by 0, crashes on RAM or storage limits, hardware
- failures, etc. In these cases on the BEAM there are ways to manage these
- via BEAM's supervision trees.
-- In contrast Go will use exceptions to handle errors and by doing so blurs
- the line between expected errors and unexpected errors. Also function
- signatures are enlarged de-facto by whatever exceptions they can throw
- and thus function calls and return types become much harder to manage.
-
-### Language reach
-
-- Go is tailored towards web applications, servers, and static to low-dynamic
- frontends.
-- Gleam can be utilized as a JavaScript replacement to drive your frontend
- application not just your backend web server.
-- Gleam on Erlang/BEAM can be used to write non-blocking, massively concurrent
- server applications comparable to RabbitMQ or multiplayer game servers.---
-layout: page
-title: Gleam for Go users
-subtitle: Hello Hypertext crafters!
----
-
-- [Comments](#comments)
-- [Variables](#variables)
- - [Match operator](#match-operator)
- - [Variables type annotations](#variables-type-annotations)
-- [Functions](#functions)
- - [Exporting functions](#exporting-functions)
- - [Function type annotations](#function-type-annotations)
- - [Referencing functions](#referencing-functions)
- - [Labelled arguments](#labelled-arguments)
-- [Operators](#operators)
-- [Constants](#constants)
-- [Blocks](#blocks)
-- [Data types](#data-types)
- - [Strings](#strings)
- - [Tuples](#tuples)
- - [Lists](#lists)
- - [Maps](#maps)
- - [Numbers](#numbers)
-- [Flow control](#flow-control)
- - [Case](#case)
- - [Piping](#piping)
- - [Try](#try)
-- [Type aliases](#type-aliases)
-- [Custom types](#custom-types)
- - [Records](#records)
- - [Unions](#unions)
- - [Opaque custom types](#opaque-custom-types)
-- [Modules](#modules)
- - [Imports](#imports)
- - [Named imports](#named-imports)
- - [Unqualified imports](#unqualified-imports)
-- [Architecture](#architecture)
-
-## Comments
-
-### Go
-
-In Go, comments are written with a `//` prefix.
-
-```Go
-// Hello, Joe!
-```
-
-Multi line comments may be written like so:
-
-```Go
-/*
- * Hello, Joe!
- */
-```
-
-IN Go, above `trait`, `interface`, `class`, `member`, `function` declarations
-there can be `docblocks` like so:
-
-```Go
-/**
- * a very special trait.
- */
-trait Foo {}
-
-/**
- * A Bar class
- */
-class Bar {}
-
-/**
- * A quux function.
- *
- * @var string $str String passed to quux
- * @return string An unprocessed string
- */
-function quux(string $str) : string { return $str; }
-```
-
-Documentation blocks (docblocks) are extracted into generated API
-documentation.
-
-### Gleam
-
-In Gleam, comments are written with a `//` prefix.
-
-```gleam
-// Hello, Joe!
-```
-
-Comments starting with `///` are used to document the following function,
-constant, or type definition. Comments starting with `////` are used to
-document the current module.
-
-```gleam
-//// This module is very important.
-
-/// The answer to life, the universe, and everything.
-const answer: Int = 42
-
-/// A main function
-fn main() {}
-
-/// A Dog type
-type Dog {
- Dog(name: String, cuteness: Int)
-}
-```
-
-`//` comments are not used while generating documentation files, while
-`////` and `///` will appear in them.
-
-## Variables
-
-You can rebind variables in both languages.
-
-### Go
-
-```Go
-$size = 50;
-$size = $size + 100;
-$size = 1;
-```
-
-In local scope Go has no specific variable keyword. You choose a name
-and that's it!
-
-In class scope for property declaration Go uses at least one related
-modifier keyword to create properties such as: `public`, `private`,
-`protected`, `static` or `readonly` (`var` is deprecated).
-
-### Gleam
-
-Gleam has the `let` keyword before its variable names.
-
-```gleam
-let size = 50
-let size = size + 100
-let size = 1
-```
-
-### Match operator
-
-#### Go
-
-Go supports basic, one directional destructuring (also called unpacking).
-Tuple of values can be unpacked and inner values can be assigned to left-hand
-variable names.
-
-```Go
-[$a, $b] = [1, 2];
-// $a == 1
-// $b == 2
-
-[1 => $idx2] = ['foo', 'bar', 'quux'];
-// $idx2 == 'bar'
-
-["profession" => $job] = ['name' => 'Joe', 'profession' => 'hacker'];
-// $job == 'hacker'
-```
-
-#### Gleam
-
-In Gleam, `let` and `=` can be used for pattern matching, but you'll get
-compile errors if there's a type mismatch, and a runtime error if there's
-a value mismatch. For assertions, the equivalent `let assert` keyword is
-preferred.
-
-```gleam
-let #(a, _) = #(1, 2)
-// a = 1
-// `_` matches 2 and is discarded
-
-let assert [] = [1] // runtime error
-let assert [y] = "Hello" // compile error, type mismatch
-```
-
-Asserts should be used with caution.
-
-### Variables type annotations
-
-#### Go
-
-Go is a dynamically typed language. Types are only checked at runtime and
-a variable can have different types in its lifetime.
-
-Go gradually introduced more and more type hints that are optional.
-The type information is accessible via `get_type()` at runtime.
-
-These hints will mainly be used to inform static analysis tools like IDEs,
-linters, etc.
-
-```Go
-class Foo {
- private ?string $bar;
-}
-```
-
-As Go's `array` structure is a combination of maps and arrays.
-The Go manual states that it is an *ordered map*.
-While creating arrays in Go the type of its elements cannot be set explicitly
-and each element can be of a different type:
-
-```Go
-$someList = [1, 2, 3];
-$someTuple = [1, "a", true];
-$someMap = [0 => 1, "foo" => "bar", true => false];
-```
-
-Single variables cannot be type-annotated unless they are `class` or `trait`
-members.
-
-#### Gleam
-
-In Gleam type annotations can optionally be given when binding variables.
-
-```gleam
-let some_list: List(Int) = [1, 2, 3]
-let some_string: String = "Foo"
-```
-
-Gleam will check the type annotation to ensure that it matches the type of the
-assigned value. It does not need annotations to type check your code, but you
-may find it useful to annotate variables to hint to the compiler that you want
-a specific type to be inferred.
-
-## Functions
-
-### Go
-
-In Go, you can define functions with the `function` keyword. One or many `return`
-keywords are optional.
-
-```Go
-function hello($name = 'Joe') : string
-{
- if ($name = 'Joe') {
- return 'Welcome back, Joe!';
- }
- return "Hello $name";
-}
-
-function noop()
-{
- // Will automatically return NULL
-}
-```
-
-Anonymous functions returning a single expression can also be defined and be
-bound to variables.
-
-```Go
-$x = 2
-$GoAnonFn = function($y) use ($x) { return $x * $y; }; // Creates a new scope
-$GoAnonFn(2, 3); // 6
-$GoArrowFn = ($x) => $x * $y; // Inherits the outer scope
-$GoArrowFn(2, 3); // 6
-```
-
-### Gleam
-
-Gleam's functions are declared like so:
-
-```gleam
-fn sum(x, y) {
- x + y
-}
-```
-
-Gleam's anonymous functions have the same basic syntax.
-
-```gleam
-let mul = fn(x, y) { x * y }
-mul(1, 2)
-```
-
-A difference between Go's and Gleam's anonymous functions is that in Go they
-create a new local scope, in Gleam they close over the local scope, aka create
-a copy and inherit all variables in the scope. This means that in Gleam you can
-shadow local variables within anonymous functions but you cannot influence the
-variable bindings in the outer scope. This is different for Go's arrow
-functions where they inherit the scope like Gleam does.
-
-The only difference between module functions and anonymous functions in Gleam
-is that module functions heads may also feature argument labels, like so:
-
-```gleam
-// In some module.gleam
-pub fn distance(from x: Int, to y: Int) : Int {
- abs(x) - abs(y) |> abs()
-}
-// In some other function
-distance(from: 1, to: -2) // 3
-```
-
-### Exporting functions
-
-#### Go
-
-In Go, top level functions are exported by default. There is no notion of
-private module-level functions.
-
-However at class level, all properties are public, by default.
-
-```Go
-class Foo {
- static $bar = 5;
- private $quux = 6;
-
- static function batz() {
- return "Hello Joe!";
- }
-
- private static function kek() {
- return "Hello Rasmus!";
- }
-}
-echo Foo::$bar; // 5
-echo Foo::$quux; // Error
-echo Foo::batz(); // "Hello Joe"
-echo Foo::kek(); // Error
-```
-
-#### Gleam
-
-In Gleam, functions are private by default and need the `pub` keyword to be
-marked as public.
-
-```gleam
-// this is public
-pub fn sum(x, y) {
- x + y
-}
-
-// this is private
-fn mul(x, y) {
- x * y
-}
-```
-
-### Go
-
-Global functions may exist in a global scope, and to execute functions or
-create objects and invoke methods at some point they have to be called from
-the global scope. Usually there is one `index.Go` file whose global scope
-acts as if it was the `main()` function.
-
-### Gleam
-
-Gleam does not support a global scope. Instead Gleam code is either
-representing a library, which can be required as a dependency, and/or it
-represents an application having a main module, whose name must match to the
-application name and within that `main()`-function which will be called via
-either `gleam run` or when the `entrypoint.sh` is executed.
-
-In contrast to Go, where any Go file can contain a global scope that can
-be invoked by requiring the file, in Gleam only code that is within functions
-can be invoked.
-
-On the Beam, Gleam code can also be invoked from other Erlang code, or it
-can be invoked from browser's JavaScript, Deno or NodeJS runtime calls.
-
-### Function type annotations
-
-#### Go
-
-Type hints can be used to optionally annotate function arguments and return
-types.
-
-Discrepancies between type hints and actual values at runtime do not prevent
-interpretation of the code. Static code analysers (IDE tooling, type checkers
-like `Gostan`) will be required to detect those errors.
-
-```Go
-function sum(int $x, int $y) : int {
- return $x + $y;
-}
-
-function mul(int $x, int $y) : bool {
- # no errors from the interpreter.
- return $x * $y;
-}
-```
-
-#### Gleam
-
-Functions can **optionally** have their argument and return types annotated in
-Gleam. These type annotations will always be checked by the compiler and throw
-a compilation error if not valid. The compiler will still type check your
-program using type inference if annotations are omitted.
-
-```gleam
-fn add(x: Int, y: Int) -> Int {
- x + y
-}
-
-fn mul(x: Int, y: Int) -> Bool {
- x * y // compile error, type mismatch
-}
-```
-
-### Referencing functions
-
-#### Go
-
-As long as functions are in scope they can be assigned to a new variable.
-As methods or static functions classes, functions can be accessed via
-`$this->object_instance_method()` or `self::static_class_function()`.
-
-Other than that only anonymous functions can be moved around the same way as
-other values.
-
-```Go
-$doubleFn = function($x) { return $x + $x; };
-// Some imaginary pushFunction
-pushFunction($queue, $doubleFn);
-```
-
-However in `Go` it is not possible to pass around global, class or instance
-functions as values.
-
-#### Gleam
-
-Gleam has a single namespace for constants and functions within a module, so
-there is no need for a special syntax to assign a module function to a
-variable.
-
-```gleam
-fn identity(x) {
- x
-}
-
-fn main() {
- let func = identity
- func(100)
-}
-```
-
-### Labelled arguments
-
-Both Go and Gleam have ways to give arguments names and in any order.
-
-#### Go
-
-When calling a function, arguments can be passed:
-
-- positionally, in the same order of the function declaration
-- by name, in any order
-
-```Go
-// Some imaginary replace function
-function replace(string $each, string $with, string $inside) {
- // TODO implementation
-}
-// Calling with positional arguments:
-replace(",", " ", "A,B,C")
-// Calling with named arguments:
-replace(inside: "A,B,C", each: ",", with: " ")
-```
-
-#### Gleam
-
-In Gleam arguments can be given a label as well as an internal name.
-Contrary to Go, the name used at the call-site does not have to match
-the name used for the variable inside the function.
-
-```gleam
-pub fn replace(inside str, each pattern, with replacement) {
- todo
-}
-```
-
-```gleam
-replace(",", " ", "A,B,C")
-replace(inside: "A,B,C", each: ",", with: " ")
-```
-
-There is no performance cost to Gleam's labelled arguments as they are
-optimised to regular function calls at compile time, and all the arguments
-are fully type checked.
-
-## Operators
-
-| Operator | Go | Gleam | Notes |
-| ------------------ | ------ | ------------------------- | -------------------------------------------------------------------------------------- |
-| Equal | `==` | `==` | In Gleam both values must be of the same type |
-| Strictly equal to | `===` | `==` | Comparison in Gleam is always strict. (see note for Go) |
-| Reference equality | `instanceof` | | True only if an object is an instance of a class |
-| Not equal | `!=` | `!=` | In Gleam both values must be of the same type |
-| Not equal | `!==` | `!=` | Comparison in Gleam is always strict (see note for Go) |
-| Greater than | `>` | `>` | In Gleam both values must be **Int** |
-| Greater than | `>` | `>.` | In Gleam both values must be **Float** |
-| Greater or equal | `>=` | `>=` | In Gleam both values must be **Int** |
-| Greater or equal | `>=` | `>=.` | In Gleam both values must be **Float** |
-| Less than | `<` | `<` | In Gleam both values must be **Int** |
-| Less than | `<` | `<.` | In Gleam both values must be **Float** |
-| Less or equal | `<=` | `<=` | In Gleam both values must be **Int** |
-| Less or equal | `<=` | `<=.` | In Gleam both values must be **Float** |
-| Boolean and | `&&` | `&&` | In Gleam both values must be **Bool** |
-| Logical and | `&&` | | Not available in Gleam |
-| Boolean or | ||
| ||
| In Gleam both values must be **Bool** |
-| Logical or | ||
| | Not available in Gleam |
-| Boolean not | `xor` | | Not available in Gleam |
-| Boolean not | `!` | `!` | In Gleam both values must be **Bool** |
-| Add | `+` | `+` | In Gleam both values must be **Int** |
-| Add | `+` | `+.` | In Gleam both values must be **Float** |
-| Subtract | `-` | `-` | In Gleam both values must be **Int** |
-| Subtract | `-` | `-.` | In Gleam both values must be **Float** |
-| Multiply | `*` | `*` | In Gleam both values must be **Int** |
-| Multiply | `*` | `*.` | In Gleam both values must be **Float** |
-| Divide | `/` | `/` | In Gleam both values must be **Int** |
-| Divide | `/` | `/.` | In Gleam both values must be **Float** |
-| Remainder | `%` | `%` | In Gleam both values must be **Int** |
-| Concatenate | `.` | `<>` | In Gleam both values must be **String**
-| Pipe | `->` | |>
| Gleam's pipe can chain function calls. See note for Go |
-
-### Notes on operators
-
-- For bitwise operators, which exist in Go but not in Gleam,
- see: .
-- `==` is by default comparing by value in Go:
- - Types may be autocast to be compareable.
- - Two objects with the same members values will equal:
-- `===` is for comparing by strict equality in Go:
- - Types will not be autocast for comparison
- - Two objects with the same members will not equal. Only if a variable binds
- to the same reference it will equal.
-- Go operators are short-circuiting as in Gleam.
-- Chains and pipes:
- - In Go chaining is usually done by constructing class methods that return
- an object: `$foo->bar(1)->quux(2)` means `bar(1)` is called as a method
- of `$foo` and then `quux()` is called as a method of the return value
- (object) of the `bar(1)` call. The objects in this chain usually
- mutate to keep the changed state and carry it forward in the chain.
- - In contrast in Gleam piping, no objects are being returned but mere data
- is pushed from left to right much like in unix tooling.
-
-## Constants
-
-### Go
-
-In Go, constants can only be defined within classes and traits.
-
-```Go
-class TheQuestion {
- public const theAnswer = 42;
-}
-echo TheQuestion::theAnswer; // 42
-```
-
-### Gleam
-
-In Gleam constants can be created using the `const` keyword.
-
-```gleam
-// the_question.gleam module
-const the_answer = 42
-
-pub fn main() {
- the_answer
-}
-```
-
-They can also be marked public via the `pub` keyword and will then be
-automatically exported.
-
-## Blocks
-
-### Go
-
-Go blocks are always associated with a function / conditional / loop or
-similar declaration. Blocks are limited to specific language constructs.
-There is no way to create multi-line expressions blocks like in Gleam.
-
-Blocks are declared via curly braces.
-
-```Go
-function a_func() {
- // A block starts here
- if ($foo) {
- // A block here
- } else {
- // A block here
- }
- // Block continues
-}
-```
-
-### Gleam
-
-In Gleam curly braces, `{` and `}`, are used to group expressions.
-
-```gleam
-pub fn main() {
- let x = {
- some_function(1)
- 2
- }
- // Braces are used to change precedence of arithmetic operators
- let y = x * {x + 10}
- y
-}
-```
-
-Unlike in Go, in Gleam function blocks are always expressions, so are `case`
-blocks or arithmetic sub groups. Because they are expressions they always
-return a value.
-
-For Gleam the last value in a block's expression is always the value being
-returned from an expression.
-
-## Data types
-
-### Strings
-
-In Go strings are stored as an array of bytes and an integer indicating the
-length of the buffer. Go itself has no information about how those bytes
-translate to characters, leaving that task to the programmer. Go's
-standard library however features a bunch of multi-byte compatible functions
-and conversion functions between UTF-8, ISO-8859-1 and further encodings.
-
-Go strings allow interpolation.
-
-In Gleam all strings are UTF-8 encoded binaries. Gleam strings do not allow
-interpolation, yet. Gleam however offers a `string_builder` via its standard
-library for performant string building.
-
-#### Go
-
-```Go
-$what = 'world';
-'Hellø, world!';
-"Hellø, ${what}!";
-```
-
-#### Gleam
-
-```gleam
-"Hellø, world!"
-```
-
-### Tuples
-
-Tuples are very useful in Gleam as they're the only collection data type that
-allows mixed types in the collection.
-
-#### Go
-
-Go does not really support tuples, but its array type can easily be used to
-mimick tuples. Unpacking can be used to bind a name to a specific value of
-the tuple.
-
-```Go
-$myTuple = ['username', 'password', 10];
-[$_, $pwd, $_] = $myTuple;
-echo $pwd; // "password"
-// Direct index access
-echo $myTuple[0]; // "username"
-```
-
-#### Gleam
-
-```gleam
-let my_tuple = #("username", "password", 10)
-let #(_, pwd, _) = my_tuple
-io.print(pwd) // "password"
-// Direct index access
-io.print(my_tuple.0) // "username"
-```
-
-### Lists
-
-Arrays in Go are allowed to have values of mixed types, but not in Gleam.
-
-#### Go
-
-Go does not feature special syntax for list handling.
-
-```Go
-$list = [2, 3, 4];
-$head = array_slice($list, 0, 1)[0];
-$tail = array_slice($list, 1);
-# $head == 2
-# $tail == [3, 4]
-$arr = array_merge($tail, [1.1]);
-# $arr == [3, 4, 1.1]
-```
-
-#### Gleam
-
-Gleam has a `cons` operator that works for lists destructuring and
-pattern matching. In Gleam lists are immutable so adding and removing elements
-from the start of a list is highly efficient.
-
-```gleam
-let list = [2, 3, 4]
-let list = [1, ..list]
-let [1, second_element, ..] = list
-[1.0, ..list] // compile error, type mismatch
-```
-
-### Maps
-
-In Go, the `array` type also covers maps and can have keys of any type as long as:
-
-- the key type is `null`, an `int`, a `string` or a `bool` (some conversions
- occur, such as null to `""` and `false` to `0` as well as `true` to `1`
- and `"1"` to `1`. Float indexes, which are not representing integers
- indexes are deprecated due to being auto downcast to integers).
-- the key is unique in the dictionary.
-- the values are of any type.
-
-In Gleam, maps can have keys and values of any type, but all keys must be of
-the same type in a given map and all values must be of the same type in a
-given map. The type of key and value can differ from each other.
-
-There is no map literal syntax in Gleam, and you cannot pattern match on a map.
-Maps are generally not used much in Gleam, custom types are more common.
-
-#### Go
-
-```Go
-["key1" => "value1", "key2" => "value2"]
-["key1" => "1", "key2" => 2]
-```
-
-#### Gleam
-
-```gleam
-import gleam/map
-
-map.from_list([#("key1", "value1"), #("key2", "value2")])
-map.from_list([#("key1", "value1"), #("key2", 2)]) // Type error!
-```
-
-### Numbers
-
-Go and Gleam both support `Integer` and `Float`. Integer and Float sizes for
-both depend on the platform: 64-bit or 32-bit hardware and OS and for Gleam
-JavaScript and Erlang.
-
-#### Go
-
-While Go differentiates between integers and floats it automatically converts
-floats and integers for you, removing precision or adding floating point
-decimals.
-
-```Go
-1 / 2 // 0.5
-```
-
-#### Gleam
-
-```gleam
-1 / 2 // 0
-1.5 + 10 // Compile time error
-```
-
-You can use the gleam standard library's `int` and `float` modules to convert
-between floats and integers in various ways including `rounding`, `floor`,
-`ceiling` and many more.
-
-## Flow control
-
-### Case
-
-Case is one of the most used control flow in Gleam. It can be seen as a switch
-statement on steroids. It provides a terse way to match a value type to an
-expression. It is also used to replace `if`/`else` statements.
-
-#### Go
-
-Go features 3 different expressions to achieve similar goals:
-
-- `if`/`else if`/`else` (does not return)
-- `switch`/`case`/`break`/`default` (does not return, does not autobreak)
-- `match` (returns)
-
-```Go
-function http_error_impl_1($status) {
- if ($status === 400) {
- return "Bad request";
- } else if ($status === 404) {
- return "Not found";
- } else if ($status === 418) {
- return "I'm a teapot";
- } else {
- return "Internal Server Error";
- }
-}
-
-function http_error_impl_2($status) {
- switch ($status) {
- case "400": // Will work because switch ($status) compares non-strict as in ==
- return "Bad request";
- break; // Not strictly required here, but combined with weak typing multiple cases could be executed if break is omitted
- case 404:
- return "Not found";
- break;
- case 418:
- return "I'm a teapot";
- break;
- default:
- return "Internal Server Error";
- }
-}
-
-function http_error_impl_3($status) {
- return match($status) { // match($status) compares strictly
- 400 => "Bad request",
- 404 => "Not found",
- 418 => "I'm a teapot",
- default => "Internal Server Error"
- };
-}
-```
-
-#### Gleam
-
-The case operator is a top level construct in Gleam:
-
-```gleam
-case some_number {
- 0 -> "Zero"
- 1 -> "One"
- 2 -> "Two"
- n -> "Some other number" // This matches anything
-}
-```
-
-As all expressions the case expression will return the matched value.
-
-They can be used to mimick if/else or if/elseif/else, with the exception that
-any branch must return unlike in Go, where it is possible to mutate a
-variable of the outer block/scope and not return at all.
-
-```gleam
-let is_status_within_4xx = status / 400 == 1
-case status {
- 400 -> "Bad Request"
- 404 -> "Not Found"
- _ if is_status_within_4xx -> "4xx" // This works as of now
- // status if status / 400 == 1 -> "4xx" // This will work in future versions of Gleam
- _ -> "I'm not sure"
-}
-```
-
-if/else example:
-
-```gleam
-case is_admin {
- True -> "allow access"
- False -> "disallow access"
-}
-```
-
-if/elseif/else example:
-
-```gleam
-case True {
- _ if is_admin == True -> "allow access"
- _ if is_confirmed_by_mail == True -> "allow access"
- _ -> "deny access"
-}
-```
-
-Exhaustiveness checking at compile time, which is in the works, will make
-certain that you must check for all possible values. A lazy and common way is
-to check of expected values and have a catchall clause with a single underscore
-`_`:
-
-```gleam
-case scale {
- 0 -> "none"
- 1 -> "one"
- 2 -> "pair"
- _ -> "many"
-}
-```
-
-The case operator especially coupled with destructuring to provide native pattern
-matching:
-
-```gleam
-case xs {
- [] -> "This list is empty"
- [a] -> "This list has 1 element"
- [a, b] -> "This list has 2 elements"
- _other -> "This list has more than 2 elements"
-}
-```
-
-The case operator supports guards:
-
-```gleam
-case xs {
- [a, b, c] if a >. b && a <=. c -> "ok"
- _other -> "ko"
-}
-```
-
-...and disjoint union matching:
-
-```gleam
-case number {
- 2 | 4 | 6 | 8 -> "This is an even number"
- 1 | 3 | 5 | 7 -> "This is an odd number"
- _ -> "I'm not sure"
-}
-```
-
-### Piping
-
-In Gleam most functions, if not all, are data first, which means the main data
-value to work on is the first argument. By this convention and the ability to
-specify the argument to pipe into, Gleam allows writing functional, immutable
-code, that reads imperative-style top down, much like unix tools and piping.
-
-#### Go
-
-Go does not offer pipes but it can chain calls by making functions return
-objects which in turn ship with their list of methods.
-
-```Go
-// Imaginary Go code
-(new Session($request))
- ->authorize()
- ->setSuccessFlash('Logged in successfully!')
- ->setFailureFlash('Failed to login!')
- ->redirectToRequestedUrl();
-```
-
-#### Gleam
-
-```gleam
-// Imaginary Gleam code
-request
-|> session.new()
-|> session.authorize()
-|> flash.set_success_flash('Logged in successfully!')
-|> flash.set_failure_flash('Failed to login!')
-|> response.redirect_to_requested_url()
-```
-
-Despite being similar to read and comprehend, the Go code creates a session
-object, and calls the authorize method of the session object: That session
-object then returns another object, say an `AuthorizedUser` object - you don't
-know by looking at the code what object gets returned. However you know it must
-implement a `setSuccessFlash` method. At the last step of the chain `redirect`
-is called on an object returned from `setFailureFlash`.
-
-In the Gleam code the request data is piped into `session.new()`'s first
-argument and that return value is piped further down. It is readability sugar
-for:
-
-```gleam
-response.redirect_to_requested_url(
- flash.set_failure_flash(
- flash.set_success_flash(
- session.authorize(
- session.new(request)
- ),
- 'Logged in successfully!'
- ),
- 'Failed to login!'
- )
-)
-```
-
-### Try
-
-Error management is approached differently in Go and Gleam.
-
-#### Go
-
-Go uses the notion of exceptions to interrupt the current code flow and
-pop up the error to the caller.
-
-An exception is raised using the keyword `throw`.
-
-```Go
-function aFunctionThatFails() {
- throw new RuntimeException('an error');
-}
-```
-
-The callee block will be able to capture any exception raised in the block
-using a `try/except` set of blocks:
-
-```Go
-// callee block
-try {
- echo 'this line will be executed and thus printed';
- aFunctionThatFails()
- echo 'this line will not be executed and thus not printed';
-} catch (Throwable $e) {
- var_dump(['doing something with the exception', $e]);
-}
-```
-
-#### Gleam
-
-In contrast in gleam, errors are just containers with an associated value.
-
-A common container to model an operation result is
-`Result(ReturnType, ErrorType)`.
-
-A `Result` is either:
-
-- an `Error(ErrorValue)`
-- or an `Ok(Data)` record
-
-Handling errors actually means to match the return value against those two
-scenarios, using a case for instance:
-
-```gleam
-case parse_int("123") {
- Ok(i) -> io.println("We parsed the Int")
- Error(e) -> io.println("That wasn't an Int")
-}
-```
-
-In order to simplify this construct, we can use the `try` keyword that will:
-
-- either bind a value to the providing name if `Ok(Something)` is matched,
-- or **interrupt the current block's flow** and return `Error(Something)` from
- the given block.
-
-```gleam
-let a_number = "1"
-let an_error = Error("ouch")
-let another_number = "3"
-
-try int_a_number = parse_int(a_number)
-try attempt_int = parse_int(an_error) // Error will be returned
-try int_another_number = parse_int(another_number) // never gets executed
-
-Ok(int_a_number + attempt_int + int_another_number) // never gets executed
-```
-
-## Type aliases
-
-Type aliases allow for easy referencing of arbitrary complex types.
-Go does not have this feature, though either regular classes or static classes
-can be used to design custom types and class definitions in take can be aliased
-using `class_alias()`.
-
-### Go
-
-A simple variable can store the result of a compound set of types.
-
-```Go
-static class Point {
- // Can act as an opaque type and utilize Point
- // Can be class_aliased to Coordinate
-}
-
-static class Triangle {
- // Can act as an opaque type definition and utilize Point
-}
-```
-
-### Gleam
-
-The `type` keyword can be used to create aliases.
-
-```gleam
-pub type Headers =
- List(#(String, String))
-```
-
-## Custom types
-
-### Records
-
-Custom type allows you to define a collection data type with a fixed number of
-named fields, and the values in those fields can be of differing types.
-
-#### Go
-
-Go uses classes to define user-defined, record-like types.
-Properties are defined as class members and initial values are generally set in
-the constructor.
-
-By default the constructor does not provide base initializers in the
-constructor so some boilerplate is needed:
-
-```Go
-class Person {
- public string $name;
- public int $age;
- function __construct(string $name, int $age) {
- $this->name = $name;
- $this->age = $age;
- }
-}
-$person = new Person(name: "Joe", age: 40);
-// $person->name // Joe;
-```
-
-#### Gleam
-
-Gleam's custom types can be used as structs. At runtime, they have a tuple
-representation and are compatible with Erlang records (or JavaScript objects).
-
-```gleam
-type Person {
- Person(name: String, age: Int)
-}
-
-let person = Person(name: "Joe", age: 40)
-let name = person.name
-```
-
-An important difference to note is there is no Java-style object-orientation in
-Gleam, thus methods can not be added to types. However opaque types exist,
-see below.
-
-### Unions
-
-Go generally does not support unions with a few exceptions such as:
-
-- type x or `null`
-- `Array` or `Traversable`.
-
-In Gleam functions must always take and receive one type. To have a union of
-two different types they must be wrapped in a new custom type.
-
-#### Go
-
-```Go
-class Foo {
- public ?string $aStringOrNull;
-}
-```
-
-#### Gleam
-
-```gleam
-type IntOrFloat {
- AnInt(Int)
- AFloat(Float)
-}
-
-fn int_or_float(X) {
- case X {
- True -> AnInt(1)
- False -> AFloat(1.0)
- }
-}
-```
-
-### Opaque custom types
-
-In Go, constructors can be marked as private and opaque types can either be
-modelled in an immutable way via static classes or in a mutable way via
-a factory pattern.
-
-In Gleam, custom types can be defined as being opaque, which causes the
-constructors for the custom type not to be exported from the module. Without
-any constructors to import other modules can only interact with opaque types
-using the intended API.
-
-#### Go
-
-```Go
-class PointObject
-{
- private int $x;
- private int $y;
-
- private function __construct(int $x, int $y) {
- $this->x = $x;
- $this->y = $y;
- }
-
- public static function spawn(int $x, int $y) {
- if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
- return new self($x, $y);
- }
- return false;
- }
-}
-PointObject::spawn(1, 2); // Returns a Point object
-```
-
-This requires mutation, but prohibits direct property changes.
-
-Go allows to skip object mutation by using static classes:
-
-```Go
-class PointStruct
-{
- public static function spawn(int $x, int $y) {
- if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
- return compact('x', 'y') + ['struct' => __CLASS__];
- }
- return false;
- }
-}
-PointStruct::spawn(1, 2); // Returns an array managed by PointStruct
-```
-
-However Go will in this case not prohibit the direct alteration the returned
-structure, like Gleam's custom types can.
-
-#### Gleam
-
-```gleam
-// In the point.gleam opaque type module:
-pub opaque type Point {
- Point(x: Int, y: Int)
-}
-
-pub fn spawn(x: Int, y: Int) -> Result(Point, Nil) {
- case x >= 0 && x <= 99 && y >= 0 && y <= 99 {
- True -> Ok(Point(x: x, y: y))
- False -> Error(Nil)
- }
-}
-
-// In the main.gleam module
-pub fn main() {
- assert Ok(point) = Point.spawn(1, 2)
- point
-}
-```
-
-## Modules
-
-### Go
-
-Go does not feature modules, but many other containers such as classes, traits
-and interfaces. Historically a single file can contain many classes, traits and
-interfaces one after another, though it is best practise to only contain one
-such declaration per file.
-
-Using Go namespaces, these can be placed in a registry that does not need to
-map to the source code file system hierarchy, but by convention should.
-
-In `src/Foo/Bar.Go`:
-
-```Go
-// Anything declared in this file will be inside namespace Foo
-namespace Foo;
-
-// Creation of (static) class Bar in Foo, thus as Foo/Bar
-class Bar {
- public static function identity($x) {
- return $x;
- }
-}
-```
-
-Making the static class available in the local scope and calling the function
-`index.Go` (aka Go's main function):
-
-```Go
-// After auto-loading has happened
-use Foo\Bar;
-
-Bar::identity(1) // 1;
-```
-
-### Gleam
-
-Coming from Go the closest thing Go has that are similar to Gleam's modules
-are static classes: Collections of functions and constants grouped into a
-static class.
-
-In comparison Gleam modules can also contain custom types.
-
-A gleam module name corresponds to its file name and path.
-
-Since there is no special syntax to create a module, there can be only one
-module in a file and since there is no way name the module the filename
-always matches the module name which keeps things simple and transparent.
-
-In `/src/foo/bar.gleam`:
-
-```gleam
-// Creation of module function identity
-// in module bar
-pub fn identity(x) {
- x
-}
-```
-
-Importing the `bar` module and calling a module function:
-
-```gleam
-// In src/main.gleam
-import foo/bar // if foo was in a directory called `lib` the import would be `lib/foo/bar`.
-
-pub fn main() {
- bar.identity(1) // 1
-}
-```
-
-### Imports
-
-#### Go
-
-Go features ways to load arbitrary Go code: `require`, `include` and
-autoload such as `spl_autoload_register`. Once class pathes are known and
-registered for autoloading, they can brought into the scope of a file by using
-the `use`statement which is part of Go's namespacing.
-Also see .
-
-Inside `src/Nasa/MoonBase.Go`
-
-```Go
-// Makes available src/nasa/RocketShip.Go
-use Nasa\RocketShip;
-
-class MoonBase {
- public static function exploreSpace() {
- RocketShip::launch();
- }
-}
-```
-
-#### Gleam
-
-Imports are relative to the app `src` folder.
-
-Modules in the same directory will need to reference the entire path from `src`
-for the target module, even if the target module is in the same folder.
-
-Inside module `src/nasa/moon_base.gleam`:
-
-```gleam
-// imports module src/nasa/rocket_ship.gleam
-import nasa/rocket_ship
-
-pub fn explore_space() {
- rocket_ship.launch()
-}
-```
-
-### Named imports
-
-#### Go
-
-Go features namespaces which can be used to rename classes when they clash:
-
-```Go
-// Source files must first be added to the auto-loader
-use Unix\Cat;
-use Animal\Cat as Kitty;
-// Cat and Kitty are available
-```
-
-#### Gleam
-
-Gleam has as similar feature:
-
-```gleam
-import unix/cat
-import animal/cat as kitty
-// cat and kitty are available
-```
-
-This may be useful to differentiate between multiple modules that would have the same default name when imported.
-
-### Unqualified imports
-
-#### Go
-
-```Go
-use Animal\Cat{
- Cat,
- function stroke
-};
-```
-
-```Go
-$kitty = new Cat(name: "Nubi");
-stroke($kitty);
-```
-
-#### Gleam
-
-```gleam
-import animal/cat.{
- Cat,
- stroke
-}
-
-pub fn main() {
- let kitty = Cat(name: "Nubi")
- stroke(kitty)
-}
-```
-
-Importing common types such as `gleam/order.{Lt, Eq, Gt}` or
-`gleam/option.{Some,None}` can be very helpful.
-
-## Architecture
-
-To iterate a few foundational differences:
-
-1. Programming model: Java-style object-orientation VS functional immutable
- programming
-2. Guarantees: weak dynamic typing VS strong static typing
-3. Runtime model: request-response script VS Erlang/OTP processes
-4. Error handling: exceptions VS result type
-5. Language reach
-
-### Programming model
-
-- Go mixes imperative, Java-style object-orientation and functional code
- styles. Gleam offers only functional code style, though it can appear
- imperative and reads easily thanks to pipes.
-- In Gleam, data structures are never mutated but always updated into new
- structures. This allows processes that fail to simply restart as there are no
- mutated objects that can be in an invalid state and take the whole
- application down (such as in Go, Ruby or Go).
-- Gleam offers syntax to make it easy to extract data out of custom types and
- update data into new copies of custom types without ever mutating variables.
- Go sometimes directly mutates references of simple values such as when using
- `reset()` or `end()` or `array_pop()`.
-- Gleam allows to rebind variables freely to make it easy to update data
- structures by making a copy and binding it to the existing variable.
-- Go features a massive, powerful but inconsistent standard library that is
- always loaded and partially extended and deprecated with new Go releases.
-- Gleam allows you to opt into a smaller, well polished and consistent standard
- library.
-
-### Guarantees and types
-
-- Go features opt-in static typing which is only checked at runtime.
-- Go values tend to be automatically cast for comparison purposes or when used
- as indexes in arrays. Gleam values are not automatically cast.
-- Go allows comparison between most if not all values, even if it does not
- make any sense say comparing a file `resource` to a `Date` in terms of order.
- Gleam's comparison operators are very strict and limited, any other
- comparisons and conversions must happen via function calls.
-- Go's checks happen at runtime, Gleam's checks (for the most part) do not
- and rely on the compiler to allow only type safe and sound code to be
- compiled.
-- Gleam's type inference allows you to be lazy for almost all type definitions.
- Gleam's type system will always assist you in what types are expected and/or
- conflicting. Gleam's type system will help you discover APIs.
-
-### Runtime model
-
-- Gleam can run on Erlang/BEAM, on the browser but also Deno or NodeJS.
-- For Gleam on Erlang/BEAM the runtime model has some striking similarities
- in practise: In Go a script starts and runs. It allocates memory for this
- script and frees it upon end or after the max execution time is exceeded
- or the memory limit is exceeded.
-- Gleam on Erlang/BEAM allows to processes requests in a similar isolation
- level that Go offers in contrast to applications running *Go* or *Ruby*.
- The level of isoluation means that, very similar to Go, if a process
- crashes (in Go read: if a request crashes) then the supervision system
- can restart that process or after a while or amount of tries abort
- repeating restarts on the process with that given input data. This means
- Erlang/BEAM will yield similar robustness that Go developers are used
- to and similar isolation guarantuees.
-- When executing Gleam code in fact its compiled Erlang or JavaScript is
- executed. So in case there are runtime crashes, the crash log will show
- Erlang (or browser-console/NodeJS/Deno) debug information. In Gleam
- applications runtime errors should almost never happen but they are harder
- to read, in Go applications runtime errors much more often and are easier
- to read.
-
-### Error handling
-
-- Gleam will catch all errors that are expected to happen via the `Result`
- type. There can however be other errors, such as miss-behavior due
- accidental to division by 0, crashes on RAM or storage limits, hardware
- failures, etc. In these cases on the BEAM there are ways to manage these
- via BEAM's supervision trees.
-- In contrast Go will use exceptions to handle errors and by doing so blurs
- the line between expected errors and unexpected errors. Also function
- signatures are enlarged de-facto by whatever exceptions they can throw
- and thus function calls and return types become much harder to manage.
-
-### Language reach
-
-- Go is tailored towards web applications, servers, and static to low-dynamic
- frontends.
-- Gleam can be utilized as a JavaScript replacement to drive your frontend
- application not just your backend web server.
-- Gleam on Erlang/BEAM can be used to write non-blocking, massively concurrent
- server applications comparable to RabbitMQ or multiplayer game servers.---
-layout: page
-title: Gleam for Go users
-subtitle: Hello Hypertext crafters!
----
-
-- [Comments](#comments)
-- [Variables](#variables)
- - [Match operator](#match-operator)
- - [Variables type annotations](#variables-type-annotations)
-- [Functions](#functions)
- - [Exporting functions](#exporting-functions)
- - [Function type annotations](#function-type-annotations)
- - [Referencing functions](#referencing-functions)
- - [Labelled arguments](#labelled-arguments)
-- [Operators](#operators)
-- [Constants](#constants)
-- [Blocks](#blocks)
-- [Data types](#data-types)
- - [Strings](#strings)
- - [Tuples](#tuples)
- - [Lists](#lists)
- - [Maps](#maps)
- - [Numbers](#numbers)
-- [Flow control](#flow-control)
- - [Case](#case)
- - [Piping](#piping)
- - [Try](#try)
-- [Type aliases](#type-aliases)
-- [Custom types](#custom-types)
- - [Records](#records)
- - [Unions](#unions)
- - [Opaque custom types](#opaque-custom-types)
-- [Modules](#modules)
- - [Imports](#imports)
- - [Named imports](#named-imports)
- - [Unqualified imports](#unqualified-imports)
-- [Architecture](#architecture)
-
-## Comments
-
-### Go
-
-In Go, comments are written with a `//` prefix.
-
-```Go
-// Hello, Joe!
-```
-
-Multi line comments may be written like so:
-
-```Go
-/*
- * Hello, Joe!
- */
-```
-
-IN Go, above `trait`, `interface`, `class`, `member`, `function` declarations
-there can be `docblocks` like so:
-
-```Go
-/**
- * a very special trait.
- */
-trait Foo {}
-
-/**
- * A Bar class
- */
-class Bar {}
-
-/**
- * A quux function.
- *
- * @var string $str String passed to quux
- * @return string An unprocessed string
- */
-function quux(string $str) : string { return $str; }
-```
-
-Documentation blocks (docblocks) are extracted into generated API
-documentation.
-
-### Gleam
-
-In Gleam, comments are written with a `//` prefix.
-
-```gleam
-// Hello, Joe!
-```
-
-Comments starting with `///` are used to document the following function,
-constant, or type definition. Comments starting with `////` are used to
-document the current module.
-
-```gleam
-//// This module is very important.
-
-/// The answer to life, the universe, and everything.
-const answer: Int = 42
-
-/// A main function
-fn main() {}
-
-/// A Dog type
-type Dog {
- Dog(name: String, cuteness: Int)
-}
-```
-
-`//` comments are not used while generating documentation files, while
-`////` and `///` will appear in them.
-
-## Variables
-
-You can rebind variables in both languages.
-
-### Go
-
-```Go
-$size = 50;
-$size = $size + 100;
-$size = 1;
-```
-
-In local scope Go has no specific variable keyword. You choose a name
-and that's it!
-
-In class scope for property declaration Go uses at least one related
-modifier keyword to create properties such as: `public`, `private`,
-`protected`, `static` or `readonly` (`var` is deprecated).
-
-### Gleam
-
-Gleam has the `let` keyword before its variable names.
-
-```gleam
-let size = 50
-let size = size + 100
-let size = 1
-```
-
-### Match operator
-
-#### Go
-
-Go supports basic, one directional destructuring (also called unpacking).
-Tuple of values can be unpacked and inner values can be assigned to left-hand
-variable names.
-
-```Go
-[$a, $b] = [1, 2];
-// $a == 1
-// $b == 2
-
-[1 => $idx2] = ['foo', 'bar', 'quux'];
-// $idx2 == 'bar'
-
-["profession" => $job] = ['name' => 'Joe', 'profession' => 'hacker'];
-// $job == 'hacker'
-```
-
-#### Gleam
-
-In Gleam, `let` and `=` can be used for pattern matching, but you'll get
-compile errors if there's a type mismatch, and a runtime error if there's
-a value mismatch. For assertions, the equivalent `let assert` keyword is
-preferred.
-
-```gleam
-let #(a, _) = #(1, 2)
-// a = 1
-// `_` matches 2 and is discarded
-
-let assert [] = [1] // runtime error
-let assert [y] = "Hello" // compile error, type mismatch
-```
-
-Asserts should be used with caution.
-
-### Variables type annotations
-
-#### Go
-
-Go is a dynamically typed language. Types are only checked at runtime and
-a variable can have different types in its lifetime.
-
-Go gradually introduced more and more type hints that are optional.
-The type information is accessible via `get_type()` at runtime.
-
-These hints will mainly be used to inform static analysis tools like IDEs,
-linters, etc.
-
-```Go
-class Foo {
- private ?string $bar;
-}
-```
-
-As Go's `array` structure is a combination of maps and arrays.
-The Go manual states that it is an *ordered map*.
-While creating arrays in Go the type of its elements cannot be set explicitly
-and each element can be of a different type:
-
-```Go
-$someList = [1, 2, 3];
-$someTuple = [1, "a", true];
-$someMap = [0 => 1, "foo" => "bar", true => false];
-```
-
-Single variables cannot be type-annotated unless they are `class` or `trait`
-members.
-
-#### Gleam
-
-In Gleam type annotations can optionally be given when binding variables.
-
-```gleam
-let some_list: List(Int) = [1, 2, 3]
-let some_string: String = "Foo"
-```
-
-Gleam will check the type annotation to ensure that it matches the type of the
-assigned value. It does not need annotations to type check your code, but you
-may find it useful to annotate variables to hint to the compiler that you want
-a specific type to be inferred.
-
-## Functions
-
-### Go
-
-In Go, you can define functions with the `function` keyword. One or many `return`
-keywords are optional.
-
-```Go
-function hello($name = 'Joe') : string
-{
- if ($name = 'Joe') {
- return 'Welcome back, Joe!';
- }
- return "Hello $name";
-}
-
-function noop()
-{
- // Will automatically return NULL
-}
-```
-
-Anonymous functions returning a single expression can also be defined and be
-bound to variables.
-
-```Go
-$x = 2
-$GoAnonFn = function($y) use ($x) { return $x * $y; }; // Creates a new scope
-$GoAnonFn(2, 3); // 6
-$GoArrowFn = ($x) => $x * $y; // Inherits the outer scope
-$GoArrowFn(2, 3); // 6
-```
-
-### Gleam
-
-Gleam's functions are declared like so:
-
-```gleam
-fn sum(x, y) {
- x + y
-}
-```
-
-Gleam's anonymous functions have the same basic syntax.
-
-```gleam
-let mul = fn(x, y) { x * y }
-mul(1, 2)
-```
-
-A difference between Go's and Gleam's anonymous functions is that in Go they
-create a new local scope, in Gleam they close over the local scope, aka create
-a copy and inherit all variables in the scope. This means that in Gleam you can
-shadow local variables within anonymous functions but you cannot influence the
-variable bindings in the outer scope. This is different for Go's arrow
-functions where they inherit the scope like Gleam does.
-
-The only difference between module functions and anonymous functions in Gleam
-is that module functions heads may also feature argument labels, like so:
-
-```gleam
-// In some module.gleam
-pub fn distance(from x: Int, to y: Int) : Int {
- abs(x) - abs(y) |> abs()
-}
-// In some other function
-distance(from: 1, to: -2) // 3
-```
-
-### Exporting functions
-
-#### Go
-
-In Go, top level functions are exported by default. There is no notion of
-private module-level functions.
-
-However at class level, all properties are public, by default.
-
-```Go
-class Foo {
- static $bar = 5;
- private $quux = 6;
-
- static function batz() {
- return "Hello Joe!";
- }
-
- private static function kek() {
- return "Hello Rasmus!";
- }
-}
-echo Foo::$bar; // 5
-echo Foo::$quux; // Error
-echo Foo::batz(); // "Hello Joe"
-echo Foo::kek(); // Error
-```
-
-#### Gleam
-
-In Gleam, functions are private by default and need the `pub` keyword to be
-marked as public.
-
-```gleam
-// this is public
-pub fn sum(x, y) {
- x + y
-}
-
-// this is private
-fn mul(x, y) {
- x * y
-}
-```
-
-### Go
-
-Global functions may exist in a global scope, and to execute functions or
-create objects and invoke methods at some point they have to be called from
-the global scope. Usually there is one `index.Go` file whose global scope
-acts as if it was the `main()` function.
-
-### Gleam
-
-Gleam does not support a global scope. Instead Gleam code is either
-representing a library, which can be required as a dependency, and/or it
-represents an application having a main module, whose name must match to the
-application name and within that `main()`-function which will be called via
-either `gleam run` or when the `entrypoint.sh` is executed.
-
-In contrast to Go, where any Go file can contain a global scope that can
-be invoked by requiring the file, in Gleam only code that is within functions
-can be invoked.
-
-On the Beam, Gleam code can also be invoked from other Erlang code, or it
-can be invoked from browser's JavaScript, Deno or NodeJS runtime calls.
-
-### Function type annotations
-
-#### Go
-
-Type hints can be used to optionally annotate function arguments and return
-types.
-
-Discrepancies between type hints and actual values at runtime do not prevent
-interpretation of the code. Static code analysers (IDE tooling, type checkers
-like `Gostan`) will be required to detect those errors.
-
-```Go
-function sum(int $x, int $y) : int {
- return $x + $y;
-}
-
-function mul(int $x, int $y) : bool {
- # no errors from the interpreter.
- return $x * $y;
-}
-```
-
-#### Gleam
-
-Functions can **optionally** have their argument and return types annotated in
-Gleam. These type annotations will always be checked by the compiler and throw
-a compilation error if not valid. The compiler will still type check your
-program using type inference if annotations are omitted.
-
-```gleam
-fn add(x: Int, y: Int) -> Int {
- x + y
-}
-
-fn mul(x: Int, y: Int) -> Bool {
- x * y // compile error, type mismatch
-}
-```
-
-### Referencing functions
-
-#### Go
-
-As long as functions are in scope they can be assigned to a new variable.
-As methods or static functions classes, functions can be accessed via
-`$this->object_instance_method()` or `self::static_class_function()`.
-
-Other than that only anonymous functions can be moved around the same way as
-other values.
-
-```Go
-$doubleFn = function($x) { return $x + $x; };
-// Some imaginary pushFunction
-pushFunction($queue, $doubleFn);
-```
-
-However in `Go` it is not possible to pass around global, class or instance
-functions as values.
-
-#### Gleam
-
-Gleam has a single namespace for constants and functions within a module, so
-there is no need for a special syntax to assign a module function to a
-variable.
-
-```gleam
-fn identity(x) {
- x
-}
-
-fn main() {
- let func = identity
- func(100)
-}
-```
-
-### Labelled arguments
-
-Both Go and Gleam have ways to give arguments names and in any order.
-
-#### Go
-
-When calling a function, arguments can be passed:
-
-- positionally, in the same order of the function declaration
-- by name, in any order
-
-```Go
-// Some imaginary replace function
-function replace(string $each, string $with, string $inside) {
- // TODO implementation
-}
-// Calling with positional arguments:
-replace(",", " ", "A,B,C")
-// Calling with named arguments:
-replace(inside: "A,B,C", each: ",", with: " ")
-```
-
-#### Gleam
-
-In Gleam arguments can be given a label as well as an internal name.
-Contrary to Go, the name used at the call-site does not have to match
-the name used for the variable inside the function.
-
-```gleam
-pub fn replace(inside str, each pattern, with replacement) {
- todo
-}
-```
-
-```gleam
-replace(",", " ", "A,B,C")
-replace(inside: "A,B,C", each: ",", with: " ")
-```
-
-There is no performance cost to Gleam's labelled arguments as they are
-optimised to regular function calls at compile time, and all the arguments
-are fully type checked.
-
-## Operators
-
-| Operator | Go | Gleam | Notes |
-| ------------------ | ------ | ------------------------- | -------------------------------------------------------------------------------------- |
-| Equal | `==` | `==` | In Gleam both values must be of the same type |
-| Strictly equal to | `===` | `==` | Comparison in Gleam is always strict. (see note for Go) |
-| Reference equality | `instanceof` | | True only if an object is an instance of a class |
-| Not equal | `!=` | `!=` | In Gleam both values must be of the same type |
-| Not equal | `!==` | `!=` | Comparison in Gleam is always strict (see note for Go) |
-| Greater than | `>` | `>` | In Gleam both values must be **Int** |
-| Greater than | `>` | `>.` | In Gleam both values must be **Float** |
-| Greater or equal | `>=` | `>=` | In Gleam both values must be **Int** |
-| Greater or equal | `>=` | `>=.` | In Gleam both values must be **Float** |
-| Less than | `<` | `<` | In Gleam both values must be **Int** |
-| Less than | `<` | `<.` | In Gleam both values must be **Float** |
-| Less or equal | `<=` | `<=` | In Gleam both values must be **Int** |
-| Less or equal | `<=` | `<=.` | In Gleam both values must be **Float** |
-| Boolean and | `&&` | `&&` | In Gleam both values must be **Bool** |
-| Logical and | `&&` | | Not available in Gleam |
-| Boolean or | ||
| ||
| In Gleam both values must be **Bool** |
-| Logical or | ||
| | Not available in Gleam |
-| Boolean not | `xor` | | Not available in Gleam |
-| Boolean not | `!` | `!` | In Gleam both values must be **Bool** |
-| Add | `+` | `+` | In Gleam both values must be **Int** |
-| Add | `+` | `+.` | In Gleam both values must be **Float** |
-| Subtract | `-` | `-` | In Gleam both values must be **Int** |
-| Subtract | `-` | `-.` | In Gleam both values must be **Float** |
-| Multiply | `*` | `*` | In Gleam both values must be **Int** |
-| Multiply | `*` | `*.` | In Gleam both values must be **Float** |
-| Divide | `/` | `/` | In Gleam both values must be **Int** |
-| Divide | `/` | `/.` | In Gleam both values must be **Float** |
-| Remainder | `%` | `%` | In Gleam both values must be **Int** |
-| Concatenate | `.` | `<>` | In Gleam both values must be **String**
-| Pipe | `->` | |>
| Gleam's pipe can chain function calls. See note for Go |
-
-### Notes on operators
-
-- For bitwise operators, which exist in Go but not in Gleam,
- see: .
-- `==` is by default comparing by value in Go:
- - Types may be autocast to be compareable.
- - Two objects with the same members values will equal:
-- `===` is for comparing by strict equality in Go:
- - Types will not be autocast for comparison
- - Two objects with the same members will not equal. Only if a variable binds
- to the same reference it will equal.
-- Go operators are short-circuiting as in Gleam.
-- Chains and pipes:
- - In Go chaining is usually done by constructing class methods that return
- an object: `$foo->bar(1)->quux(2)` means `bar(1)` is called as a method
- of `$foo` and then `quux()` is called as a method of the return value
- (object) of the `bar(1)` call. The objects in this chain usually
- mutate to keep the changed state and carry it forward in the chain.
- - In contrast in Gleam piping, no objects are being returned but mere data
- is pushed from left to right much like in unix tooling.
-
-## Constants
-
-### Go
-
-In Go, constants can only be defined within classes and traits.
-
-```Go
-class TheQuestion {
- public const theAnswer = 42;
-}
-echo TheQuestion::theAnswer; // 42
-```
-
-### Gleam
-
-In Gleam constants can be created using the `const` keyword.
-
-```gleam
-// the_question.gleam module
-const the_answer = 42
-
-pub fn main() {
- the_answer
-}
-```
-
-They can also be marked public via the `pub` keyword and will then be
-automatically exported.
-
-## Blocks
-
-### Go
-
-Go blocks are always associated with a function / conditional / loop or
-similar declaration. Blocks are limited to specific language constructs.
-There is no way to create multi-line expressions blocks like in Gleam.
-
-Blocks are declared via curly braces.
-
-```Go
-function a_func() {
- // A block starts here
- if ($foo) {
- // A block here
- } else {
- // A block here
- }
- // Block continues
-}
-```
-
-### Gleam
-
-In Gleam curly braces, `{` and `}`, are used to group expressions.
-
-```gleam
-pub fn main() {
- let x = {
- some_function(1)
- 2
- }
- // Braces are used to change precedence of arithmetic operators
- let y = x * {x + 10}
- y
-}
-```
-
-Unlike in Go, in Gleam function blocks are always expressions, so are `case`
-blocks or arithmetic sub groups. Because they are expressions they always
-return a value.
-
-For Gleam the last value in a block's expression is always the value being
-returned from an expression.
-
-## Data types
-
-### Strings
-
-In Go strings are stored as an array of bytes and an integer indicating the
-length of the buffer. Go itself has no information about how those bytes
-translate to characters, leaving that task to the programmer. Go's
-standard library however features a bunch of multi-byte compatible functions
-and conversion functions between UTF-8, ISO-8859-1 and further encodings.
-
-Go strings allow interpolation.
-
-In Gleam all strings are UTF-8 encoded binaries. Gleam strings do not allow
-interpolation, yet. Gleam however offers a `string_builder` via its standard
-library for performant string building.
-
-#### Go
-
-```Go
-$what = 'world';
-'Hellø, world!';
-"Hellø, ${what}!";
-```
-
-#### Gleam
-
-```gleam
-"Hellø, world!"
-```
-
-### Tuples
-
-Tuples are very useful in Gleam as they're the only collection data type that
-allows mixed types in the collection.
-
-#### Go
-
-Go does not really support tuples, but its array type can easily be used to
-mimick tuples. Unpacking can be used to bind a name to a specific value of
-the tuple.
-
-```Go
-$myTuple = ['username', 'password', 10];
-[$_, $pwd, $_] = $myTuple;
-echo $pwd; // "password"
-// Direct index access
-echo $myTuple[0]; // "username"
-```
-
-#### Gleam
-
-```gleam
-let my_tuple = #("username", "password", 10)
-let #(_, pwd, _) = my_tuple
-io.print(pwd) // "password"
-// Direct index access
-io.print(my_tuple.0) // "username"
-```
-
-### Lists
-
-Arrays in Go are allowed to have values of mixed types, but not in Gleam.
-
-#### Go
-
-Go does not feature special syntax for list handling.
-
-```Go
-$list = [2, 3, 4];
-$head = array_slice($list, 0, 1)[0];
-$tail = array_slice($list, 1);
-# $head == 2
-# $tail == [3, 4]
-$arr = array_merge($tail, [1.1]);
-# $arr == [3, 4, 1.1]
-```
-
-#### Gleam
-
-Gleam has a `cons` operator that works for lists destructuring and
-pattern matching. In Gleam lists are immutable so adding and removing elements
-from the start of a list is highly efficient.
-
-```gleam
-let list = [2, 3, 4]
-let list = [1, ..list]
-let [1, second_element, ..] = list
-[1.0, ..list] // compile error, type mismatch
-```
-
-### Maps
-
-In Go, the `array` type also covers maps and can have keys of any type as long as:
-
-- the key type is `null`, an `int`, a `string` or a `bool` (some conversions
- occur, such as null to `""` and `false` to `0` as well as `true` to `1`
- and `"1"` to `1`. Float indexes, which are not representing integers
- indexes are deprecated due to being auto downcast to integers).
-- the key is unique in the dictionary.
-- the values are of any type.
-
-In Gleam, maps can have keys and values of any type, but all keys must be of
-the same type in a given map and all values must be of the same type in a
-given map. The type of key and value can differ from each other.
-
-There is no map literal syntax in Gleam, and you cannot pattern match on a map.
-Maps are generally not used much in Gleam, custom types are more common.
-
-#### Go
-
-```Go
-["key1" => "value1", "key2" => "value2"]
-["key1" => "1", "key2" => 2]
-```
-
-#### Gleam
-
-```gleam
-import gleam/map
-
-map.from_list([#("key1", "value1"), #("key2", "value2")])
-map.from_list([#("key1", "value1"), #("key2", 2)]) // Type error!
-```
-
-### Numbers
-
-Go and Gleam both support `Integer` and `Float`. Integer and Float sizes for
-both depend on the platform: 64-bit or 32-bit hardware and OS and for Gleam
-JavaScript and Erlang.
-
-#### Go
-
-While Go differentiates between integers and floats it automatically converts
-floats and integers for you, removing precision or adding floating point
-decimals.
-
-```Go
-1 / 2 // 0.5
-```
-
-#### Gleam
-
-```gleam
-1 / 2 // 0
-1.5 + 10 // Compile time error
-```
-
-You can use the gleam standard library's `int` and `float` modules to convert
-between floats and integers in various ways including `rounding`, `floor`,
-`ceiling` and many more.
-
-## Flow control
-
-### Case
-
-Case is one of the most used control flow in Gleam. It can be seen as a switch
-statement on steroids. It provides a terse way to match a value type to an
-expression. It is also used to replace `if`/`else` statements.
-
-#### Go
-
-Go features 3 different expressions to achieve similar goals:
-
-- `if`/`else if`/`else` (does not return)
-- `switch`/`case`/`break`/`default` (does not return, does not autobreak)
-- `match` (returns)
-
-```Go
-function http_error_impl_1($status) {
- if ($status === 400) {
- return "Bad request";
- } else if ($status === 404) {
- return "Not found";
- } else if ($status === 418) {
- return "I'm a teapot";
- } else {
- return "Internal Server Error";
- }
-}
-
-function http_error_impl_2($status) {
- switch ($status) {
- case "400": // Will work because switch ($status) compares non-strict as in ==
- return "Bad request";
- break; // Not strictly required here, but combined with weak typing multiple cases could be executed if break is omitted
- case 404:
- return "Not found";
- break;
- case 418:
- return "I'm a teapot";
- break;
- default:
- return "Internal Server Error";
- }
-}
-
-function http_error_impl_3($status) {
- return match($status) { // match($status) compares strictly
- 400 => "Bad request",
- 404 => "Not found",
- 418 => "I'm a teapot",
- default => "Internal Server Error"
- };
-}
-```
-
-#### Gleam
-
-The case operator is a top level construct in Gleam:
-
-```gleam
-case some_number {
- 0 -> "Zero"
- 1 -> "One"
- 2 -> "Two"
- n -> "Some other number" // This matches anything
-}
-```
-
-As all expressions the case expression will return the matched value.
-
-They can be used to mimick if/else or if/elseif/else, with the exception that
-any branch must return unlike in Go, where it is possible to mutate a
-variable of the outer block/scope and not return at all.
-
-```gleam
-let is_status_within_4xx = status / 400 == 1
-case status {
- 400 -> "Bad Request"
- 404 -> "Not Found"
- _ if is_status_within_4xx -> "4xx" // This works as of now
- // status if status / 400 == 1 -> "4xx" // This will work in future versions of Gleam
- _ -> "I'm not sure"
-}
-```
-
-if/else example:
-
-```gleam
-case is_admin {
- True -> "allow access"
- False -> "disallow access"
-}
-```
-
-if/elseif/else example:
-
-```gleam
-case True {
- _ if is_admin == True -> "allow access"
- _ if is_confirmed_by_mail == True -> "allow access"
- _ -> "deny access"
-}
-```
-
-Exhaustiveness checking at compile time, which is in the works, will make
-certain that you must check for all possible values. A lazy and common way is
-to check of expected values and have a catchall clause with a single underscore
-`_`:
-
-```gleam
-case scale {
- 0 -> "none"
- 1 -> "one"
- 2 -> "pair"
- _ -> "many"
-}
-```
-
-The case operator especially coupled with destructuring to provide native pattern
-matching:
-
-```gleam
-case xs {
- [] -> "This list is empty"
- [a] -> "This list has 1 element"
- [a, b] -> "This list has 2 elements"
- _other -> "This list has more than 2 elements"
-}
-```
-
-The case operator supports guards:
-
-```gleam
-case xs {
- [a, b, c] if a >. b && a <=. c -> "ok"
- _other -> "ko"
-}
-```
-
-...and disjoint union matching:
-
-```gleam
-case number {
- 2 | 4 | 6 | 8 -> "This is an even number"
- 1 | 3 | 5 | 7 -> "This is an odd number"
- _ -> "I'm not sure"
-}
-```
-
-### Piping
-
-In Gleam most functions, if not all, are data first, which means the main data
-value to work on is the first argument. By this convention and the ability to
-specify the argument to pipe into, Gleam allows writing functional, immutable
-code, that reads imperative-style top down, much like unix tools and piping.
-
-#### Go
-
-Go does not offer pipes but it can chain calls by making functions return
-objects which in turn ship with their list of methods.
-
-```Go
-// Imaginary Go code
-(new Session($request))
- ->authorize()
- ->setSuccessFlash('Logged in successfully!')
- ->setFailureFlash('Failed to login!')
- ->redirectToRequestedUrl();
-```
-
-#### Gleam
-
-```gleam
-// Imaginary Gleam code
-request
-|> session.new()
-|> session.authorize()
-|> flash.set_success_flash('Logged in successfully!')
-|> flash.set_failure_flash('Failed to login!')
-|> response.redirect_to_requested_url()
-```
-
-Despite being similar to read and comprehend, the Go code creates a session
-object, and calls the authorize method of the session object: That session
-object then returns another object, say an `AuthorizedUser` object - you don't
-know by looking at the code what object gets returned. However you know it must
-implement a `setSuccessFlash` method. At the last step of the chain `redirect`
-is called on an object returned from `setFailureFlash`.
-
-In the Gleam code the request data is piped into `session.new()`'s first
-argument and that return value is piped further down. It is readability sugar
-for:
-
-```gleam
-response.redirect_to_requested_url(
- flash.set_failure_flash(
- flash.set_success_flash(
- session.authorize(
- session.new(request)
- ),
- 'Logged in successfully!'
- ),
- 'Failed to login!'
- )
-)
-```
-
-### Try
-
-Error management is approached differently in Go and Gleam.
-
-#### Go
-
-Go uses the notion of exceptions to interrupt the current code flow and
-pop up the error to the caller.
-
-An exception is raised using the keyword `throw`.
-
-```Go
-function aFunctionThatFails() {
- throw new RuntimeException('an error');
-}
-```
-
-The callee block will be able to capture any exception raised in the block
-using a `try/except` set of blocks:
-
-```Go
-// callee block
-try {
- echo 'this line will be executed and thus printed';
- aFunctionThatFails()
- echo 'this line will not be executed and thus not printed';
-} catch (Throwable $e) {
- var_dump(['doing something with the exception', $e]);
-}
-```
-
-#### Gleam
-
-In contrast in gleam, errors are just containers with an associated value.
-
-A common container to model an operation result is
-`Result(ReturnType, ErrorType)`.
-
-A `Result` is either:
-
-- an `Error(ErrorValue)`
-- or an `Ok(Data)` record
-
-Handling errors actually means to match the return value against those two
-scenarios, using a case for instance:
-
-```gleam
-case parse_int("123") {
- Ok(i) -> io.println("We parsed the Int")
- Error(e) -> io.println("That wasn't an Int")
-}
-```
-
-In order to simplify this construct, we can use the `try` keyword that will:
-
-- either bind a value to the providing name if `Ok(Something)` is matched,
-- or **interrupt the current block's flow** and return `Error(Something)` from
- the given block.
-
-```gleam
-let a_number = "1"
-let an_error = Error("ouch")
-let another_number = "3"
-
-try int_a_number = parse_int(a_number)
-try attempt_int = parse_int(an_error) // Error will be returned
-try int_another_number = parse_int(another_number) // never gets executed
-
-Ok(int_a_number + attempt_int + int_another_number) // never gets executed
-```
-
-## Type aliases
-
-Type aliases allow for easy referencing of arbitrary complex types.
-Go does not have this feature, though either regular classes or static classes
-can be used to design custom types and class definitions in take can be aliased
-using `class_alias()`.
-
-### Go
-
-A simple variable can store the result of a compound set of types.
-
-```Go
-static class Point {
- // Can act as an opaque type and utilize Point
- // Can be class_aliased to Coordinate
-}
-
-static class Triangle {
- // Can act as an opaque type definition and utilize Point
-}
-```
-
-### Gleam
-
-The `type` keyword can be used to create aliases.
-
-```gleam
-pub type Headers =
- List(#(String, String))
-```
-
-## Custom types
-
-### Records
-
-Custom type allows you to define a collection data type with a fixed number of
-named fields, and the values in those fields can be of differing types.
-
-#### Go
-
-Go uses classes to define user-defined, record-like types.
-Properties are defined as class members and initial values are generally set in
-the constructor.
-
-By default the constructor does not provide base initializers in the
-constructor so some boilerplate is needed:
-
-```Go
-class Person {
- public string $name;
- public int $age;
- function __construct(string $name, int $age) {
- $this->name = $name;
- $this->age = $age;
- }
-}
-$person = new Person(name: "Joe", age: 40);
-// $person->name // Joe;
-```
-
-#### Gleam
-
-Gleam's custom types can be used as structs. At runtime, they have a tuple
-representation and are compatible with Erlang records (or JavaScript objects).
-
-```gleam
-type Person {
- Person(name: String, age: Int)
-}
-
-let person = Person(name: "Joe", age: 40)
-let name = person.name
-```
-
-An important difference to note is there is no Java-style object-orientation in
-Gleam, thus methods can not be added to types. However opaque types exist,
-see below.
-
-### Unions
-
-Go generally does not support unions with a few exceptions such as:
-
-- type x or `null`
-- `Array` or `Traversable`.
-
-In Gleam functions must always take and receive one type. To have a union of
-two different types they must be wrapped in a new custom type.
-
-#### Go
-
-```Go
-class Foo {
- public ?string $aStringOrNull;
-}
-```
-
-#### Gleam
-
-```gleam
-type IntOrFloat {
- AnInt(Int)
- AFloat(Float)
-}
-
-fn int_or_float(X) {
- case X {
- True -> AnInt(1)
- False -> AFloat(1.0)
- }
-}
-```
-
-### Opaque custom types
-
-In Go, constructors can be marked as private and opaque types can either be
-modelled in an immutable way via static classes or in a mutable way via
-a factory pattern.
-
-In Gleam, custom types can be defined as being opaque, which causes the
-constructors for the custom type not to be exported from the module. Without
-any constructors to import other modules can only interact with opaque types
-using the intended API.
-
-#### Go
-
-```Go
-class PointObject
-{
- private int $x;
- private int $y;
-
- private function __construct(int $x, int $y) {
- $this->x = $x;
- $this->y = $y;
- }
-
- public static function spawn(int $x, int $y) {
- if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
- return new self($x, $y);
- }
- return false;
- }
-}
-PointObject::spawn(1, 2); // Returns a Point object
-```
-
-This requires mutation, but prohibits direct property changes.
-
-Go allows to skip object mutation by using static classes:
-
-```Go
-class PointStruct
-{
- public static function spawn(int $x, int $y) {
- if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
- return compact('x', 'y') + ['struct' => __CLASS__];
- }
- return false;
- }
-}
-PointStruct::spawn(1, 2); // Returns an array managed by PointStruct
-```
-
-However Go will in this case not prohibit the direct alteration the returned
-structure, like Gleam's custom types can.
-
-#### Gleam
-
-```gleam
-// In the point.gleam opaque type module:
-pub opaque type Point {
- Point(x: Int, y: Int)
-}
-
-pub fn spawn(x: Int, y: Int) -> Result(Point, Nil) {
- case x >= 0 && x <= 99 && y >= 0 && y <= 99 {
- True -> Ok(Point(x: x, y: y))
- False -> Error(Nil)
- }
-}
-
-// In the main.gleam module
-pub fn main() {
- assert Ok(point) = Point.spawn(1, 2)
- point
-}
-```
-
-## Modules
-
-### Go
-
-Go does not feature modules, but many other containers such as classes, traits
-and interfaces. Historically a single file can contain many classes, traits and
-interfaces one after another, though it is best practise to only contain one
-such declaration per file.
-
-Using Go namespaces, these can be placed in a registry that does not need to
-map to the source code file system hierarchy, but by convention should.
-
-In `src/Foo/Bar.Go`:
-
-```Go
-// Anything declared in this file will be inside namespace Foo
-namespace Foo;
-
-// Creation of (static) class Bar in Foo, thus as Foo/Bar
-class Bar {
- public static function identity($x) {
- return $x;
- }
-}
-```
-
-Making the static class available in the local scope and calling the function
-`index.Go` (aka Go's main function):
-
-```Go
-// After auto-loading has happened
-use Foo\Bar;
-
-Bar::identity(1) // 1;
-```
-
-### Gleam
-
-Coming from Go the closest thing Go has that are similar to Gleam's modules
-are static classes: Collections of functions and constants grouped into a
-static class.
-
-In comparison Gleam modules can also contain custom types.
-
-A gleam module name corresponds to its file name and path.
-
-Since there is no special syntax to create a module, there can be only one
-module in a file and since there is no way name the module the filename
-always matches the module name which keeps things simple and transparent.
-
-In `/src/foo/bar.gleam`:
-
-```gleam
-// Creation of module function identity
-// in module bar
-pub fn identity(x) {
- x
-}
-```
-
-Importing the `bar` module and calling a module function:
-
-```gleam
-// In src/main.gleam
-import foo/bar // if foo was in a directory called `lib` the import would be `lib/foo/bar`.
-
-pub fn main() {
- bar.identity(1) // 1
-}
-```
-
-### Imports
-
-#### Go
-
-Go features ways to load arbitrary Go code: `require`, `include` and
-autoload such as `spl_autoload_register`. Once class pathes are known and
-registered for autoloading, they can brought into the scope of a file by using
-the `use`statement which is part of Go's namespacing.
-Also see .
-
-Inside `src/Nasa/MoonBase.Go`
-
-```Go
-// Makes available src/nasa/RocketShip.Go
-use Nasa\RocketShip;
-
-class MoonBase {
- public static function exploreSpace() {
- RocketShip::launch();
- }
-}
-```
-
-#### Gleam
-
-Imports are relative to the app `src` folder.
-
-Modules in the same directory will need to reference the entire path from `src`
-for the target module, even if the target module is in the same folder.
-
-Inside module `src/nasa/moon_base.gleam`:
-
-```gleam
-// imports module src/nasa/rocket_ship.gleam
-import nasa/rocket_ship
-
-pub fn explore_space() {
- rocket_ship.launch()
-}
-```
-
-### Named imports
-
-#### Go
-
-Go features namespaces which can be used to rename classes when they clash:
-
-```Go
-// Source files must first be added to the auto-loader
-use Unix\Cat;
-use Animal\Cat as Kitty;
-// Cat and Kitty are available
-```
-
-#### Gleam
-
-Gleam has as similar feature:
-
-```gleam
-import unix/cat
-import animal/cat as kitty
-// cat and kitty are available
-```
-
-This may be useful to differentiate between multiple modules that would have the same default name when imported.
-
-### Unqualified imports
-
-#### Go
-
-```Go
-use Animal\Cat{
- Cat,
- function stroke
-};
-```
-
-```Go
-$kitty = new Cat(name: "Nubi");
-stroke($kitty);
-```
-
-#### Gleam
-
-```gleam
-import animal/cat.{
- Cat,
- stroke
-}
-
-pub fn main() {
- let kitty = Cat(name: "Nubi")
- stroke(kitty)
-}
-```
-
-Importing common types such as `gleam/order.{Lt, Eq, Gt}` or
-`gleam/option.{Some,None}` can be very helpful.
-
-## Architecture
-
-To iterate a few foundational differences:
-
-1. Programming model: Java-style object-orientation VS functional immutable
- programming
-2. Guarantees: weak dynamic typing VS strong static typing
-3. Runtime model: request-response script VS Erlang/OTP processes
-4. Error handling: exceptions VS result type
-5. Language reach
-
-### Programming model
-
-- Go mixes imperative, Java-style object-orientation and functional code
- styles. Gleam offers only functional code style, though it can appear
- imperative and reads easily thanks to pipes.
-- In Gleam, data structures are never mutated but always updated into new
- structures. This allows processes that fail to simply restart as there are no
- mutated objects that can be in an invalid state and take the whole
- application down (such as in Go, Ruby or Go).
-- Gleam offers syntax to make it easy to extract data out of custom types and
- update data into new copies of custom types without ever mutating variables.
- Go sometimes directly mutates references of simple values such as when using
- `reset()` or `end()` or `array_pop()`.
-- Gleam allows to rebind variables freely to make it easy to update data
- structures by making a copy and binding it to the existing variable.
-- Go features a massive, powerful but inconsistent standard library that is
- always loaded and partially extended and deprecated with new Go releases.
-- Gleam allows you to opt into a smaller, well polished and consistent standard
- library.
-
-### Guarantees and types
-
-- Go features opt-in static typing which is only checked at runtime.
-- Go values tend to be automatically cast for comparison purposes or when used
- as indexes in arrays. Gleam values are not automatically cast.
-- Go allows comparison between most if not all values, even if it does not
- make any sense say comparing a file `resource` to a `Date` in terms of order.
- Gleam's comparison operators are very strict and limited, any other
- comparisons and conversions must happen via function calls.
-- Go's checks happen at runtime, Gleam's checks (for the most part) do not
- and rely on the compiler to allow only type safe and sound code to be
- compiled.
-- Gleam's type inference allows you to be lazy for almost all type definitions.
- Gleam's type system will always assist you in what types are expected and/or
- conflicting. Gleam's type system will help you discover APIs.
-
-### Runtime model
-
-- Gleam can run on Erlang/BEAM, on the browser but also Deno or NodeJS.
-- For Gleam on Erlang/BEAM the runtime model has some striking similarities
- in practise: In Go a script starts and runs. It allocates memory for this
- script and frees it upon end or after the max execution time is exceeded
- or the memory limit is exceeded.
-- Gleam on Erlang/BEAM allows to processes requests in a similar isolation
- level that Go offers in contrast to applications running *Go* or *Ruby*.
- The level of isoluation means that, very similar to Go, if a process
- crashes (in Go read: if a request crashes) then the supervision system
- can restart that process or after a while or amount of tries abort
- repeating restarts on the process with that given input data. This means
- Erlang/BEAM will yield similar robustness that Go developers are used
- to and similar isolation guarantuees.
-- When executing Gleam code in fact its compiled Erlang or JavaScript is
- executed. So in case there are runtime crashes, the crash log will show
- Erlang (or browser-console/NodeJS/Deno) debug information. In Gleam
- applications runtime errors should almost never happen but they are harder
- to read, in Go applications runtime errors much more often and are easier
- to read.
-
-### Error handling
-
-- Gleam will catch all errors that are expected to happen via the `Result`
- type. There can however be other errors, such as miss-behavior due
- accidental to division by 0, crashes on RAM or storage limits, hardware
- failures, etc. In these cases on the BEAM there are ways to manage these
- via BEAM's supervision trees.
-- In contrast Go will use exceptions to handle errors and by doing so blurs
- the line between expected errors and unexpected errors. Also function
- signatures are enlarged de-facto by whatever exceptions they can throw
- and thus function calls and return types become much harder to manage.
-
-### Language reach
-
-- Go is tailored towards web applications, servers, and static to low-dynamic
- frontends.
-- Gleam can be utilized as a JavaScript replacement to drive your frontend
- application not just your backend web server.
-- Gleam on Erlang/BEAM can be used to write non-blocking, massively concurrent
- server applications comparable to RabbitMQ or multiplayer game servers.---
-layout: page
-title: Gleam for Go users
-subtitle: Hello Hypertext crafters!
----
-
-- [Comments](#comments)
-- [Variables](#variables)
- - [Match operator](#match-operator)
- - [Variables type annotations](#variables-type-annotations)
-- [Functions](#functions)
- - [Exporting functions](#exporting-functions)
- - [Function type annotations](#function-type-annotations)
- - [Referencing functions](#referencing-functions)
- - [Labelled arguments](#labelled-arguments)
-- [Operators](#operators)
-- [Constants](#constants)
-- [Blocks](#blocks)
-- [Data types](#data-types)
- - [Strings](#strings)
- - [Tuples](#tuples)
- - [Lists](#lists)
- - [Maps](#maps)
- - [Numbers](#numbers)
-- [Flow control](#flow-control)
- - [Case](#case)
- - [Piping](#piping)
- - [Try](#try)
-- [Type aliases](#type-aliases)
-- [Custom types](#custom-types)
- - [Records](#records)
- - [Unions](#unions)
- - [Opaque custom types](#opaque-custom-types)
-- [Modules](#modules)
- - [Imports](#imports)
- - [Named imports](#named-imports)
- - [Unqualified imports](#unqualified-imports)
-- [Architecture](#architecture)
-
-## Comments
-
-### Go
-
-In Go, comments are written with a `//` prefix.
-
-```Go
-// Hello, Joe!
-```
-
-Multi line comments may be written like so:
-
-```Go
-/*
- * Hello, Joe!
- */
-```
-
-IN Go, above `trait`, `interface`, `class`, `member`, `function` declarations
-there can be `docblocks` like so:
-
-```Go
-/**
- * a very special trait.
- */
-trait Foo {}
-
-/**
- * A Bar class
- */
-class Bar {}
-
-/**
- * A quux function.
- *
- * @var string $str String passed to quux
- * @return string An unprocessed string
- */
-function quux(string $str) : string { return $str; }
-```
-
-Documentation blocks (docblocks) are extracted into generated API
-documentation.
-
-### Gleam
-
-In Gleam, comments are written with a `//` prefix.
-
-```gleam
-// Hello, Joe!
-```
-
-Comments starting with `///` are used to document the following function,
-constant, or type definition. Comments starting with `////` are used to
-document the current module.
-
-```gleam
-//// This module is very important.
-
-/// The answer to life, the universe, and everything.
-const answer: Int = 42
-
-/// A main function
-fn main() {}
-
-/// A Dog type
-type Dog {
- Dog(name: String, cuteness: Int)
-}
-```
-
-`//` comments are not used while generating documentation files, while
-`////` and `///` will appear in them.
-
-## Variables
-
-You can rebind variables in both languages.
-
-### Go
-
-```Go
-$size = 50;
-$size = $size + 100;
-$size = 1;
-```
-
-In local scope Go has no specific variable keyword. You choose a name
-and that's it!
-
-In class scope for property declaration Go uses at least one related
-modifier keyword to create properties such as: `public`, `private`,
-`protected`, `static` or `readonly` (`var` is deprecated).
-
-### Gleam
-
-Gleam has the `let` keyword before its variable names.
-
-```gleam
-let size = 50
-let size = size + 100
-let size = 1
-```
-
-### Match operator
-
-#### Go
-
-Go supports basic, one directional destructuring (also called unpacking).
-Tuple of values can be unpacked and inner values can be assigned to left-hand
-variable names.
-
-```Go
-[$a, $b] = [1, 2];
-// $a == 1
-// $b == 2
-
-[1 => $idx2] = ['foo', 'bar', 'quux'];
-// $idx2 == 'bar'
-
-["profession" => $job] = ['name' => 'Joe', 'profession' => 'hacker'];
-// $job == 'hacker'
-```
-
-#### Gleam
-
-In Gleam, `let` and `=` can be used for pattern matching, but you'll get
-compile errors if there's a type mismatch, and a runtime error if there's
-a value mismatch. For assertions, the equivalent `let assert` keyword is
-preferred.
-
-```gleam
-let #(a, _) = #(1, 2)
-// a = 1
-// `_` matches 2 and is discarded
-
-let assert [] = [1] // runtime error
-let assert [y] = "Hello" // compile error, type mismatch
-```
-
-Asserts should be used with caution.
-
-### Variables type annotations
-
-#### Go
-
-Go is a dynamically typed language. Types are only checked at runtime and
-a variable can have different types in its lifetime.
-
-Go gradually introduced more and more type hints that are optional.
-The type information is accessible via `get_type()` at runtime.
-
-These hints will mainly be used to inform static analysis tools like IDEs,
-linters, etc.
-
-```Go
-class Foo {
- private ?string $bar;
-}
-```
-
-As Go's `array` structure is a combination of maps and arrays.
-The Go manual states that it is an *ordered map*.
-While creating arrays in Go the type of its elements cannot be set explicitly
-and each element can be of a different type:
-
-```Go
-$someList = [1, 2, 3];
-$someTuple = [1, "a", true];
-$someMap = [0 => 1, "foo" => "bar", true => false];
-```
-
-Single variables cannot be type-annotated unless they are `class` or `trait`
-members.
-
-#### Gleam
-
-In Gleam type annotations can optionally be given when binding variables.
-
-```gleam
-let some_list: List(Int) = [1, 2, 3]
-let some_string: String = "Foo"
-```
-
-Gleam will check the type annotation to ensure that it matches the type of the
-assigned value. It does not need annotations to type check your code, but you
-may find it useful to annotate variables to hint to the compiler that you want
-a specific type to be inferred.
-
-## Functions
-
-### Go
-
-In Go, you can define functions with the `function` keyword. One or many `return`
-keywords are optional.
-
-```Go
-function hello($name = 'Joe') : string
-{
- if ($name = 'Joe') {
- return 'Welcome back, Joe!';
- }
- return "Hello $name";
-}
-
-function noop()
-{
- // Will automatically return NULL
-}
-```
-
-Anonymous functions returning a single expression can also be defined and be
-bound to variables.
-
-```Go
-$x = 2
-$GoAnonFn = function($y) use ($x) { return $x * $y; }; // Creates a new scope
-$GoAnonFn(2, 3); // 6
-$GoArrowFn = ($x) => $x * $y; // Inherits the outer scope
-$GoArrowFn(2, 3); // 6
-```
-
-### Gleam
-
-Gleam's functions are declared like so:
-
-```gleam
-fn sum(x, y) {
- x + y
-}
-```
-
-Gleam's anonymous functions have the same basic syntax.
-
-```gleam
-let mul = fn(x, y) { x * y }
-mul(1, 2)
-```
-
-A difference between Go's and Gleam's anonymous functions is that in Go they
-create a new local scope, in Gleam they close over the local scope, aka create
-a copy and inherit all variables in the scope. This means that in Gleam you can
-shadow local variables within anonymous functions but you cannot influence the
-variable bindings in the outer scope. This is different for Go's arrow
-functions where they inherit the scope like Gleam does.
-
-The only difference between module functions and anonymous functions in Gleam
-is that module functions heads may also feature argument labels, like so:
-
-```gleam
-// In some module.gleam
-pub fn distance(from x: Int, to y: Int) : Int {
- abs(x) - abs(y) |> abs()
-}
-// In some other function
-distance(from: 1, to: -2) // 3
-```
-
-### Exporting functions
-
-#### Go
-
-In Go, top level functions are exported by default. There is no notion of
-private module-level functions.
-
-However at class level, all properties are public, by default.
-
-```Go
-class Foo {
- static $bar = 5;
- private $quux = 6;
-
- static function batz() {
- return "Hello Joe!";
- }
-
- private static function kek() {
- return "Hello Rasmus!";
- }
-}
-echo Foo::$bar; // 5
-echo Foo::$quux; // Error
-echo Foo::batz(); // "Hello Joe"
-echo Foo::kek(); // Error
-```
-
-#### Gleam
-
-In Gleam, functions are private by default and need the `pub` keyword to be
-marked as public.
-
-```gleam
-// this is public
-pub fn sum(x, y) {
- x + y
-}
-
-// this is private
-fn mul(x, y) {
- x * y
-}
-```
-
-### Go
-
-Global functions may exist in a global scope, and to execute functions or
-create objects and invoke methods at some point they have to be called from
-the global scope. Usually there is one `index.Go` file whose global scope
-acts as if it was the `main()` function.
-
-### Gleam
-
-Gleam does not support a global scope. Instead Gleam code is either
-representing a library, which can be required as a dependency, and/or it
-represents an application having a main module, whose name must match to the
-application name and within that `main()`-function which will be called via
-either `gleam run` or when the `entrypoint.sh` is executed.
-
-In contrast to Go, where any Go file can contain a global scope that can
-be invoked by requiring the file, in Gleam only code that is within functions
-can be invoked.
-
-On the Beam, Gleam code can also be invoked from other Erlang code, or it
-can be invoked from browser's JavaScript, Deno or NodeJS runtime calls.
-
-### Function type annotations
-
-#### Go
-
-Type hints can be used to optionally annotate function arguments and return
-types.
-
-Discrepancies between type hints and actual values at runtime do not prevent
-interpretation of the code. Static code analysers (IDE tooling, type checkers
-like `Gostan`) will be required to detect those errors.
-
-```Go
-function sum(int $x, int $y) : int {
- return $x + $y;
-}
-
-function mul(int $x, int $y) : bool {
- # no errors from the interpreter.
- return $x * $y;
-}
-```
-
-#### Gleam
-
-Functions can **optionally** have their argument and return types annotated in
-Gleam. These type annotations will always be checked by the compiler and throw
-a compilation error if not valid. The compiler will still type check your
-program using type inference if annotations are omitted.
-
-```gleam
-fn add(x: Int, y: Int) -> Int {
- x + y
-}
-
-fn mul(x: Int, y: Int) -> Bool {
- x * y // compile error, type mismatch
-}
-```
-
-### Referencing functions
-
-#### Go
-
-As long as functions are in scope they can be assigned to a new variable.
-As methods or static functions classes, functions can be accessed via
-`$this->object_instance_method()` or `self::static_class_function()`.
-
-Other than that only anonymous functions can be moved around the same way as
-other values.
-
-```Go
-$doubleFn = function($x) { return $x + $x; };
-// Some imaginary pushFunction
-pushFunction($queue, $doubleFn);
-```
-
-However in `Go` it is not possible to pass around global, class or instance
-functions as values.
-
-#### Gleam
-
-Gleam has a single namespace for constants and functions within a module, so
-there is no need for a special syntax to assign a module function to a
-variable.
-
-```gleam
-fn identity(x) {
- x
-}
-
-fn main() {
- let func = identity
- func(100)
-}
-```
-
-### Labelled arguments
-
-Both Go and Gleam have ways to give arguments names and in any order.
-
-#### Go
-
-When calling a function, arguments can be passed:
-
-- positionally, in the same order of the function declaration
-- by name, in any order
-
-```Go
-// Some imaginary replace function
-function replace(string $each, string $with, string $inside) {
- // TODO implementation
-}
-// Calling with positional arguments:
-replace(",", " ", "A,B,C")
-// Calling with named arguments:
-replace(inside: "A,B,C", each: ",", with: " ")
-```
-
-#### Gleam
-
-In Gleam arguments can be given a label as well as an internal name.
-Contrary to Go, the name used at the call-site does not have to match
-the name used for the variable inside the function.
-
-```gleam
-pub fn replace(inside str, each pattern, with replacement) {
- todo
-}
-```
-
-```gleam
-replace(",", " ", "A,B,C")
-replace(inside: "A,B,C", each: ",", with: " ")
-```
-
-There is no performance cost to Gleam's labelled arguments as they are
-optimised to regular function calls at compile time, and all the arguments
-are fully type checked.
-
-## Operators
-
-| Operator | Go | Gleam | Notes |
-| ------------------ | ------ | ------------------------- | -------------------------------------------------------------------------------------- |
-| Equal | `==` | `==` | In Gleam both values must be of the same type |
-| Strictly equal to | `===` | `==` | Comparison in Gleam is always strict. (see note for Go) |
-| Reference equality | `instanceof` | | True only if an object is an instance of a class |
-| Not equal | `!=` | `!=` | In Gleam both values must be of the same type |
-| Not equal | `!==` | `!=` | Comparison in Gleam is always strict (see note for Go) |
-| Greater than | `>` | `>` | In Gleam both values must be **Int** |
-| Greater than | `>` | `>.` | In Gleam both values must be **Float** |
-| Greater or equal | `>=` | `>=` | In Gleam both values must be **Int** |
-| Greater or equal | `>=` | `>=.` | In Gleam both values must be **Float** |
-| Less than | `<` | `<` | In Gleam both values must be **Int** |
-| Less than | `<` | `<.` | In Gleam both values must be **Float** |
-| Less or equal | `<=` | `<=` | In Gleam both values must be **Int** |
-| Less or equal | `<=` | `<=.` | In Gleam both values must be **Float** |
-| Boolean and | `&&` | `&&` | In Gleam both values must be **Bool** |
-| Logical and | `&&` | | Not available in Gleam |
-| Boolean or | ||
| ||
| In Gleam both values must be **Bool** |
-| Logical or | ||
| | Not available in Gleam |
-| Boolean not | `xor` | | Not available in Gleam |
-| Boolean not | `!` | `!` | In Gleam both values must be **Bool** |
-| Add | `+` | `+` | In Gleam both values must be **Int** |
-| Add | `+` | `+.` | In Gleam both values must be **Float** |
-| Subtract | `-` | `-` | In Gleam both values must be **Int** |
-| Subtract | `-` | `-.` | In Gleam both values must be **Float** |
-| Multiply | `*` | `*` | In Gleam both values must be **Int** |
-| Multiply | `*` | `*.` | In Gleam both values must be **Float** |
-| Divide | `/` | `/` | In Gleam both values must be **Int** |
-| Divide | `/` | `/.` | In Gleam both values must be **Float** |
-| Remainder | `%` | `%` | In Gleam both values must be **Int** |
-| Concatenate | `.` | `<>` | In Gleam both values must be **String**
-| Pipe | `->` | |>
| Gleam's pipe can chain function calls. See note for Go |
-
-### Notes on operators
-
-- For bitwise operators, which exist in Go but not in Gleam,
- see: .
-- `==` is by default comparing by value in Go:
- - Types may be autocast to be compareable.
- - Two objects with the same members values will equal:
-- `===` is for comparing by strict equality in Go:
- - Types will not be autocast for comparison
- - Two objects with the same members will not equal. Only if a variable binds
- to the same reference it will equal.
-- Go operators are short-circuiting as in Gleam.
-- Chains and pipes:
- - In Go chaining is usually done by constructing class methods that return
- an object: `$foo->bar(1)->quux(2)` means `bar(1)` is called as a method
- of `$foo` and then `quux()` is called as a method of the return value
- (object) of the `bar(1)` call. The objects in this chain usually
- mutate to keep the changed state and carry it forward in the chain.
- - In contrast in Gleam piping, no objects are being returned but mere data
- is pushed from left to right much like in unix tooling.
-
-## Constants
-
-### Go
-
-In Go, constants can only be defined within classes and traits.
-
-```Go
-class TheQuestion {
- public const theAnswer = 42;
-}
-echo TheQuestion::theAnswer; // 42
-```
-
-### Gleam
-
-In Gleam constants can be created using the `const` keyword.
-
-```gleam
-// the_question.gleam module
-const the_answer = 42
-
-pub fn main() {
- the_answer
-}
-```
-
-They can also be marked public via the `pub` keyword and will then be
-automatically exported.
-
-## Blocks
-
-### Go
-
-Go blocks are always associated with a function / conditional / loop or
-similar declaration. Blocks are limited to specific language constructs.
-There is no way to create multi-line expressions blocks like in Gleam.
-
-Blocks are declared via curly braces.
-
-```Go
-function a_func() {
- // A block starts here
- if ($foo) {
- // A block here
- } else {
- // A block here
- }
- // Block continues
-}
-```
-
-### Gleam
-
-In Gleam curly braces, `{` and `}`, are used to group expressions.
-
-```gleam
-pub fn main() {
- let x = {
- some_function(1)
- 2
- }
- // Braces are used to change precedence of arithmetic operators
- let y = x * {x + 10}
- y
-}
-```
-
-Unlike in Go, in Gleam function blocks are always expressions, so are `case`
-blocks or arithmetic sub groups. Because they are expressions they always
-return a value.
-
-For Gleam the last value in a block's expression is always the value being
-returned from an expression.
-
-## Data types
-
-### Strings
-
-In Go strings are stored as an array of bytes and an integer indicating the
-length of the buffer. Go itself has no information about how those bytes
-translate to characters, leaving that task to the programmer. Go's
-standard library however features a bunch of multi-byte compatible functions
-and conversion functions between UTF-8, ISO-8859-1 and further encodings.
-
-Go strings allow interpolation.
-
-In Gleam all strings are UTF-8 encoded binaries. Gleam strings do not allow
-interpolation, yet. Gleam however offers a `string_builder` via its standard
-library for performant string building.
-
-#### Go
-
-```Go
-$what = 'world';
-'Hellø, world!';
-"Hellø, ${what}!";
-```
-
-#### Gleam
-
-```gleam
-"Hellø, world!"
-```
-
-### Tuples
-
-Tuples are very useful in Gleam as they're the only collection data type that
-allows mixed types in the collection.
-
-#### Go
-
-Go does not really support tuples, but its array type can easily be used to
-mimick tuples. Unpacking can be used to bind a name to a specific value of
-the tuple.
-
-```Go
-$myTuple = ['username', 'password', 10];
-[$_, $pwd, $_] = $myTuple;
-echo $pwd; // "password"
-// Direct index access
-echo $myTuple[0]; // "username"
-```
-
-#### Gleam
-
-```gleam
-let my_tuple = #("username", "password", 10)
-let #(_, pwd, _) = my_tuple
-io.print(pwd) // "password"
-// Direct index access
-io.print(my_tuple.0) // "username"
-```
-
-### Lists
-
-Arrays in Go are allowed to have values of mixed types, but not in Gleam.
-
-#### Go
-
-Go does not feature special syntax for list handling.
-
-```Go
-$list = [2, 3, 4];
-$head = array_slice($list, 0, 1)[0];
-$tail = array_slice($list, 1);
-# $head == 2
-# $tail == [3, 4]
-$arr = array_merge($tail, [1.1]);
-# $arr == [3, 4, 1.1]
-```
-
-#### Gleam
-
-Gleam has a `cons` operator that works for lists destructuring and
-pattern matching. In Gleam lists are immutable so adding and removing elements
-from the start of a list is highly efficient.
-
-```gleam
-let list = [2, 3, 4]
-let list = [1, ..list]
-let [1, second_element, ..] = list
-[1.0, ..list] // compile error, type mismatch
-```
-
-### Maps
-
-In Go, the `array` type also covers maps and can have keys of any type as long as:
-
-- the key type is `null`, an `int`, a `string` or a `bool` (some conversions
- occur, such as null to `""` and `false` to `0` as well as `true` to `1`
- and `"1"` to `1`. Float indexes, which are not representing integers
- indexes are deprecated due to being auto downcast to integers).
-- the key is unique in the dictionary.
-- the values are of any type.
-
-In Gleam, maps can have keys and values of any type, but all keys must be of
-the same type in a given map and all values must be of the same type in a
-given map. The type of key and value can differ from each other.
-
-There is no map literal syntax in Gleam, and you cannot pattern match on a map.
-Maps are generally not used much in Gleam, custom types are more common.
-
-#### Go
-
-```Go
-["key1" => "value1", "key2" => "value2"]
-["key1" => "1", "key2" => 2]
-```
-
-#### Gleam
-
-```gleam
-import gleam/map
-
-map.from_list([#("key1", "value1"), #("key2", "value2")])
-map.from_list([#("key1", "value1"), #("key2", 2)]) // Type error!
-```
-
-### Numbers
-
-Go and Gleam both support `Integer` and `Float`. Integer and Float sizes for
-both depend on the platform: 64-bit or 32-bit hardware and OS and for Gleam
-JavaScript and Erlang.
-
-#### Go
-
-While Go differentiates between integers and floats it automatically converts
-floats and integers for you, removing precision or adding floating point
-decimals.
-
-```Go
-1 / 2 // 0.5
-```
-
-#### Gleam
-
-```gleam
-1 / 2 // 0
-1.5 + 10 // Compile time error
-```
-
-You can use the gleam standard library's `int` and `float` modules to convert
-between floats and integers in various ways including `rounding`, `floor`,
-`ceiling` and many more.
-
-## Flow control
-
-### Case
-
-Case is one of the most used control flow in Gleam. It can be seen as a switch
-statement on steroids. It provides a terse way to match a value type to an
-expression. It is also used to replace `if`/`else` statements.
-
-#### Go
-
-Go features 3 different expressions to achieve similar goals:
-
-- `if`/`else if`/`else` (does not return)
-- `switch`/`case`/`break`/`default` (does not return, does not autobreak)
-- `match` (returns)
-
-```Go
-function http_error_impl_1($status) {
- if ($status === 400) {
- return "Bad request";
- } else if ($status === 404) {
- return "Not found";
- } else if ($status === 418) {
- return "I'm a teapot";
- } else {
- return "Internal Server Error";
- }
-}
-
-function http_error_impl_2($status) {
- switch ($status) {
- case "400": // Will work because switch ($status) compares non-strict as in ==
- return "Bad request";
- break; // Not strictly required here, but combined with weak typing multiple cases could be executed if break is omitted
- case 404:
- return "Not found";
- break;
- case 418:
- return "I'm a teapot";
- break;
- default:
- return "Internal Server Error";
- }
-}
-
-function http_error_impl_3($status) {
- return match($status) { // match($status) compares strictly
- 400 => "Bad request",
- 404 => "Not found",
- 418 => "I'm a teapot",
- default => "Internal Server Error"
- };
-}
-```
-
-#### Gleam
-
-The case operator is a top level construct in Gleam:
-
-```gleam
-case some_number {
- 0 -> "Zero"
- 1 -> "One"
- 2 -> "Two"
- n -> "Some other number" // This matches anything
-}
-```
-
-As all expressions the case expression will return the matched value.
-
-They can be used to mimick if/else or if/elseif/else, with the exception that
-any branch must return unlike in Go, where it is possible to mutate a
-variable of the outer block/scope and not return at all.
-
-```gleam
-let is_status_within_4xx = status / 400 == 1
-case status {
- 400 -> "Bad Request"
- 404 -> "Not Found"
- _ if is_status_within_4xx -> "4xx" // This works as of now
- // status if status / 400 == 1 -> "4xx" // This will work in future versions of Gleam
- _ -> "I'm not sure"
-}
-```
-
-if/else example:
-
-```gleam
-case is_admin {
- True -> "allow access"
- False -> "disallow access"
-}
-```
-
-if/elseif/else example:
-
-```gleam
-case True {
- _ if is_admin == True -> "allow access"
- _ if is_confirmed_by_mail == True -> "allow access"
- _ -> "deny access"
-}
-```
-
-Exhaustiveness checking at compile time, which is in the works, will make
-certain that you must check for all possible values. A lazy and common way is
-to check of expected values and have a catchall clause with a single underscore
-`_`:
-
-```gleam
-case scale {
- 0 -> "none"
- 1 -> "one"
- 2 -> "pair"
- _ -> "many"
-}
-```
-
-The case operator especially coupled with destructuring to provide native pattern
-matching:
-
-```gleam
-case xs {
- [] -> "This list is empty"
- [a] -> "This list has 1 element"
- [a, b] -> "This list has 2 elements"
- _other -> "This list has more than 2 elements"
-}
-```
-
-The case operator supports guards:
-
-```gleam
-case xs {
- [a, b, c] if a >. b && a <=. c -> "ok"
- _other -> "ko"
-}
-```
-
-...and disjoint union matching:
-
-```gleam
-case number {
- 2 | 4 | 6 | 8 -> "This is an even number"
- 1 | 3 | 5 | 7 -> "This is an odd number"
- _ -> "I'm not sure"
-}
-```
-
-### Piping
-
-In Gleam most functions, if not all, are data first, which means the main data
-value to work on is the first argument. By this convention and the ability to
-specify the argument to pipe into, Gleam allows writing functional, immutable
-code, that reads imperative-style top down, much like unix tools and piping.
-
-#### Go
-
-Go does not offer pipes but it can chain calls by making functions return
-objects which in turn ship with their list of methods.
-
-```Go
-// Imaginary Go code
-(new Session($request))
- ->authorize()
- ->setSuccessFlash('Logged in successfully!')
- ->setFailureFlash('Failed to login!')
- ->redirectToRequestedUrl();
-```
-
-#### Gleam
-
-```gleam
-// Imaginary Gleam code
-request
-|> session.new()
-|> session.authorize()
-|> flash.set_success_flash('Logged in successfully!')
-|> flash.set_failure_flash('Failed to login!')
-|> response.redirect_to_requested_url()
-```
-
-Despite being similar to read and comprehend, the Go code creates a session
-object, and calls the authorize method of the session object: That session
-object then returns another object, say an `AuthorizedUser` object - you don't
-know by looking at the code what object gets returned. However you know it must
-implement a `setSuccessFlash` method. At the last step of the chain `redirect`
-is called on an object returned from `setFailureFlash`.
-
-In the Gleam code the request data is piped into `session.new()`'s first
-argument and that return value is piped further down. It is readability sugar
-for:
-
-```gleam
-response.redirect_to_requested_url(
- flash.set_failure_flash(
- flash.set_success_flash(
- session.authorize(
- session.new(request)
- ),
- 'Logged in successfully!'
- ),
- 'Failed to login!'
- )
-)
-```
-
-### Try
-
-Error management is approached differently in Go and Gleam.
-
-#### Go
-
-Go uses the notion of exceptions to interrupt the current code flow and
-pop up the error to the caller.
-
-An exception is raised using the keyword `throw`.
-
-```Go
-function aFunctionThatFails() {
- throw new RuntimeException('an error');
-}
-```
-
-The callee block will be able to capture any exception raised in the block
-using a `try/except` set of blocks:
-
-```Go
-// callee block
-try {
- echo 'this line will be executed and thus printed';
- aFunctionThatFails()
- echo 'this line will not be executed and thus not printed';
-} catch (Throwable $e) {
- var_dump(['doing something with the exception', $e]);
-}
-```
-
-#### Gleam
-
-In contrast in gleam, errors are just containers with an associated value.
-
-A common container to model an operation result is
-`Result(ReturnType, ErrorType)`.
-
-A `Result` is either:
-
-- an `Error(ErrorValue)`
-- or an `Ok(Data)` record
-
-Handling errors actually means to match the return value against those two
-scenarios, using a case for instance:
-
-```gleam
-case parse_int("123") {
- Ok(i) -> io.println("We parsed the Int")
- Error(e) -> io.println("That wasn't an Int")
-}
-```
-
-In order to simplify this construct, we can use the `try` keyword that will:
-
-- either bind a value to the providing name if `Ok(Something)` is matched,
-- or **interrupt the current block's flow** and return `Error(Something)` from
- the given block.
-
-```gleam
-let a_number = "1"
-let an_error = Error("ouch")
-let another_number = "3"
-
-try int_a_number = parse_int(a_number)
-try attempt_int = parse_int(an_error) // Error will be returned
-try int_another_number = parse_int(another_number) // never gets executed
-
-Ok(int_a_number + attempt_int + int_another_number) // never gets executed
-```
-
-## Type aliases
-
-Type aliases allow for easy referencing of arbitrary complex types.
-Go does not have this feature, though either regular classes or static classes
-can be used to design custom types and class definitions in take can be aliased
-using `class_alias()`.
-
-### Go
-
-A simple variable can store the result of a compound set of types.
-
-```Go
-static class Point {
- // Can act as an opaque type and utilize Point
- // Can be class_aliased to Coordinate
-}
-
-static class Triangle {
- // Can act as an opaque type definition and utilize Point
-}
-```
-
-### Gleam
-
-The `type` keyword can be used to create aliases.
-
-```gleam
-pub type Headers =
- List(#(String, String))
-```
-
-## Custom types
-
-### Records
-
-Custom type allows you to define a collection data type with a fixed number of
-named fields, and the values in those fields can be of differing types.
-
-#### Go
-
-Go uses classes to define user-defined, record-like types.
-Properties are defined as class members and initial values are generally set in
-the constructor.
-
-By default the constructor does not provide base initializers in the
-constructor so some boilerplate is needed:
-
-```Go
-class Person {
- public string $name;
- public int $age;
- function __construct(string $name, int $age) {
- $this->name = $name;
- $this->age = $age;
- }
-}
-$person = new Person(name: "Joe", age: 40);
-// $person->name // Joe;
-```
-
-#### Gleam
-
-Gleam's custom types can be used as structs. At runtime, they have a tuple
-representation and are compatible with Erlang records (or JavaScript objects).
-
-```gleam
-type Person {
- Person(name: String, age: Int)
-}
-
-let person = Person(name: "Joe", age: 40)
-let name = person.name
-```
-
-An important difference to note is there is no Java-style object-orientation in
-Gleam, thus methods can not be added to types. However opaque types exist,
-see below.
-
-### Unions
-
-Go generally does not support unions with a few exceptions such as:
-
-- type x or `null`
-- `Array` or `Traversable`.
-
-In Gleam functions must always take and receive one type. To have a union of
-two different types they must be wrapped in a new custom type.
-
-#### Go
-
-```Go
-class Foo {
- public ?string $aStringOrNull;
-}
-```
-
-#### Gleam
-
-```gleam
-type IntOrFloat {
- AnInt(Int)
- AFloat(Float)
-}
-
-fn int_or_float(X) {
- case X {
- True -> AnInt(1)
- False -> AFloat(1.0)
- }
-}
-```
-
-### Opaque custom types
-
-In Go, constructors can be marked as private and opaque types can either be
-modelled in an immutable way via static classes or in a mutable way via
-a factory pattern.
-
-In Gleam, custom types can be defined as being opaque, which causes the
-constructors for the custom type not to be exported from the module. Without
-any constructors to import other modules can only interact with opaque types
-using the intended API.
-
-#### Go
-
-```Go
-class PointObject
-{
- private int $x;
- private int $y;
-
- private function __construct(int $x, int $y) {
- $this->x = $x;
- $this->y = $y;
- }
-
- public static function spawn(int $x, int $y) {
- if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
- return new self($x, $y);
- }
- return false;
- }
-}
-PointObject::spawn(1, 2); // Returns a Point object
-```
-
-This requires mutation, but prohibits direct property changes.
-
-Go allows to skip object mutation by using static classes:
-
-```Go
-class PointStruct
-{
- public static function spawn(int $x, int $y) {
- if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
- return compact('x', 'y') + ['struct' => __CLASS__];
- }
- return false;
- }
-}
-PointStruct::spawn(1, 2); // Returns an array managed by PointStruct
-```
-
-However Go will in this case not prohibit the direct alteration the returned
-structure, like Gleam's custom types can.
-
-#### Gleam
-
-```gleam
-// In the point.gleam opaque type module:
-pub opaque type Point {
- Point(x: Int, y: Int)
-}
-
-pub fn spawn(x: Int, y: Int) -> Result(Point, Nil) {
- case x >= 0 && x <= 99 && y >= 0 && y <= 99 {
- True -> Ok(Point(x: x, y: y))
- False -> Error(Nil)
- }
-}
-
-// In the main.gleam module
-pub fn main() {
- assert Ok(point) = Point.spawn(1, 2)
- point
-}
-```
-
-## Modules
-
-### Go
-
-Go does not feature modules, but many other containers such as classes, traits
-and interfaces. Historically a single file can contain many classes, traits and
-interfaces one after another, though it is best practise to only contain one
-such declaration per file.
-
-Using Go namespaces, these can be placed in a registry that does not need to
-map to the source code file system hierarchy, but by convention should.
-
-In `src/Foo/Bar.Go`:
-
-```Go
-// Anything declared in this file will be inside namespace Foo
-namespace Foo;
-
-// Creation of (static) class Bar in Foo, thus as Foo/Bar
-class Bar {
- public static function identity($x) {
- return $x;
- }
-}
-```
-
-Making the static class available in the local scope and calling the function
-`index.Go` (aka Go's main function):
-
-```Go
-// After auto-loading has happened
-use Foo\Bar;
-
-Bar::identity(1) // 1;
-```
-
-### Gleam
-
-Coming from Go the closest thing Go has that are similar to Gleam's modules
-are static classes: Collections of functions and constants grouped into a
-static class.
-
-In comparison Gleam modules can also contain custom types.
-
-A gleam module name corresponds to its file name and path.
-
-Since there is no special syntax to create a module, there can be only one
-module in a file and since there is no way name the module the filename
-always matches the module name which keeps things simple and transparent.
-
-In `/src/foo/bar.gleam`:
-
-```gleam
-// Creation of module function identity
-// in module bar
-pub fn identity(x) {
- x
-}
-```
-
-Importing the `bar` module and calling a module function:
-
-```gleam
-// In src/main.gleam
-import foo/bar // if foo was in a directory called `lib` the import would be `lib/foo/bar`.
-
-pub fn main() {
- bar.identity(1) // 1
-}
-```
-
-### Imports
-
-#### Go
-
-Go features ways to load arbitrary Go code: `require`, `include` and
-autoload such as `spl_autoload_register`. Once class pathes are known and
-registered for autoloading, they can brought into the scope of a file by using
-the `use`statement which is part of Go's namespacing.
-Also see .
-
-Inside `src/Nasa/MoonBase.Go`
-
-```Go
-// Makes available src/nasa/RocketShip.Go
-use Nasa\RocketShip;
-
-class MoonBase {
- public static function exploreSpace() {
- RocketShip::launch();
- }
-}
-```
-
-#### Gleam
-
-Imports are relative to the app `src` folder.
-
-Modules in the same directory will need to reference the entire path from `src`
-for the target module, even if the target module is in the same folder.
-
-Inside module `src/nasa/moon_base.gleam`:
-
-```gleam
-// imports module src/nasa/rocket_ship.gleam
-import nasa/rocket_ship
-
-pub fn explore_space() {
- rocket_ship.launch()
-}
-```
-
-### Named imports
-
-#### Go
-
-Go features namespaces which can be used to rename classes when they clash:
-
-```Go
-// Source files must first be added to the auto-loader
-use Unix\Cat;
-use Animal\Cat as Kitty;
-// Cat and Kitty are available
-```
-
-#### Gleam
-
-Gleam has as similar feature:
-
-```gleam
-import unix/cat
-import animal/cat as kitty
-// cat and kitty are available
-```
-
-This may be useful to differentiate between multiple modules that would have the same default name when imported.
-
-### Unqualified imports
-
-#### Go
-
-```Go
-use Animal\Cat{
- Cat,
- function stroke
-};
-```
-
-```Go
-$kitty = new Cat(name: "Nubi");
-stroke($kitty);
-```
-
-#### Gleam
-
-```gleam
-import animal/cat.{
- Cat,
- stroke
-}
-
-pub fn main() {
- let kitty = Cat(name: "Nubi")
- stroke(kitty)
-}
-```
-
-Importing common types such as `gleam/order.{Lt, Eq, Gt}` or
-`gleam/option.{Some,None}` can be very helpful.
-
-## Architecture
-
-To iterate a few foundational differences:
-
-1. Programming model: Java-style object-orientation VS functional immutable
- programming
-2. Guarantees: weak dynamic typing VS strong static typing
-3. Runtime model: request-response script VS Erlang/OTP processes
-4. Error handling: exceptions VS result type
-5. Language reach
-
-### Programming model
-
-- Go mixes imperative, Java-style object-orientation and functional code
- styles. Gleam offers only functional code style, though it can appear
- imperative and reads easily thanks to pipes.
-- In Gleam, data structures are never mutated but always updated into new
- structures. This allows processes that fail to simply restart as there are no
- mutated objects that can be in an invalid state and take the whole
- application down (such as in Go, Ruby or Go).
-- Gleam offers syntax to make it easy to extract data out of custom types and
- update data into new copies of custom types without ever mutating variables.
- Go sometimes directly mutates references of simple values such as when using
- `reset()` or `end()` or `array_pop()`.
-- Gleam allows to rebind variables freely to make it easy to update data
- structures by making a copy and binding it to the existing variable.
-- Go features a massive, powerful but inconsistent standard library that is
- always loaded and partially extended and deprecated with new Go releases.
-- Gleam allows you to opt into a smaller, well polished and consistent standard
- library.
-
-### Guarantees and types
-
-- Go features opt-in static typing which is only checked at runtime.
-- Go values tend to be automatically cast for comparison purposes or when used
- as indexes in arrays. Gleam values are not automatically cast.
-- Go allows comparison between most if not all values, even if it does not
- make any sense say comparing a file `resource` to a `Date` in terms of order.
- Gleam's comparison operators are very strict and limited, any other
- comparisons and conversions must happen via function calls.
-- Go's checks happen at runtime, Gleam's checks (for the most part) do not
- and rely on the compiler to allow only type safe and sound code to be
- compiled.
-- Gleam's type inference allows you to be lazy for almost all type definitions.
- Gleam's type system will always assist you in what types are expected and/or
- conflicting. Gleam's type system will help you discover APIs.
-
-### Runtime model
-
-- Gleam can run on Erlang/BEAM, on the browser but also Deno or NodeJS.
-- For Gleam on Erlang/BEAM the runtime model has some striking similarities
- in practise: In Go a script starts and runs. It allocates memory for this
- script and frees it upon end or after the max execution time is exceeded
- or the memory limit is exceeded.
-- Gleam on Erlang/BEAM allows to processes requests in a similar isolation
- level that Go offers in contrast to applications running *Go* or *Ruby*.
- The level of isoluation means that, very similar to Go, if a process
- crashes (in Go read: if a request crashes) then the supervision system
- can restart that process or after a while or amount of tries abort
- repeating restarts on the process with that given input data. This means
- Erlang/BEAM will yield similar robustness that Go developers are used
- to and similar isolation guarantuees.
-- When executing Gleam code in fact its compiled Erlang or JavaScript is
- executed. So in case there are runtime crashes, the crash log will show
- Erlang (or browser-console/NodeJS/Deno) debug information. In Gleam
- applications runtime errors should almost never happen but they are harder
- to read, in Go applications runtime errors much more often and are easier
- to read.
-
-### Error handling
-
-- Gleam will catch all errors that are expected to happen via the `Result`
- type. There can however be other errors, such as miss-behavior due
- accidental to division by 0, crashes on RAM or storage limits, hardware
- failures, etc. In these cases on the BEAM there are ways to manage these
- via BEAM's supervision trees.
-- In contrast Go will use exceptions to handle errors and by doing so blurs
- the line between expected errors and unexpected errors. Also function
- signatures are enlarged de-facto by whatever exceptions they can throw
- and thus function calls and return types become much harder to manage.
-
-### Language reach
-
-- Go is tailored towards web applications, servers, and static to low-dynamic
- frontends.
-- Gleam can be utilized as a JavaScript replacement to drive your frontend
- application not just your backend web server.
-- Gleam on Erlang/BEAM can be used to write non-blocking, massively concurrent
- server applications comparable to RabbitMQ or multiplayer game servers.
- - [Numbers](#numbers)
-- [Flow control](#flow-control)
- - [Case](#case)
- - [Piping](#piping)
- - [Try](#try)
-- [Type aliases](#type-aliases)
-- [Custom types](#custom-types)
- - [Records](#records)
- - [Unions](#unions)
- - [Opaque custom types](#opaque-custom-types)
-- [Modules](#modules)
- - [Imports](#imports)
- - [Named imports](#named-imports)
- - [Unqualified imports](#unqualified-imports)
-- [Architecture](#architecture)
-
-## Comments
-
-### Go
-
-In Go, comments are written with a `//` prefix.
-
-```Go
-// Hello, Joe!
-```
-
-Multi line comments may be written like so:
-
-```Go
-/*
- * Hello, Joe!
- */
-```
-
-IN Go, above `trait`, `interface`, `class`, `member`, `function` declarations
-there can be `docblocks` like so:
-
-```Go
-/**
- * a very special trait.
- */
-trait Foo {}
-
-/**
- * A Bar class
- */
-class Bar {}
-
-/**
- * A quux function.
- *
- * @var string $str String passed to quux
- * @return string An unprocessed string
- */
-function quux(string $str) : string { return $str; }
-```
-
-Documentation blocks (docblocks) are extracted into generated API
-documentation.
-
-### Gleam
-
-In Gleam, comments are written with a `//` prefix.
-
-```gleam
-// Hello, Joe!
-```
-
-Comments starting with `///` are used to document the following function,
-constant, or type definition. Comments starting with `////` are used to
-document the current module.
-
-```gleam
-//// This module is very important.
-
-/// The answer to life, the universe, and everything.
-const answer: Int = 42
-
-/// A main function
-fn main() {}
-
-/// A Dog type
-type Dog {
- Dog(name: String, cuteness: Int)
-}
-```
-
-`//` comments are not used while generating documentation files, while
-`////` and `///` will appear in them.
-
-## Variables
-
-You can rebind variables in both languages.
-
-### Go
-
-```Go
-$size = 50;
-$size = $size + 100;
-$size = 1;
-```
-
-In local scope Go has no specific variable keyword. You choose a name
-and that's it!
-
-In class scope for property declaration Go uses at least one related
-modifier keyword to create properties such as: `public`, `private`,
-`protected`, `static` or `readonly` (`var` is deprecated).
-
-### Gleam
-
-Gleam has the `let` keyword before its variable names.
-
-```gleam
-let size = 50
-let size = size + 100
-let size = 1
-```
-
-### Match operator
-
-#### Go
-
-Go supports basic, one directional destructuring (also called unpacking).
-Tuple of values can be unpacked and inner values can be assigned to left-hand
-variable names.
-
-```Go
-[$a, $b] = [1, 2];
-// $a == 1
-// $b == 2
-
-[1 => $idx2] = ['foo', 'bar', 'quux'];
-// $idx2 == 'bar'
-
-["profession" => $job] = ['name' => 'Joe', 'profession' => 'hacker'];
-// $job == 'hacker'
-```
-
-#### Gleam
-
-In Gleam, `let` and `=` can be used for pattern matching, but you'll get
-compile errors if there's a type mismatch, and a runtime error if there's
-a value mismatch. For assertions, the equivalent `let assert` keyword is
-preferred.
-
-```gleam
-let #(a, _) = #(1, 2)
-// a = 1
-// `_` matches 2 and is discarded
-
-let assert [] = [1] // runtime error
-let assert [y] = "Hello" // compile error, type mismatch
-```
-
-Asserts should be used with caution.
-
-### Variables type annotations
-
-#### Go
-
-Go is a dynamically typed language. Types are only checked at runtime and
-a variable can have different types in its lifetime.
-
-Go gradually introduced more and more type hints that are optional.
-The type information is accessible via `get_type()` at runtime.
-
-These hints will mainly be used to inform static analysis tools like IDEs,
-linters, etc.
-
-```Go
-class Foo {
- private ?string $bar;
-}
-```
-
-As Go's `array` structure is a combination of maps and arrays.
-The Go manual states that it is an *ordered map*.
-While creating arrays in Go the type of its elements cannot be set explicitly
-and each element can be of a different type:
-
-```Go
-$someList = [1, 2, 3];
-$someTuple = [1, "a", true];
-$someMap = [0 => 1, "foo" => "bar", true => false];
-```
-
-Single variables cannot be type-annotated unless they are `class` or `trait`
-members.
-
-#### Gleam
-
-In Gleam type annotations can optionally be given when binding variables.
-
-```gleam
-let some_list: List(Int) = [1, 2, 3]
-let some_string: String = "Foo"
-```
-
-Gleam will check the type annotation to ensure that it matches the type of the
-assigned value. It does not need annotations to type check your code, but you
-may find it useful to annotate variables to hint to the compiler that you want
-a specific type to be inferred.
-
-## Functions
-
-### Go
-
-In Go, you can define functions with the `function` keyword. One or many `return`
-keywords are optional.
-
-```Go
-function hello($name = 'Joe') : string
-{
- if ($name = 'Joe') {
- return 'Welcome back, Joe!';
- }
- return "Hello $name";
-}
-
-function noop()
-{
- // Will automatically return NULL
-}
-```
-
-Anonymous functions returning a single expression can also be defined and be
-bound to variables.
-
-```Go
-$x = 2
-$GoAnonFn = function($y) use ($x) { return $x * $y; }; // Creates a new scope
-$GoAnonFn(2, 3); // 6
-$GoArrowFn = ($x) => $x * $y; // Inherits the outer scope
-$GoArrowFn(2, 3); // 6
-```
-
-### Gleam
-
-Gleam's functions are declared like so:
-
-```gleam
-fn sum(x, y) {
- x + y
-}
-```
-
-Gleam's anonymous functions have the same basic syntax.
-
-```gleam
-let mul = fn(x, y) { x * y }
-mul(1, 2)
-```
-
-A difference between Go's and Gleam's anonymous functions is that in Go they
-create a new local scope, in Gleam they close over the local scope, aka create
-a copy and inherit all variables in the scope. This means that in Gleam you can
-shadow local variables within anonymous functions but you cannot influence the
-variable bindings in the outer scope. This is different for Go's arrow
-functions where they inherit the scope like Gleam does.
-
-The only difference between module functions and anonymous functions in Gleam
-is that module functions heads may also feature argument labels, like so:
-
-```gleam
-// In some module.gleam
-pub fn distance(from x: Int, to y: Int) : Int {
- abs(x) - abs(y) |> abs()
-}
-// In some other function
-distance(from: 1, to: -2) // 3
-```
-
-### Exporting functions
-
-#### Go
-
-In Go, top level functions are exported by default. There is no notion of
-private module-level functions.
-
-However at class level, all properties are public, by default.
-
-```Go
-class Foo {
- static $bar = 5;
- private $quux = 6;
-
- static function batz() {
- return "Hello Joe!";
- }
-
- private static function kek() {
- return "Hello Rasmus!";
- }
-}
-echo Foo::$bar; // 5
-echo Foo::$quux; // Error
-echo Foo::batz(); // "Hello Joe"
-echo Foo::kek(); // Error
-```
-
-#### Gleam
-
-In Gleam, functions are private by default and need the `pub` keyword to be
-marked as public.
-
-```gleam
-// this is public
-pub fn sum(x, y) {
- x + y
-}
-
-// this is private
-fn mul(x, y) {
- x * y
-}
-```
-
-### Go
-
-Global functions may exist in a global scope, and to execute functions or
-create objects and invoke methods at some point they have to be called from
-the global scope. Usually there is one `index.Go` file whose global scope
-acts as if it was the `main()` function.
-
-### Gleam
-
-Gleam does not support a global scope. Instead Gleam code is either
-representing a library, which can be required as a dependency, and/or it
-represents an application having a main module, whose name must match to the
-application name and within that `main()`-function which will be called via
-either `gleam run` or when the `entrypoint.sh` is executed.
-
-In contrast to Go, where any Go file can contain a global scope that can
-be invoked by requiring the file, in Gleam only code that is within functions
-can be invoked.
-
-On the Beam, Gleam code can also be invoked from other Erlang code, or it
-can be invoked from browser's JavaScript, Deno or NodeJS runtime calls.
-
-### Function type annotations
-
-#### Go
-
-Type hints can be used to optionally annotate function arguments and return
-types.
-
-Discrepancies between type hints and actual values at runtime do not prevent
-interpretation of the code. Static code analysers (IDE tooling, type checkers
-like `Gostan`) will be required to detect those errors.
-
-```Go
-function sum(int $x, int $y) : int {
- return $x + $y;
-}
-
-function mul(int $x, int $y) : bool {
- # no errors from the interpreter.
- return $x * $y;
-}
-```
-
-#### Gleam
-
-Functions can **optionally** have their argument and return types annotated in
-Gleam. These type annotations will always be checked by the compiler and throw
-a compilation error if not valid. The compiler will still type check your
-program using type inference if annotations are omitted.
-
-```gleam
-fn add(x: Int, y: Int) -> Int {
- x + y
-}
-
-fn mul(x: Int, y: Int) -> Bool {
- x * y // compile error, type mismatch
-}
-```
-
-### Referencing functions
-
-#### Go
-
-As long as functions are in scope they can be assigned to a new variable.
-As methods or static functions classes, functions can be accessed via
-`$this->object_instance_method()` or `self::static_class_function()`.
-
-Other than that only anonymous functions can be moved around the same way as
-other values.
-
-```Go
-$doubleFn = function($x) { return $x + $x; };
-// Some imaginary pushFunction
-pushFunction($queue, $doubleFn);
-```
-
-However in `Go` it is not possible to pass around global, class or instance
-functions as values.
-
-#### Gleam
-
-Gleam has a single namespace for constants and functions within a module, so
-there is no need for a special syntax to assign a module function to a
-variable.
-
-```gleam
-fn identity(x) {
- x
-}
-
-fn main() {
- let func = identity
- func(100)
-}
-```
-
-### Labelled arguments
-
-Both Go and Gleam have ways to give arguments names and in any order.
-
-#### Go
-
-When calling a function, arguments can be passed:
-
-- positionally, in the same order of the function declaration
-- by name, in any order
-
-```Go
-// Some imaginary replace function
-function replace(string $each, string $with, string $inside) {
- // TODO implementation
-}
-// Calling with positional arguments:
-replace(",", " ", "A,B,C")
-// Calling with named arguments:
-replace(inside: "A,B,C", each: ",", with: " ")
-```
-
-#### Gleam
-
-In Gleam arguments can be given a label as well as an internal name.
-Contrary to Go, the name used at the call-site does not have to match
-the name used for the variable inside the function.
-
-```gleam
-pub fn replace(inside str, each pattern, with replacement) {
- todo
-}
-```
-
-```gleam
-replace(",", " ", "A,B,C")
-replace(inside: "A,B,C", each: ",", with: " ")
-```
-
-There is no performance cost to Gleam's labelled arguments as they are
-optimised to regular function calls at compile time, and all the arguments
-are fully type checked.
-
-## Operators
-
-| Operator | Go | Gleam | Notes |
-| ------------------ | ------ | ------------------------- | -------------------------------------------------------------------------------------- |
-| Equal | `==` | `==` | In Gleam both values must be of the same type |
-| Strictly equal to | `===` | `==` | Comparison in Gleam is always strict. (see note for Go) |
-| Reference equality | `instanceof` | | True only if an object is an instance of a class |
-| Not equal | `!=` | `!=` | In Gleam both values must be of the same type |
-| Not equal | `!==` | `!=` | Comparison in Gleam is always strict (see note for Go) |
-| Greater than | `>` | `>` | In Gleam both values must be **Int** |
-| Greater than | `>` | `>.` | In Gleam both values must be **Float** |
-| Greater or equal | `>=` | `>=` | In Gleam both values must be **Int** |
-| Greater or equal | `>=` | `>=.` | In Gleam both values must be **Float** |
-| Less than | `<` | `<` | In Gleam both values must be **Int** |
-| Less than | `<` | `<.` | In Gleam both values must be **Float** |
-| Less or equal | `<=` | `<=` | In Gleam both values must be **Int** |
-| Less or equal | `<=` | `<=.` | In Gleam both values must be **Float** |
-| Boolean and | `&&` | `&&` | In Gleam both values must be **Bool** |
-| Logical and | `&&` | | Not available in Gleam |
-| Boolean or | ||
| ||
| In Gleam both values must be **Bool** |
-| Logical or | ||
| | Not available in Gleam |
-| Boolean not | `xor` | | Not available in Gleam |
-| Boolean not | `!` | `!` | In Gleam both values must be **Bool** |
-| Add | `+` | `+` | In Gleam both values must be **Int** |
-| Add | `+` | `+.` | In Gleam both values must be **Float** |
-| Subtract | `-` | `-` | In Gleam both values must be **Int** |
-| Subtract | `-` | `-.` | In Gleam both values must be **Float** |
-| Multiply | `*` | `*` | In Gleam both values must be **Int** |
-| Multiply | `*` | `*.` | In Gleam both values must be **Float** |
-| Divide | `/` | `/` | In Gleam both values must be **Int** |
-| Divide | `/` | `/.` | In Gleam both values must be **Float** |
-| Remainder | `%` | `%` | In Gleam both values must be **Int** |
-| Concatenate | `.` | `<>` | In Gleam both values must be **String**
-| Pipe | `->` | |>
| Gleam's pipe can chain function calls. See note for Go |
-
-### Notes on operators
-
-- For bitwise operators, which exist in Go but not in Gleam,
- see: .
-- `==` is by default comparing by value in Go:
- - Types may be autocast to be compareable.
- - Two objects with the same members values will equal:
-- `===` is for comparing by strict equality in Go:
- - Types will not be autocast for comparison
- - Two objects with the same members will not equal. Only if a variable binds
- to the same reference it will equal.
-- Go operators are short-circuiting as in Gleam.
-- Chains and pipes:
- - In Go chaining is usually done by constructing class methods that return
- an object: `$foo->bar(1)->quux(2)` means `bar(1)` is called as a method
- of `$foo` and then `quux()` is called as a method of the return value
- (object) of the `bar(1)` call. The objects in this chain usually
- mutate to keep the changed state and carry it forward in the chain.
- - In contrast in Gleam piping, no objects are being returned but mere data
- is pushed from left to right much like in unix tooling.
-
-## Constants
-
-### Go
-
-In Go, constants can only be defined within classes and traits.
-
-```Go
-class TheQuestion {
- public const theAnswer = 42;
-}
-echo TheQuestion::theAnswer; // 42
-```
-
-### Gleam
-
-In Gleam constants can be created using the `const` keyword.
-
-```gleam
-// the_question.gleam module
-const the_answer = 42
-
-pub fn main() {
- the_answer
-}
-```
-
-They can also be marked public via the `pub` keyword and will then be
-automatically exported.
-
-## Blocks
-
-### Go
-
-Go blocks are always associated with a function / conditional / loop or
-similar declaration. Blocks are limited to specific language constructs.
-There is no way to create multi-line expressions blocks like in Gleam.
-
-Blocks are declared via curly braces.
-
-```Go
-function a_func() {
- // A block starts here
- if ($foo) {
- // A block here
- } else {
- // A block here
- }
- // Block continues
-}
-```
-
-### Gleam
-
-In Gleam curly braces, `{` and `}`, are used to group expressions.
-
-```gleam
-pub fn main() {
- let x = {
- some_function(1)
- 2
- }
- // Braces are used to change precedence of arithmetic operators
- let y = x * {x + 10}
- y
-}
-```
-
-Unlike in Go, in Gleam function blocks are always expressions, so are `case`
-blocks or arithmetic sub groups. Because they are expressions they always
-return a value.
-
-For Gleam the last value in a block's expression is always the value being
-returned from an expression.
-
-## Data types
-
-### Strings
-
-In Go strings are stored as an array of bytes and an integer indicating the
-length of the buffer. Go itself has no information about how those bytes
-translate to characters, leaving that task to the programmer. Go's
-standard library however features a bunch of multi-byte compatible functions
-and conversion functions between UTF-8, ISO-8859-1 and further encodings.
-
-Go strings allow interpolation.
-
-In Gleam all strings are UTF-8 encoded binaries. Gleam strings do not allow
-interpolation, yet. Gleam however offers a `string_builder` via its standard
-library for performant string building.
-
-#### Go
-
-```Go
-$what = 'world';
-'Hellø, world!';
-"Hellø, ${what}!";
-```
-
-#### Gleam
-
-```gleam
-"Hellø, world!"
-```
-
-### Tuples
-
-Tuples are very useful in Gleam as they're the only collection data type that
-allows mixed types in the collection.
-
-#### Go
-
-Go does not really support tuples, but its array type can easily be used to
-mimick tuples. Unpacking can be used to bind a name to a specific value of
-the tuple.
-
-```Go
-$myTuple = ['username', 'password', 10];
-[$_, $pwd, $_] = $myTuple;
-echo $pwd; // "password"
-// Direct index access
-echo $myTuple[0]; // "username"
-```
-
-#### Gleam
-
-```gleam
-let my_tuple = #("username", "password", 10)
-let #(_, pwd, _) = my_tuple
-io.print(pwd) // "password"
-// Direct index access
-io.print(my_tuple.0) // "username"
-```
-
-### Lists
-
-Arrays in Go are allowed to have values of mixed types, but not in Gleam.
-
-#### Go
-
-Go does not feature special syntax for list handling.
-
-```Go
-$list = [2, 3, 4];
-$head = array_slice($list, 0, 1)[0];
-$tail = array_slice($list, 1);
-# $head == 2
-# $tail == [3, 4]
-$arr = array_merge($tail, [1.1]);
-# $arr == [3, 4, 1.1]
-```
-
-#### Gleam
-
-Gleam has a `cons` operator that works for lists destructuring and
-pattern matching. In Gleam lists are immutable so adding and removing elements
-from the start of a list is highly efficient.
-
-```gleam
-let list = [2, 3, 4]
-let list = [1, ..list]
-let [1, second_element, ..] = list
-[1.0, ..list] // compile error, type mismatch
-```
-
-### Maps
-
-In Go, the `array` type also covers maps and can have keys of any type as long as:
-
-- the key type is `null`, an `int`, a `string` or a `bool` (some conversions
- occur, such as null to `""` and `false` to `0` as well as `true` to `1`
- and `"1"` to `1`. Float indexes, which are not representing integers
- indexes are deprecated due to being auto downcast to integers).
-- the key is unique in the dictionary.
-- the values are of any type.
-
-In Gleam, maps can have keys and values of any type, but all keys must be of
-the same type in a given map and all values must be of the same type in a
-given map. The type of key and value can differ from each other.
-
-There is no map literal syntax in Gleam, and you cannot pattern match on a map.
-Maps are generally not used much in Gleam, custom types are more common.
-
-#### Go
-
-```Go
-["key1" => "value1", "key2" => "value2"]
-["key1" => "1", "key2" => 2]
-```
-
-#### Gleam
-
-```gleam
-import gleam/map
-
-map.from_list([#("key1", "value1"), #("key2", "value2")])
-map.from_list([#("key1", "value1"), #("key2", 2)]) // Type error!
-```
-
-### Numbers
-
-Go and Gleam both support `Integer` and `Float`. Integer and Float sizes for
-both depend on the platform: 64-bit or 32-bit hardware and OS and for Gleam
-JavaScript and Erlang.
-
-#### Go
-
-While Go differentiates between integers and floats it automatically converts
-floats and integers for you, removing precision or adding floating point
-decimals.
-
-```Go
-1 / 2 // 0.5
-```
-
-#### Gleam
-
-```gleam
-1 / 2 // 0
-1.5 + 10 // Compile time error
-```
-
-You can use the gleam standard library's `int` and `float` modules to convert
-between floats and integers in various ways including `rounding`, `floor`,
-`ceiling` and many more.
-
-## Flow control
-
-### Case
-
-Case is one of the most used control flow in Gleam. It can be seen as a switch
-statement on steroids. It provides a terse way to match a value type to an
-expression. It is also used to replace `if`/`else` statements.
-
-#### Go
-
-Go features 3 different expressions to achieve similar goals:
-
-- `if`/`else if`/`else` (does not return)
-- `switch`/`case`/`break`/`default` (does not return, does not autobreak)
-- `match` (returns)
-
-```Go
-function http_error_impl_1($status) {
- if ($status === 400) {
- return "Bad request";
- } else if ($status === 404) {
- return "Not found";
- } else if ($status === 418) {
- return "I'm a teapot";
- } else {
- return "Internal Server Error";
- }
-}
-
-function http_error_impl_2($status) {
- switch ($status) {
- case "400": // Will work because switch ($status) compares non-strict as in ==
- return "Bad request";
- break; // Not strictly required here, but combined with weak typing multiple cases could be executed if break is omitted
- case 404:
- return "Not found";
- break;
- case 418:
- return "I'm a teapot";
- break;
- default:
- return "Internal Server Error";
- }
-}
-
-function http_error_impl_3($status) {
- return match($status) { // match($status) compares strictly
- 400 => "Bad request",
- 404 => "Not found",
- 418 => "I'm a teapot",
- default => "Internal Server Error"
- };
-}
-```
-
-#### Gleam
-
-The case operator is a top level construct in Gleam:
-
-```gleam
-case some_number {
- 0 -> "Zero"
- 1 -> "One"
- 2 -> "Two"
- n -> "Some other number" // This matches anything
-}
-```
-
-As all expressions the case expression will return the matched value.
-
-They can be used to mimick if/else or if/elseif/else, with the exception that
-any branch must return unlike in Go, where it is possible to mutate a
-variable of the outer block/scope and not return at all.
-
-```gleam
-let is_status_within_4xx = status / 400 == 1
-case status {
- 400 -> "Bad Request"
- 404 -> "Not Found"
- _ if is_status_within_4xx -> "4xx" // This works as of now
- // status if status / 400 == 1 -> "4xx" // This will work in future versions of Gleam
- _ -> "I'm not sure"
-}
-```
-
-if/else example:
-
-```gleam
-case is_admin {
- True -> "allow access"
- False -> "disallow access"
-}
-```
-
-if/elseif/else example:
-
-```gleam
-case True {
- _ if is_admin == True -> "allow access"
- _ if is_confirmed_by_mail == True -> "allow access"
- _ -> "deny access"
-}
-```
-
-Exhaustiveness checking at compile time, which is in the works, will make
-certain that you must check for all possible values. A lazy and common way is
-to check of expected values and have a catchall clause with a single underscore
-`_`:
-
-```gleam
-case scale {
- 0 -> "none"
- 1 -> "one"
- 2 -> "pair"
- _ -> "many"
-}
-```
-
-The case operator especially coupled with destructuring to provide native pattern
-matching:
-
-```gleam
-case xs {
- [] -> "This list is empty"
- [a] -> "This list has 1 element"
- [a, b] -> "This list has 2 elements"
- _other -> "This list has more than 2 elements"
-}
-```
-
-The case operator supports guards:
-
-```gleam
-case xs {
- [a, b, c] if a >. b && a <=. c -> "ok"
- _other -> "ko"
-}
-```
-
-...and disjoint union matching:
-
-```gleam
-case number {
- 2 | 4 | 6 | 8 -> "This is an even number"
- 1 | 3 | 5 | 7 -> "This is an odd number"
- _ -> "I'm not sure"
-}
-```
-
-### Piping
-
-In Gleam most functions, if not all, are data first, which means the main data
-value to work on is the first argument. By this convention and the ability to
-specify the argument to pipe into, Gleam allows writing functional, immutable
-code, that reads imperative-style top down, much like unix tools and piping.
-
-#### Go
-
-Go does not offer pipes but it can chain calls by making functions return
-objects which in turn ship with their list of methods.
-
-```Go
-// Imaginary Go code
-(new Session($request))
- ->authorize()
- ->setSuccessFlash('Logged in successfully!')
- ->setFailureFlash('Failed to login!')
- ->redirectToRequestedUrl();
-```
-
-#### Gleam
-
-```gleam
-// Imaginary Gleam code
-request
-|> session.new()
-|> session.authorize()
-|> flash.set_success_flash('Logged in successfully!')
-|> flash.set_failure_flash('Failed to login!')
-|> response.redirect_to_requested_url()
-```
-
-Despite being similar to read and comprehend, the Go code creates a session
-object, and calls the authorize method of the session object: That session
-object then returns another object, say an `AuthorizedUser` object - you don't
-know by looking at the code what object gets returned. However you know it must
-implement a `setSuccessFlash` method. At the last step of the chain `redirect`
-is called on an object returned from `setFailureFlash`.
-
-In the Gleam code the request data is piped into `session.new()`'s first
-argument and that return value is piped further down. It is readability sugar
-for:
-
-```gleam
-response.redirect_to_requested_url(
- flash.set_failure_flash(
- flash.set_success_flash(
- session.authorize(
- session.new(request)
- ),
- 'Logged in successfully!'
- ),
- 'Failed to login!'
- )
-)
-```
-
-### Try
-
-Error management is approached differently in Go and Gleam.
-
-#### Go
-
-Go uses the notion of exceptions to interrupt the current code flow and
-pop up the error to the caller.
-
-An exception is raised using the keyword `throw`.
-
-```Go
-function aFunctionThatFails() {
- throw new RuntimeException('an error');
-}
-```
-
-The callee block will be able to capture any exception raised in the block
-using a `try/except` set of blocks:
-
-```Go
-// callee block
-try {
- echo 'this line will be executed and thus printed';
- aFunctionThatFails()
- echo 'this line will not be executed and thus not printed';
-} catch (Throwable $e) {
- var_dump(['doing something with the exception', $e]);
-}
-```
-
-#### Gleam
-
-In contrast in gleam, errors are just containers with an associated value.
-
-A common container to model an operation result is
-`Result(ReturnType, ErrorType)`.
-
-A `Result` is either:
-
-- an `Error(ErrorValue)`
-- or an `Ok(Data)` record
-
-Handling errors actually means to match the return value against those two
-scenarios, using a case for instance:
-
-```gleam
-case parse_int("123") {
- Ok(i) -> io.println("We parsed the Int")
- Error(e) -> io.println("That wasn't an Int")
-}
-```
-
-In order to simplify this construct, we can use the `try` keyword that will:
-
-- either bind a value to the providing name if `Ok(Something)` is matched,
-- or **interrupt the current block's flow** and return `Error(Something)` from
- the given block.
-
-```gleam
-let a_number = "1"
-let an_error = Error("ouch")
-let another_number = "3"
-
-try int_a_number = parse_int(a_number)
-try attempt_int = parse_int(an_error) // Error will be returned
-try int_another_number = parse_int(another_number) // never gets executed
-
-Ok(int_a_number + attempt_int + int_another_number) // never gets executed
-```
-
-## Type aliases
-
-Type aliases allow for easy referencing of arbitrary complex types.
-Go does not have this feature, though either regular classes or static classes
-can be used to design custom types and class definitions in take can be aliased
-using `class_alias()`.
-
-### Go
+package mypkg
+type myType struct { // Can't be used outside of this package
-A simple variable can store the result of a compound set of types.
-
-```Go
-static class Point {
- // Can act as an opaque type and utilize Point
- // Can be class_aliased to Coordinate
-}
-
-static class Triangle {
- // Can act as an opaque type definition and utilize Point
-}
-```
-
-### Gleam
-
-The `type` keyword can be used to create aliases.
-
-```gleam
-pub type Headers =
- List(#(String, String))
-```
-
-## Custom types
-
-### Records
-
-Custom type allows you to define a collection data type with a fixed number of
-named fields, and the values in those fields can be of differing types.
-
-#### Go
-
-Go uses classes to define user-defined, record-like types.
-Properties are defined as class members and initial values are generally set in
-the constructor.
-
-By default the constructor does not provide base initializers in the
-constructor so some boilerplate is needed:
-
-```Go
-class Person {
- public string $name;
- public int $age;
- function __construct(string $name, int $age) {
- $this->name = $name;
- $this->age = $age;
- }
-}
-$person = new Person(name: "Joe", age: 40);
-// $person->name // Joe;
-```
-
-#### Gleam
-
-Gleam's custom types can be used as structs. At runtime, they have a tuple
-representation and are compatible with Erlang records (or JavaScript objects).
-
-```gleam
-type Person {
- Person(name: String, age: Int)
-}
-
-let person = Person(name: "Joe", age: 40)
-let name = person.name
-```
-
-An important difference to note is there is no Java-style object-orientation in
-Gleam, thus methods can not be added to types. However opaque types exist,
-see below.
-
-### Unions
-
-Go generally does not support unions with a few exceptions such as:
-
-- type x or `null`
-- `Array` or `Traversable`.
-
-In Gleam functions must always take and receive one type. To have a union of
-two different types they must be wrapped in a new custom type.
-
-#### Go
-
-```Go
-class Foo {
- public ?string $aStringOrNull;
-}
-```
-
-#### Gleam
-
-```gleam
-type IntOrFloat {
- AnInt(Int)
- AFloat(Float)
-}
-
-fn int_or_float(X) {
- case X {
- True -> AnInt(1)
- False -> AFloat(1.0)
- }
}
-```
-
-### Opaque custom types
-
-In Go, constructors can be marked as private and opaque types can either be
-modelled in an immutable way via static classes or in a mutable way via
-a factory pattern.
-In Gleam, custom types can be defined as being opaque, which causes the
-constructors for the custom type not to be exported from the module. Without
-any constructors to import other modules can only interact with opaque types
-using the intended API.
-
-#### Go
-
-```Go
-class PointObject
-{
- private int $x;
- private int $y;
-
- private function __construct(int $x, int $y) {
- $this->x = $x;
- $this->y = $y;
- }
-
- public static function spawn(int $x, int $y) {
- if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
- return new self($x, $y);
- }
- return false;
- }
-}
-PointObject::spawn(1, 2); // Returns a Point object
+func SomeFunc() myType {}
+func OtherFunc(mt myType) bool {}
```
-This requires mutation, but prohibits direct property changes.
+```go
+package main
-Go allows to skip object mutation by using static classes:
+import "someurl.com/mymodule/mypkg"
-```Go
-class PointStruct
-{
- public static function spawn(int $x, int $y) {
- if ($x >= 0 && $x <= 99 && $y >= 0 && $y <= 99) {
- return compact('x', 'y') + ['struct' => __CLASS__];
- }
- return false;
+func main() {
+ mt := mypkg.SomeFunc()
+ if mypkg.OtherFunc(mt) {
+ fmt.Println("I can use the opaque type but can't create it!")
}
}
-PointStruct::spawn(1, 2); // Returns an array managed by PointStruct
```
-However Go will in this case not prohibit the direct alteration the returned
-structure, like Gleam's custom types can.
-
#### Gleam
```gleam
@@ -7123,38 +1179,57 @@ pub fn main() {
## Modules
+Modules in Gleam are the principal unit of code organization. Each
+Gleam file is a Module. A module exports a number of symbols and
+can import symbols from other modules.
+
### Go
-Go does not feature modules, but many other containers such as classes, traits
-and interfaces. Historically a single file can contain many classes, traits and
-interfaces one after another, though it is best practise to only contain one
-such declaration per file.
+In Go, the term _modules_ refers to a set of packages that share
+common dependencies and are stored alongside one another. A _package_
+in Go is closer to the Gleam concept of _modules_. The biggest difference
+is that a _package_ in Go can be spread across many files in one directory.
+
+In `mymod/foo/foo.go`:
+```Go
+// Anything declared in the foo directory will be inside the /foo package
+package foo
-Using Go namespaces, these can be placed in a registry that does not need to
-map to the source code file system hierarchy, but by convention should.
+// This function is available for import by other packages
+func Identity(x any) {
+ return x;
+}
-In `src/Foo/Bar.Go`:
+func privateFunc() {}
+```
+In `mymod/foo/other.go`:
```Go
-// Anything declared in this file will be inside namespace Foo
-namespace Foo;
+// Anything declared in the foo directory will be inside the /foo package
+package foo
-// Creation of (static) class Bar in Foo, thus as Foo/Bar
-class Bar {
- public static function identity($x) {
- return $x;
- }
+func otherFunc(x any) {
+ privateFunc() // Can be used here
+ return x;
}
+
```
-Making the static class available in the local scope and calling the function
-`index.Go` (aka Go's main function):
+We can now call Identity from the main package in your binary.
```Go
-// After auto-loading has happened
-use Foo\Bar;
+package main
+
+import (
+ "fmt"
+m
+ "someurl.com/mymod/foo"
+)
-Bar::identity(1) // 1;
+func main() {
+ fmt.Println(foo.Identity("Hello, world!"))
+ // privateFunc is not visible here
+}
```
### Gleam
@@ -7196,23 +1271,29 @@ pub fn main() {
#### Go
-Go features ways to load arbitrary Go code: `require`, `include` and
-autoload such as `spl_autoload_register`. Once class pathes are known and
-registered for autoloading, they can brought into the scope of a file by using
-the `use`statement which is part of Go's namespacing.
-Also see .
+Go imports are fairly simple. Using `import` keyword with either a string literal
+that contains the path to a package, or several such strings each on separate lines
+inside of parentheses.
-Inside `src/Nasa/MoonBase.Go`
+Besides the standard library, all packages have to be fully qualified, where the
+qualifier is the name of the containing module, which by convention is the url
+at which the module is hosted.
-```Go
-// Makes available src/nasa/RocketShip.Go
-use Nasa\RocketShip;
+```go
+import "fmt" // Single import. Stdlib packages are referenced bare, no path required
+import ( // Multi-package import
+ "strings" // Available for use as `strings`
-class MoonBase {
- public static function exploreSpace() {
- RocketShip::launch();
- }
-}
+ "github.com/example/example-go-project/somepkg" // Will be available as `somepkg`
+)
+```
+
+There is no way in Go to import a symbol itself, all imports are qualified by their
+package.
+
+```go
+fmt.Println()
+strings.Trim()
```
#### Gleam
@@ -7237,13 +1318,16 @@ pub fn explore_space() {
#### Go
-Go features namespaces which can be used to rename classes when they clash:
+Go allows you to alias a package import
-```Go
-// Source files must first be added to the auto-loader
-use Unix\Cat;
-use Animal\Cat as Kitty;
-// Cat and Kitty are available
+```go
+import (
+ other "github.com/example/example-go-project/somepkg"
+)
+
+func main() {
+ other.SomeFunc()
+}
```
#### Gleam
@@ -7262,17 +1346,7 @@ This may be useful to differentiate between multiple modules that would have the
#### Go
-```Go
-use Animal\Cat{
- Cat,
- function stroke
-};
-```
-
-```Go
-$kitty = new Cat(name: "Nubi");
-stroke($kitty);
-```
+Go does not support unqualified imports
#### Gleam
@@ -7295,70 +1369,72 @@ Importing common types such as `gleam/order.{Lt, Eq, Gt}` or
To iterate a few foundational differences:
-1. Programming model: Java-style object-orientation VS functional immutable
+1. Programming model: imperative VS functional immutable
programming
-2. Guarantees: weak dynamic typing VS strong static typing
-3. Runtime model: request-response script VS Erlang/OTP processes
-4. Error handling: exceptions VS result type
-5. Language reach
+2. Guarantees: implicit nillability vs explicit nillability
+3. Runtime model: lightweight coroutines(`goroutines`) VS Erlang/OTP processes
+4. Error handling: error value (and very few panics) VS result type
+5. Distribution: Single static binaries vs Dynamically linked binary that relies on Erlang runtime
### Programming model
-- Go mixes imperative, Java-style object-orientation and functional code
- styles. Gleam offers only functional code style, though it can appear
+- Go is an imperative programming language, with only very limited object-oriented facilities
+ provided. Gleam offers only functional code style, though it can appear
imperative and reads easily thanks to pipes.
- In Gleam, data structures are never mutated but always updated into new
structures. This allows processes that fail to simply restart as there are no
mutated objects that can be in an invalid state and take the whole
- application down (such as in Go, Ruby or Go).
+ application down (such as in languages like Ruby or Go).
- Gleam offers syntax to make it easy to extract data out of custom types and
update data into new copies of custom types without ever mutating variables.
Go sometimes directly mutates references of simple values such as when using
- `reset()` or `end()` or `array_pop()`.
+ pointers or global variables, though this is very much not idiomatic.
- Gleam allows to rebind variables freely to make it easy to update data
structures by making a copy and binding it to the existing variable.
-- Go features a massive, powerful but inconsistent standard library that is
- always loaded and partially extended and deprecated with new Go releases.
+- Go features a massive, powerful standard library centered around simple interfaces.
+ Everything from string manipulation to the tools to create an http server are included
+ out of the box. It has been tuned for over 15 years for performance and has strong
+ guarantees about backwards and forwards compatibility.
- Gleam allows you to opt into a smaller, well polished and consistent standard
library.
### Guarantees and types
-- Go features opt-in static typing which is only checked at runtime.
-- Go values tend to be automatically cast for comparison purposes or when used
- as indexes in arrays. Gleam values are not automatically cast.
-- Go allows comparison between most if not all values, even if it does not
- make any sense say comparing a file `resource` to a `Date` in terms of order.
- Gleam's comparison operators are very strict and limited, any other
- comparisons and conversions must happen via function calls.
-- Go's checks happen at runtime, Gleam's checks (for the most part) do not
- and rely on the compiler to allow only type safe and sound code to be
- compiled.
-- Gleam's type inference allows you to be lazy for almost all type definitions.
+- Both Go and Gleam features strong static typing.
+- Both Go and Gleam values are not automatically cast.
+- Both Go and Gleam's comparison operators are very strict and limited, any other
+ comparisons and conversions must happen via function calls or other explicit type
+ conversion mechanisms.
+- Go's checks happen at compile time (except for reflection), Gleam uses the compiler
+ and pattern matching to allow for robust compile time check but does have interop
+ with Erlang, a dynamically language that relies on good interfaces written in Gleam
+ to provide any type-safety.
+- Go has limited type inference, all functions and data structures require explicit types.
+ Gleam's type inference allows you to be lazy for almost all type definitions.
Gleam's type system will always assist you in what types are expected and/or
conflicting. Gleam's type system will help you discover APIs.
### Runtime model
- Gleam can run on Erlang/BEAM, on the browser but also Deno or NodeJS.
-- For Gleam on Erlang/BEAM the runtime model has some striking similarities
- in practise: In Go a script starts and runs. It allocates memory for this
- script and frees it upon end or after the max execution time is exceeded
- or the memory limit is exceeded.
-- Gleam on Erlang/BEAM allows to processes requests in a similar isolation
- level that Go offers in contrast to applications running *Go* or *Ruby*.
- The level of isoluation means that, very similar to Go, if a process
- crashes (in Go read: if a request crashes) then the supervision system
- can restart that process or after a while or amount of tries abort
+- Gleam on Erlang/BEAM allows to processes requests in complete isolation,
+ unlike Go, where memory sharing is allowed - though communicating through
+ channels is recommended. Channels and Goroutines allow for good isolation
+ if used in a disciplined manner. That being said, Mutexes and other shared
+ state mechanisms are included in the standard library.
+
+ The level of isolation means that, if a process crashes then the supervision
+ system can restart that process or after a while or amount of tries abort
repeating restarts on the process with that given input data. This means
- Erlang/BEAM will yield similar robustness that Go developers are used
- to and similar isolation guarantuees.
+ Erlang/BEAM will yield incredibly robust concurrent systems, even superior
+ to what experienced Gophers can accomplish with Goroutines, Channels, and
+ recover patterns.
- When executing Gleam code in fact its compiled Erlang or JavaScript is
executed. So in case there are runtime crashes, the crash log will show
Erlang (or browser-console/NodeJS/Deno) debug information. In Gleam
applications runtime errors should almost never happen but they are harder
- to read, in Go applications runtime errors much more often and are easier
- to read.
+ to read, in Go applications runtime errors might be more common but the will be
+ easier to read.
### Error handling
@@ -7367,16 +1443,18 @@ To iterate a few foundational differences:
accidental to division by 0, crashes on RAM or storage limits, hardware
failures, etc. In these cases on the BEAM there are ways to manage these
via BEAM's supervision trees.
-- In contrast Go will use exceptions to handle errors and by doing so blurs
- the line between expected errors and unexpected errors. Also function
- signatures are enlarged de-facto by whatever exceptions they can throw
- and thus function calls and return types become much harder to manage.
+- Go has explicit errors as well, and pairs it with multiple return values
+ to provide a similar experience to Gleam, but in an imperative, non-monadic
+ form. Go does have panics which will crash the running goroutine (and if that
+ is the main goroutine, the program will crash). Panics are generally not
+ explicitly created by a developer, but there are a number of issues that can cause
+ panics to occur: Division by zero, accessing the field of a nil struct, accessing an
+ out of bounds array element, etc.
### Language reach
-- Go is tailored towards web applications, servers, and static to low-dynamic
- frontends.
+- Go is tailored towards web applications, servers, CLI tools, and infrastructure.
- Gleam can be utilized as a JavaScript replacement to drive your frontend
application not just your backend web server.
- Gleam on Erlang/BEAM can be used to write non-blocking, massively concurrent
- server applications comparable to RabbitMQ or multiplayer game servers.
+ server applications comparable to RabbitMQ or multiplayer game servers.---
\ No newline at end of file
From e2c3013759a3d70f5ab087f6eedd81c7851bc2da Mon Sep 17 00:00:00 2001
From: Anthony Bullard <1380687+gamebox@users.noreply.github.com>
Date: Fri, 10 May 2024 05:34:21 -0500
Subject: [PATCH 06/10] Apply suggestions from code review
This will save some editing work, before I address the meatier comments.
Co-authored-by: Louis Pilfold
---
cheatsheets/gleam-for-go-users.md | 51 ++++++++++++-------------------
1 file changed, 20 insertions(+), 31 deletions(-)
diff --git a/cheatsheets/gleam-for-go-users.md b/cheatsheets/gleam-for-go-users.md
index 549cff2a..52e2e1e8 100644
--- a/cheatsheets/gleam-for-go-users.md
+++ b/cheatsheets/gleam-for-go-users.md
@@ -55,7 +55,7 @@ Multi line comments may be written like so:
*/
```
-IN Go, top level declarations can be annotated with a comment directly above it to create documentation for that symbol.
+In Go, top level declarations can be annotated with a comment directly above it to create documentation for that symbol.
```Go
// This is a special interface
@@ -163,7 +163,7 @@ Asserts should be used with caution.
#### Go
-Go is a statically typed language, and type annotations are generally required in most places. The exception is when variables or constants are initialized with a value. Multiple consecutive struct fields or function arguments of the same time can combined their type annotation.
+In Go type annotations are generally required in most places. The exception is when variables or constants are initialized with a value. Multiple consecutive struct fields or function arguments of the same time can combined their type annotation.
```Go
type Bar struct {
@@ -186,8 +186,7 @@ let some_string: String = "Foo"
Gleam will check the type annotation to ensure that it matches the type of the
assigned value. It does not need annotations to type check your code, but you
-may find it useful to annotate variables to hint to the compiler that you want
-a specific type to be inferred.
+may find them useful for documentation purposes.
## Functions
@@ -311,8 +310,8 @@ either `gleam run` or when the `entrypoint.sh` is executed.
Like Go, in Gleam only code that is within functions can be invoked.
-On the Beam, Gleam code can also be invoked from other Erlang code, or it
-can be invoked from browser's JavaScript, Deno or NodeJS runtime calls.
+On the BEAM, Gleam code can also be invoked from other Erlang code, or it
+can be invoked from JavaScript runtime calls.
### Function type annotations
@@ -472,9 +471,8 @@ are fully type checked.
- For bitwise operators, which exist in Go but not in Gleam,
see: .
- `==` is by default comparing value for primtive values, and reference for structs, arrays, and interface values in Go.
- - In Gleam it is always by value.
+ - In Gleam equality is checked for structurally.
- Go operators are short-circuiting as in Gleam.
-- In Go, all the arithmetic operators must have both arguments be of the same type, so `int` and `int32` values must be converted to one common type.
## Constants
@@ -566,9 +564,8 @@ the standard library. Interpolation can be accomplished using `Sprintf` and oth
similar functions found in `fmt` package amongst others in the standard library.
This uses C `strfmt` style format strings that are statically checked at compile time.
-In Gleam all strings are UTF-8 encoded binaries. Gleam strings do not allow
-interpolation, yet. Gleam however offers a `string_builder` via its standard
-library for performant string building.
+In Gleam all strings are unicode binaries. Gleam however offers a `StringBuilder` type via its standard
+library which may be more performant than joining strings in some scenarios.
#### Go
@@ -602,7 +599,6 @@ fmt.Print(myTuple.pwd)
```
```go
-// This is not idiomatic Go!
func returnUserInfo() (string, string, int) {
return "username", "password", 10
}
@@ -683,7 +679,7 @@ map.from_list([#("key1", "value1"), #("key2", 2)]) // Type error!
### Numbers
Go and Gleam both support platform-dependent sized integer and float types.
-`Integer` and `Float` in Gleam and `int` and `float` in Go sizes for both depend
+`Int` and `Float` in Gleam and `int` and `float` in Go sizes for both depend
on the platform: 64-bit or 32-bit hardware and OS and for Gleam JavaScript and Erlang.
#### Go
@@ -713,8 +709,8 @@ between floats and integers in various ways including `rounding`, `floor`,
### Case
-Case is one of the most used control flow in Gleam. It can be seen as a switch
-statement on steroids. It provides a terse way to match a value type to an
+Case is how control flow is done in Gleam. It can be seen as a switch
+statement with extra abilities. It provides a terse way to match a value type to an
expression. It is also used to replace `if`/`else` statements.
#### Go
@@ -933,15 +929,12 @@ recover.
#### Gleam
-In contrast in gleam, errors are just containers with an associated value.
-
-A common container to model an operation result is
-`Result(ReturnType, ErrorType)`.
+In Gleam functions that can fail return the `Result(success, error)` generic type.
A `Result` is either:
-- an `Error(ErrorValue)`
-- or an `Ok(Data)` record
+- an `Ok` record holding a success value
+- an `Error` record holding an error value
Handling errors actually means to match the return value against those two
scenarios, using a case for instance:
@@ -978,16 +971,12 @@ supported by both Gleam and Go.
### Go
-Type aliases in Go allow an Identifier to refer to a different type with it's
-scope.
-
```go
type Headers = []struct{key, value string}
```
### Gleam
-The `type` keyword can be used to create aliases.
```gleam
pub type Headers =
@@ -1042,7 +1031,7 @@ let person = Person(name: "Joe", age: 40)
let name = person.name
```
-An important difference to note is there is no Java-style object-orientation in
+An important difference to note is there is no object-orientation in
Gleam, thus methods can not be added to types. However opaque types exist,
see below.
@@ -1374,7 +1363,7 @@ To iterate a few foundational differences:
2. Guarantees: implicit nillability vs explicit nillability
3. Runtime model: lightweight coroutines(`goroutines`) VS Erlang/OTP processes
4. Error handling: error value (and very few panics) VS result type
-5. Distribution: Single static binaries vs Dynamically linked binary that relies on Erlang runtime
+5. Distribution: Single static binaries vs BEAM virtual machine bytecode
### Programming model
@@ -1416,7 +1405,7 @@ To iterate a few foundational differences:
### Runtime model
-- Gleam can run on Erlang/BEAM, on the browser but also Deno or NodeJS.
+- Gleam can run on Erlang or JavaScript runtimes.
- Gleam on Erlang/BEAM allows to processes requests in complete isolation,
unlike Go, where memory sharing is allowed - though communicating through
channels is recommended. Channels and Goroutines allow for good isolation
@@ -1426,12 +1415,12 @@ To iterate a few foundational differences:
The level of isolation means that, if a process crashes then the supervision
system can restart that process or after a while or amount of tries abort
repeating restarts on the process with that given input data. This means
- Erlang/BEAM will yield incredibly robust concurrent systems, even superior
+ Erlang can yield incredibly robust concurrent systems, even superior
to what experienced Gophers can accomplish with Goroutines, Channels, and
recover patterns.
- When executing Gleam code in fact its compiled Erlang or JavaScript is
executed. So in case there are runtime crashes, the crash log will show
- Erlang (or browser-console/NodeJS/Deno) debug information. In Gleam
+ Erlang or JavaScript debug information. In Gleam
applications runtime errors should almost never happen but they are harder
to read, in Go applications runtime errors might be more common but the will be
easier to read.
@@ -1442,7 +1431,7 @@ To iterate a few foundational differences:
type. There can however be other errors, such as miss-behavior due
accidental to division by 0, crashes on RAM or storage limits, hardware
failures, etc. In these cases on the BEAM there are ways to manage these
- via BEAM's supervision trees.
+ via Erlang/OTP's supervision trees.
- Go has explicit errors as well, and pairs it with multiple return values
to provide a similar experience to Gleam, but in an imperative, non-monadic
form. Go does have panics which will crash the running goroutine (and if that
From fcccb59a750eeeba97c5592450e49744d8ebf1c6 Mon Sep 17 00:00:00 2001
From: Anthony Bullard <1380687+gamebox@users.noreply.github.com>
Date: Fri, 10 May 2024 11:46:54 +0000
Subject: [PATCH 07/10] Addressing review feedback
---
cheatsheets/gleam-for-go-users.md | 101 +++++++++++++++---------------
1 file changed, 52 insertions(+), 49 deletions(-)
diff --git a/cheatsheets/gleam-for-go-users.md b/cheatsheets/gleam-for-go-users.md
index 52e2e1e8..ec7a37d8 100644
--- a/cheatsheets/gleam-for-go-users.md
+++ b/cheatsheets/gleam-for-go-users.md
@@ -234,11 +234,7 @@ mul(1, 2)
```
A difference between Go's and Gleam's anonymous functions is that in Go they
-create a new local scope but inherit the surrounding scope, in Gleam they close
-over the local scope, aka create a copy and inherit all variables in the scope.
-This means that in Gleam you can shadow local variables within anonymous functions
-but you cannot influence the variable bindings in the outer scope. In Go you can
-actually change the values in the outer scope, even if that scope has been returned.
+create a new local scope but inherit the surrounding scope, allowing you to mutate variables in that scope. In Gleam you can shadow local variables within anonymous functions but you cannot influence the variable bindings in the outer scope. In Go you can actually change the values in the outer scope, even if that scope has been returned.
The only difference between module functions and anonymous functions in Gleam
is that module functions heads may also feature argument labels, like so:
@@ -302,16 +298,10 @@ boundary between them.
### Gleam
-Gleam does not support a global scope. Instead Gleam code is either
-representing a library, which can be required as a dependency, and/or it
-represents an application having a main module, whose name must match to the
-application name and within that `main()`-function which will be called via
-either `gleam run` or when the `entrypoint.sh` is executed.
+Gleam does not support a global scope. Like Go, in Gleam only code that is within functions can be invoked.
-Like Go, in Gleam only code that is within functions can be invoked.
-
-On the BEAM, Gleam code can also be invoked from other Erlang code, or it
-can be invoked from JavaScript runtime calls.
+On the BEAM, Gleam code can also be invoked from other Erlang code. It
+can also be invoked from JavaScript runtime calls.
### Function type annotations
@@ -334,9 +324,7 @@ func mul(x, y int) bool {
#### Gleam
Functions can **optionally** have their argument and return types annotated in
-Gleam. These type annotations will always be checked by the compiler and throw
-a compilation error if not valid. The compiler will still type check your
-program using type inference if annotations are omitted.
+Gleam. These type annotations don't change how type checking works, but are good documentation for you and other readers of your code.
```gleam
fn add(x: Int, y: Int) -> Int {
@@ -469,7 +457,7 @@ are fully type checked.
### Notes on operators
- For bitwise operators, which exist in Go but not in Gleam,
- see: .
+ instead use the `bitwise_*` functions exposed in the `gleam/int` standard library module.
- `==` is by default comparing value for primtive values, and reference for structs, arrays, and interface values in Go.
- In Gleam equality is checked for structurally.
- Go operators are short-circuiting as in Gleam.
@@ -583,8 +571,8 @@ fmt.Sprintf("Hellø, %d!", what);
### Tuples
-Tuples are very useful in Gleam as they're the only collection data type that
-allows mixed types in the collection.
+Tuples are very useful in Gleam as they're a fixed-length collection data type that
+allows mixed types in the collection without naming the fields.
#### Go
@@ -642,9 +630,7 @@ unpracticed (or even experienced) Gopher.
#### Gleam
-Gleam has a `cons` operator that works for lists destructuring and
-pattern matching. In Gleam lists are immutable so adding and removing elements
-from the start of a list is highly efficient.
+Gleam has syntax for lists destructuring and pattern matching. In Gleam lists are immutable so adding and removing elements from the start of a list is highly efficient.
```gleam
let list = [2, 3, 4]
@@ -749,7 +735,7 @@ func httpErrorImpl2(status int) string {
#### Gleam
-The case operator is a top level construct in Gleam:
+In Gleam, the case expression is similar in concept:
```gleam
case some_number {
@@ -856,7 +842,11 @@ often.
```Go
// Imaginary Go code
-// TODO: Pick up here!
+func setOptions() somePkg.Options {
+ return options.New().
+ WithDelay(200).
+ WithCompression(true);
+}
```
#### Gleam
@@ -946,24 +936,35 @@ case parse_int("123") {
}
```
-In order to simplify this construct, we can use the `try` keyword that will:
-
-- either bind a value to the providing name if `Ok(Something)` is matched,
-- or **interrupt the current block's flow** and return `Error(Something)` from
- the given block.
+Sometimes this can get complicated, and there are functions like `try` from the `gleam/result` module in the standard library that can help:
```gleam
-let a_number = "1"
-let an_error = Error("ouch")
-let another_number = "3"
+pub fn without_use() {
+ result.try(get_username(), fn(username) {
+ result.try(get_password(), fn(password) {
+ result.map(log_in(username, password), fn(greeting) {
+ greeting <> ", " <> username
+ })
+ })
+ })
+}
+```
-try int_a_number = parse_int(a_number)
-try attempt_int = parse_int(an_error) // Error will be returned
-try int_another_number = parse_int(another_number) // never gets executed
+But this can get nested quickly. In order to simplify these scenarios, we can use the `use` construct which allows for a flattening of callbacks to make this code much easier
+to read, and somewhat gives one the feel of an early return.
-Ok(int_a_number + attempt_int + int_another_number) // never gets executed
+```gleam
+pub fn with_use() {
+ use username <- result.try(get_username()) // If this fails, we return its error
+ use password <- result.try(get_password()) // If this fails, we return its error
+ use greeting <- result.map(log_in(username, password))
+ greeting <> ", " <> username
+}
```
+You can see that `use` is great not just for error handling with `result.try`, but for
+dealing with higher order functions of all sorts.
+
## Type aliases
Type aliases allow for easy referencing of arbitrary complex types. They are
@@ -1094,6 +1095,8 @@ constraints.
#### Gleam
+Data modeling in Gleam will often use unions like seen below. It's a great way to hold single values of different types in a single value. Pattern matching makes them easy to work with and reason about.
+
```gleam
type IntOrFloat {
AnInt(Int)
@@ -1112,7 +1115,10 @@ fn int_or_float(X) {
In Go, you can choose to not export a type and then they will be considered
opaque to the user of your package. Just have the type have a lowercase
-identifier.
+identifier. Or, if it's desirable to have the type be referenceable by a
+consuming package, the name of the type can be uppercase(public), but all fields
+and methods of the type be lowercase(private). In the latter case the consumer
+will be able to construct a zero value for the type, which might not be desirable.
In Gleam, custom types can be defined as being opaque, which causes the
constructors for the custom type not to be exported from the module. Without
@@ -1123,7 +1129,7 @@ using the intended API.
```Go
package mypkg
-type myType struct { // Can't be used outside of this package
+type myType struct { // Can't be referenced outside of this package
}
@@ -1356,14 +1362,14 @@ Importing common types such as `gleam/order.{Lt, Eq, Gt}` or
## Architecture
-To iterate a few foundational differences:
+To iterate a few foundational differences (Go VS Gleam):
1. Programming model: imperative VS functional immutable
programming
-2. Guarantees: implicit nillability vs explicit nillability
+2. Guarantees: implicit nullability VS explicit nullability
3. Runtime model: lightweight coroutines(`goroutines`) VS Erlang/OTP processes
-4. Error handling: error value (and very few panics) VS result type
-5. Distribution: Single static binaries vs BEAM virtual machine bytecode
+4. Error handling: error value VS result type . Both do have some form of runtime panic or exception which can be recovered from.
+5. Distribution: Single static binaries VS BEAM virtual machine bytecode (or Javascript code).
### Programming model
@@ -1383,8 +1389,7 @@ To iterate a few foundational differences:
- Go features a massive, powerful standard library centered around simple interfaces.
Everything from string manipulation to the tools to create an http server are included
out of the box. It has been tuned for over 15 years for performance and has strong
- guarantees about backwards and forwards compatibility.
-- Gleam allows you to opt into a smaller, well polished and consistent standard
+ guarantees about backwards and forwards compatibility. While Gleam allows you to opt into a smaller, well polished and consistent standard
library.
### Guarantees and types
@@ -1395,9 +1400,7 @@ To iterate a few foundational differences:
comparisons and conversions must happen via function calls or other explicit type
conversion mechanisms.
- Go's checks happen at compile time (except for reflection), Gleam uses the compiler
- and pattern matching to allow for robust compile time check but does have interop
- with Erlang, a dynamically language that relies on good interfaces written in Gleam
- to provide any type-safety.
+ and pattern matching to allow for robust compile-time checks. But Gleam does have interop with Erlang, a dynamically-typed language that relies on good interfaces written in Gleam to provide any type-safety for those interactions.
- Go has limited type inference, all functions and data structures require explicit types.
Gleam's type inference allows you to be lazy for almost all type definitions.
Gleam's type system will always assist you in what types are expected and/or
@@ -1406,7 +1409,7 @@ To iterate a few foundational differences:
### Runtime model
- Gleam can run on Erlang or JavaScript runtimes.
-- Gleam on Erlang/BEAM allows to processes requests in complete isolation,
+- Gleam on Erlang allows to processes requests in complete isolation,
unlike Go, where memory sharing is allowed - though communicating through
channels is recommended. Channels and Goroutines allow for good isolation
if used in a disciplined manner. That being said, Mutexes and other shared
From d55a611037c45c1b88e57c498926408ab1b89854 Mon Sep 17 00:00:00 2001
From: Anthony Bullard <1380687+gamebox@users.noreply.github.com>
Date: Thu, 25 Jul 2024 08:31:33 -0500
Subject: [PATCH 08/10] Remove references to "foo" and "bar"
---
cheatsheets/gleam-for-go-users.md | 48 +++++++++++++++----------------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/cheatsheets/gleam-for-go-users.md b/cheatsheets/gleam-for-go-users.md
index ec7a37d8..a99f4e75 100644
--- a/cheatsheets/gleam-for-go-users.md
+++ b/cheatsheets/gleam-for-go-users.md
@@ -59,10 +59,10 @@ In Go, top level declarations can be annotated with a comment directly above it
```Go
// This is a special interface
-type Foo interface {}
+type Stringer interface {}
-// Bar struct
-type Bar Struct {}
+// Config struct
+type Config Struct {}
// This will quux a string
func Quux(str string) string {
@@ -166,7 +166,7 @@ Asserts should be used with caution.
In Go type annotations are generally required in most places. The exception is when variables or constants are initialized with a value. Multiple consecutive struct fields or function arguments of the same time can combined their type annotation.
```Go
-type Bar struct {
+type SomethingElse struct {
field string
otherField int
x, y float64
@@ -181,7 +181,7 @@ In Gleam type annotations can optionally be given when binding variables.
```gleam
let some_list: List(Int) = [1, 2, 3]
-let some_string: String = "Foo"
+let some_string: String = "A string"
```
Gleam will check the type annotation to ensure that it matches the type of the
@@ -354,17 +354,17 @@ func returnsAFunc() func() {
}
}
-type Bar struct {
+type SomethingElse struct {
something string
}
-func (b Bar) Func() {
- fmt.Printf("This bar has %s in something field", b.something)
+func (b SomethingElse) Func() {
+ fmt.Printf("This somethingElse has %s in something field", b.something)
}
func returnsAMethod() func() {
- bar := Bar{"Hello"}
- return bar.Func
+ somethingElse := SomethingElse{"Hello"}
+ return somethingElse.Func
}
func main() {
@@ -508,7 +508,7 @@ Blocks are declared via curly braces.
```Go
func aFunc() {
// A block starts here
- if foo {
+ if someBool {
// A block here
} else {
// A block here
@@ -1185,10 +1185,10 @@ common dependencies and are stored alongside one another. A _package_
in Go is closer to the Gleam concept of _modules_. The biggest difference
is that a _package_ in Go can be spread across many files in one directory.
-In `mymod/foo/foo.go`:
+In `mymod/something/something.go`:
```Go
-// Anything declared in the foo directory will be inside the /foo package
-package foo
+// Anything declared in the something directory will be inside the /something package
+package something
// This function is available for import by other packages
func Identity(x any) {
@@ -1198,10 +1198,10 @@ func Identity(x any) {
func privateFunc() {}
```
-In `mymod/foo/other.go`:
+In `mymod/something/other.go`:
```Go
-// Anything declared in the foo directory will be inside the /foo package
-package foo
+// Anything declared in the something directory will be inside the /something package
+package something
func otherFunc(x any) {
privateFunc() // Can be used here
@@ -1218,11 +1218,11 @@ package main
import (
"fmt"
m
- "someurl.com/mymod/foo"
+ "someurl.com/mymod/something"
)
func main() {
- fmt.Println(foo.Identity("Hello, world!"))
+ fmt.Println(something.Identity("Hello, world!"))
// privateFunc is not visible here
}
```
@@ -1241,24 +1241,24 @@ Since there is no special syntax to create a module, there can be only one
module in a file and since there is no way name the module the filename
always matches the module name which keeps things simple and transparent.
-In `/src/foo/bar.gleam`:
+In `/src/something/somethingElse.gleam`:
```gleam
// Creation of module function identity
-// in module bar
+// in module somethingElse
pub fn identity(x) {
x
}
```
-Importing the `bar` module and calling a module function:
+Importing the `somethingElse` module and calling a module function:
```gleam
// In src/main.gleam
-import foo/bar // if foo was in a directory called `lib` the import would be `lib/foo/bar`.
+import something/somethingElse // if something was in a directory called `lib` the import would be `lib/something/somethingElse`.
pub fn main() {
- bar.identity(1) // 1
+ somethingElse.identity(1) // 1
}
```
From 7a7278c643e89779b05fb6724043ad712c33aa1a Mon Sep 17 00:00:00 2001
From: Anthony Bullard <1380687+gamebox@users.noreply.github.com>
Date: Sun, 4 Aug 2024 11:40:23 -0500
Subject: [PATCH 09/10] Address new feedback
---
cheatsheets/gleam-for-go-users.md | 127 ++++++++++++++----------------
1 file changed, 61 insertions(+), 66 deletions(-)
diff --git a/cheatsheets/gleam-for-go-users.md b/cheatsheets/gleam-for-go-users.md
index a99f4e75..c17ef39e 100644
--- a/cheatsheets/gleam-for-go-users.md
+++ b/cheatsheets/gleam-for-go-users.md
@@ -212,8 +212,8 @@ Anonymous functions can also be defined and be bound to variables.
```Go
x := 2
-GoAnonFn := func(y) { return x * y } // Captures x
-GoAnonFn(2, 3) // 6
+GoAnonFn := func(y int) int { return x * y } // Captures x
+GoAnonFn(3) // 6
```
### Gleam
@@ -472,7 +472,7 @@ In Go, constants can only be defined at the top level of any file.
const theAnswer int = 42
func main() {
- fmt.Printf("%d\n", theAnswer) // 42
+ fmt.Printf("%d\n", theAnswer) // 42
}
```
@@ -507,13 +507,13 @@ Blocks are declared via curly braces.
```Go
func aFunc() {
- // A block starts here
- if someBool {
- // A block here
- } else {
- // A block here
- }
- // Block continues
+ // A block starts here
+ if someBool {
+ // A block here
+ } else {
+ // A block here
+ }
+ // Block continues
}
```
@@ -546,11 +546,7 @@ returned from an expression.
In Go strings are slices (dynamically sized arrays) of bytes. Those bytes are
arbitrary, and are not required to contain Unicode or any other string encoding.
-Go's standard library however has extensive support for string operations. Strings
-can be built efficiently with a `StringBuilder` type from the `strings` package in
-the standard library. Interpolation can be accomplished using `Sprintf` and other
-similar functions found in `fmt` package amongst others in the standard library.
-This uses C `strfmt` style format strings that are statically checked at compile time.
+Go's standard library however has extensive support for string operations, that relies heavily on C `strfmt` style format strings that are statically checked at compile time.
In Gleam all strings are unicode binaries. Gleam however offers a `StringBuilder` type via its standard
library which may be more performant than joining strings in some scenarios.
@@ -559,8 +555,8 @@ library which may be more performant than joining strings in some scenarios.
```Go
what := "world"
-"Hellø, world!"
-fmt.Sprintf("Hellø, %d!", what);
+// "Hellø, world!"
+fmt.Sprintf("Hellø, %v!", what)
```
#### Gleam
@@ -641,14 +637,14 @@ let [1, second_element, ..] = list
### Maps
-Maps are similar in Go and Gleam, except that they are mutated in Go and
+Maps are similar in Go and Gleam(where they are called Dicts), except that they are mutated in Go and
immutable in Gleam.
#### Go
```Go
myMap := map[string]string{
- "key1": "value1"
+ "key1": "value1"
}
fmt.Print(myMap["key1"])
```
@@ -708,28 +704,28 @@ Go features 2 different expressions to achieve similar goals:
```Go
func httpErrorImpl1(status int) string {
- if status == 400 {
- return "Bad request"
- } else if status == 404 {
- return "Not found"
- } else if status == 418 {
- return "I'm a teapot"
- } else {
- return "Internal Server Error"
- }
+ if status == 400 {
+ return "Bad request"
+ } else if status == 404 {
+ return "Not found"
+ } else if status == 418 {
+ return "I'm a teapot"
+ } else {
+ return "Internal Server Error"
+ }
}
func httpErrorImpl2(status int) string {
- switch (status) {
- case 400:
- return "Bad request"
- case 404:
- return "Not found"
- case 418:
- return "I'm a teapot"
- default:
- return "Internal Server Error"
- }
+ switch (status) {
+ case 400:
+ return "Bad request"
+ case 404:
+ return "Not found"
+ case 418:
+ return "I'm a teapot"
+ default:
+ return "Internal Server Error"
+ }
}
```
@@ -843,9 +839,9 @@ often.
```Go
// Imaginary Go code
func setOptions() somePkg.Options {
- return options.New().
- WithDelay(200).
- WithCompression(true);
+ return options.New().
+ WithDelay(200).
+ WithCompression(true);
}
```
@@ -897,7 +893,7 @@ support for multiple return values creates a very straightforward pattern
for error handling that almost defines the Go experience.
```Go
func aFunctionThatFails() error {
- return errors.New("This is an error")
+ return errors.New("This is an error")
}
```
@@ -1003,14 +999,14 @@ functions to construct a struct in an ergonomic way.
```Go
type Person struct {
- name string
- age int
+ name string
+ age int
}
func NewPerson(name string, age int) Person {
- return Person{ name, age } // Short hand literal construction
- // Could also be done with
- // return Person { name: name, age: age }
+ return Person{ name, age } // Short hand literal construction
+ // Could also be done with
+ // return Person { name: name, age: age }
}
// Inside of a function
@@ -1058,7 +1054,7 @@ type StructA struct {
age int
}
-func (s StructA) String() string { // This method fulfills the Stringer interface
+func (s StructA) String() string { // This method fulfills the Stringer interface
return fmt.Sprintf("%s,%d", s.name, s.age)
}
@@ -1067,7 +1063,7 @@ type StructB struct {
y int
}
-func (s StructB) String() string { // This method fulfills the Stringer interface
+func (s StructB) String() string { // This method fulfills the Stringer interface
return fmt.Sprintf("%d,%d", s.x, s.y)
}
@@ -1143,10 +1139,10 @@ package main
import "someurl.com/mymodule/mypkg"
func main() {
- mt := mypkg.SomeFunc()
- if mypkg.OtherFunc(mt) {
- fmt.Println("I can use the opaque type but can't create it!")
- }
+ mt := mypkg.SomeFunc()
+ if mypkg.OtherFunc(mt) {
+ fmt.Println("I can use the opaque type but can't create it!")
+ }
}
```
@@ -1192,7 +1188,7 @@ package something
// This function is available for import by other packages
func Identity(x any) {
- return x;
+ return x;
}
func privateFunc() {}
@@ -1204,8 +1200,8 @@ In `mymod/something/other.go`:
package something
func otherFunc(x any) {
- privateFunc() // Can be used here
- return x;
+ privateFunc() // Can be used here
+ return x;
}
```
@@ -1216,14 +1212,13 @@ We can now call Identity from the main package in your binary.
package main
import (
- "fmt"
-m
- "someurl.com/mymod/something"
+ "fmt"
+ "someurl.com/mymod/something"
)
func main() {
- fmt.Println(something.Identity("Hello, world!"))
- // privateFunc is not visible here
+ fmt.Println(something.Identity("Hello, world!"))
+ // privateFunc is not visible here
}
```
@@ -1275,11 +1270,11 @@ qualifier is the name of the containing module, which by convention is the url
at which the module is hosted.
```go
-import "fmt" // Single import. Stdlib packages are referenced bare, no path required
+import "fmt" // Single import. Stdlib packages are referenced bare, no path required
import ( // Multi-package import
- "strings" // Available for use as `strings`
+ "strings" // Available for use as `strings`
- "github.com/example/example-go-project/somepkg" // Will be available as `somepkg`
+ "github.com/example/example-go-project/somepkg" // Will be available as `somepkg`
)
```
@@ -1317,11 +1312,11 @@ Go allows you to alias a package import
```go
import (
- other "github.com/example/example-go-project/somepkg"
+ other "github.com/example/example-go-project/somepkg"
)
func main() {
- other.SomeFunc()
+ other.SomeFunc()
}
```
From 48336c7868900acde4cd3c1850cb52a4079ae30f Mon Sep 17 00:00:00 2001
From: Anthony Bullard <1380687+gamebox@users.noreply.github.com>
Date: Sun, 4 Aug 2024 11:48:44 -0500
Subject: [PATCH 10/10] Last bit of feedback
---
cheatsheets/gleam-for-go-users.md | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/cheatsheets/gleam-for-go-users.md b/cheatsheets/gleam-for-go-users.md
index c17ef39e..1001c0b9 100644
--- a/cheatsheets/gleam-for-go-users.md
+++ b/cheatsheets/gleam-for-go-users.md
@@ -197,14 +197,14 @@ keyword is required if the function has a return value, and optional otherwise.
```Go
func hello(name string) string {
- if name == 'Joe' {
- return 'Welcome back, Joe!'
- }
- return "Hello $name"
+ if name == "Joe" {
+ return "Welcome back, Joe!"
+ }
+ return fmt.Sprintf("Hello %s", name)
}
func noop() {
- // No return value
+ // No return value
}
```
@@ -256,17 +256,17 @@ In Go, functions are exported if their name is capitalized, and private to the p
```Go
func PublicHello(name string) string { // Exported
- if name == 'Joe' {
- return 'Welcome back, Joe!'
- }
- return "Hello $name"
+ if name == "Joe" {
+ return "Welcome back, Joe!"
+ }
+ return fmt.Sprintf("Hello %s", name)
}
func privateHello(name string) string { // Package private
- if name == 'Joe' {
- return 'Welcome back, Joe!'
- }
- return "Hello $name"
+ if name == "Joe" {
+ return "Welcome back, Joe!"
+ }
+ return fmt.Sprintf("Hello %s", name)
}
```
@@ -313,11 +313,11 @@ Again, multiple consecutive arugments of the same type can share an annotation.
```Go
func sum(x, y int) int {
- return x + y
+ return x + y
}
func mul(x, y int) bool {
- return x * y // This will be a compile-time error
+ return x * y // This will be a compile-time error
}
```