From 13befc87a7cde98e8306302dff902c7bb341e207 Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sat, 9 Sep 2023 18:29:02 +0100 Subject: [PATCH 01/23] Fix typo in PHP guide --- cheatsheets/gleam-for-php-users.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cheatsheets/gleam-for-php-users.md b/cheatsheets/gleam-for-php-users.md index 25caa54d..9e10d86a 100644 --- a/cheatsheets/gleam-for-php-users.md +++ b/cheatsheets/gleam-for-php-users.md @@ -55,7 +55,7 @@ Multi line comments may be written like so: */ ``` -IN PHP, above `trait`, `interface`, `class`, `member`, `function` declarations +In PHP, above `trait`, `interface`, `class`, `member`, `function` declarations there can be `docblocks` like so: ```php From c2ae74f976904942cb065cefa86f5bc3b3d7c4e9 Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Mon, 11 Sep 2023 20:16:19 +0100 Subject: [PATCH 02/23] Start writing the JavaScript cheatsheet --- cheatsheets/gleam-for-javascript-users.md | 318 ++++++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 cheatsheets/gleam-for-javascript-users.md diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md new file mode 100644 index 00000000..1d7c3725 --- /dev/null +++ b/cheatsheets/gleam-for-javascript-users.md @@ -0,0 +1,318 @@ +--- +layout: page +title: Gleam for JavaScript users +subtitle: Hello JavaScripticians! +--- + +- [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) + - [Function heads](#function-heads) + - [Function overloading](#function-overloading) + - [Referencing functions](#referencing-function) + - [Calling anonymous functions](#calling-anonymous-functions) + - [Labelled arguments](#labelled-arguments) +- [Modules](#modules) +- [Operators](#operators) +- [Constants](#constants) +- [Blocks](#blocks) +- [Data types](#data-types) + - [Strings](#strings) + - [Tuples](#tuples) + - [Lists](#lists) + - [Atoms](#atoms) + - [Maps](#maps) +- [Patterns] TODO +- [Flow control](#flow-control) TODO + - [Case](#case) TODO + - [Try](#try) TODO +- [Type aliases](#type-aliases) TODO +- [Custom types](#custom-types) + - [Records](#records) + - [Unions](#unions) + - [Opaque custom types](#opaque-custom-types) TODO +- [Modules](#modules) TODO + - [Imports](#imports) TODO + - [Nested modules](#nested-modules) TODO + - [First class modules](#first-class-modules) TODO + + +## Comments + +### JavaScript + +In JavaScript, comments are written with a `//` prefix. + +```javascript +// Hello, Joe! +``` + +Multi-line comments may be written like so: + +```javascript +/* + * Hello, Joe! + */ +``` + +In JavaScript, above `class` and `function` declarations there can be +`docblocks` like so: + +```javascript +/** + * A Bar class + */ +class Bar {} + +/** + * A quux function. + * + * @param {string} str String passed to quux + * @returns {string} An unprocessed string + */ +function quux(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 statement. 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 +``` + +## Variables + +In JavaScript, you can declare variables using `let`, `const`, or `var`. `let` +and `var` variables can be reassigned, and `const`s cannot. + +#### JavaScript + +```javascript +let size = 50; +size = size + 100; + +const height = 60; +const height = height + 100; // Error! +``` + +#### Gleam + +Gleam has the `let` keyword before each variable assignment. Variables can be +reassigned, but each assignment must start with the `let` keyword. + +```gleam +let size = 50 +let size = size + 100 +let size = 1 +``` + +### Variables type annotations + +#### JavaScript/TypeScript + +In plain JavaScript there are no static types, but in TypeScript variables can +optionally be annotated with types. + +```typescript +const some_list: number[] = [1, 2, 3]; +``` + +#### Gleam + +In Gleam type annotations can optionally be given when binding variables. + +```gleam +let some_list: List(Int) = [1, 2, 3] +``` + +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 + +#### JavaScript + +In JavaScript, you can define functions with the `function` keyword, or assign +anonymous functions to variables. + +```javascript +function sum(x, y) { + return x + y; +} + +const mul = (x, y) => x * y; +``` + +#### Gleam + +Gleam's functions are declared using a syntax similar to Rust. Gleam's anonymous functions have a similar syntax, just without the function name. + +```gleam +pub fn sum(x, y) { + x + y +} + +let mul = fn(x, y) { x * y } +mul(1, 2) +``` + +### Exporting functions + +#### JavaScript + +In both JavaScript and Gleam, functions are private by default. In JavaScript, +functions can be made public with the `export` keyword. + +```javascript +// this is public +export function sum(x, y) { + return x + y; +} + +// this is private +function mul(x, y) { + return x * y; +} +``` + +#### Gleam + +In Gleam functions need the `pub` keyword to be public. + +```gleam +// this is public +pub fn sum(x, y) { + x + y +} + +// this is private +fn mul(x, y) { + x * y +} +``` + +### Function type annotations + +#### JavaScript/TypeScript + +In TypeScript, you can annotate the types of function parameters and return +values. + +```typescript +function sum(x: number, y: number): number { + return x + y; +} +``` + +The choice of whether, and exactly how to annotate a function can influence how +type-safe your code is. + +#### Gleam + +In Gleam, functions can **optionally** have their argument and return types +annotated. 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 +pub fn add(x: Int, y: Int) -> Int { + x + y +} + +pub fn mul(x: Int, y: Int) -> Bool { // compile error, type mismatch + x * y +} +``` + +### Function overloading + +Like JavaScript, Gleam does not support function overloading, so there can only +be 1 function with a given name, and the function can only have a single +implementation for the types it accepts. + +### Referencing functions + +Referencing functions in Gleam works like in JavaScript, without any special +syntax. + +#### JavaScript +```javascript +function identity(x) { + return x +} + +function main() { + const func = identity; + func(100); +} +``` + +#### Gleam +```gleam +fn identity(x) { + x +} + +fn main() { + let func = identity + func(100) +} +``` + + +### Labelled arguments + +#### JavaScript + +JavaScript doesn't really have a syntax for passing arguments by name and in any +order, but this behavior can be approximated using an object literal. + +```javascript +function replace({ inside: string, each: pattern, with: replacement }) { + go(string, pattern, replacement) +} +``` + +```javascript +replace({ each: ",", with: " ", inside: "A,B,C" }); +``` + +Because the arguments are stored in an object there is a small runtime +performance penalty for this pattern. + +#### Gleam + +In Gleam arguments can be given a label as well as an internal name. 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 string, each pattern, with replacement) { + go(string, pattern, replacement) +} +``` + +```gleam +replace(each: ",", with: " ", inside: "A,B,C") +``` + +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. + From 377b9fc05fe235f83af47ae7f9dabe0323a562ee Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Wed, 13 Sep 2023 18:49:51 +0100 Subject: [PATCH 03/23] Add operators --- cheatsheets/gleam-for-javascript-users.md | 29 +++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index 1d7c3725..079c2faa 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -316,3 +316,32 @@ 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 | JavaScript | Gleam | Notes | +| ----------------- | ---------- | ----- | ---------------------------------------------- | +| Equal | `==` | `==` | In Gleam both values must be of the same type | +| Strictly equal to | `===` | `==` | Comparison in Gleam is always strict | +| Not equal | `!==` | `!=` | In Gleam both values must be of the same type | +| Greater than | `>` | `>` | In Gleam both values must be **ints** | +| Greater than | `>` | `>.` | In Gleam both values must be **floats** | +| Greater or equal | `>=` | `>=` | In Gleam both values must be **ints** | +| Greater or equal | `>=` | `>=.` | In Gleam both values must be **floats** | +| Less than | `<` | `<` | In Gleam both values must be **ints** | +| Less than | `<` | `<.` | In Gleam both values must be **floats** | +| Less or equal | `<=` | `<=` | In Gleam both values must be **ints** | +| Less or equal | `<=` | `<=.` | In Gleam both values must be **floats** | +| Boolean and | `&&` | `&&` | In Gleam both values must be **bools** | +| Boolean or | `||` | `||` | In Gleam both values must be **bools** | +| Add | `+` | `+` | In Gleam both values must be **ints** | +| Add | `+` | `+.` | In Gleam both values must be **floats** | +| Subtract | `-` | `-` | In Gleam both values must be **ints** | +| Subtract | `-` | `-.` | In Gleam both values must be **floats** | +| Multiply | `*` | `*` | In Gleam both values must be **ints** | +| Multiply | `*` | `*.` | In Gleam both values must be **floats** | +| Divide | `/` | `/` | In Gleam both values **ints** | +| Divide | `/` | `/.` | In Gleam both values must be **floats** | +| Remainder | `%` | `%` | In Gleam both values must be **ints** | +| Concatenate | `+` | `<>` | In Gleam both values must be **strings** | +| Pipe | | `|>` | Gleam's pipe can pipe into anonymous functions | + From 4d5fcef1b55a195b7e92d958fb953108463f7679 Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sun, 17 Sep 2023 11:41:31 +0100 Subject: [PATCH 04/23] Fix another typo in PHP cheatsheet --- cheatsheets/gleam-for-php-users.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cheatsheets/gleam-for-php-users.md b/cheatsheets/gleam-for-php-users.md index 9e10d86a..17f591d4 100644 --- a/cheatsheets/gleam-for-php-users.md +++ b/cheatsheets/gleam-for-php-users.md @@ -521,7 +521,7 @@ are fully type checked. see: . - `==` is by default comparing by value in PHP: - Types may be autocast to be compareable. - - Two objects with the same members values will equal: + - Two objects with the same members values will equal. - `===` is for comparing by strict equality in PHP: - Types will not be autocast for comparison - Two objects with the same members will not equal. Only if a variable binds From a393b13683b4eea4c0cc2ddb5a01a8603438320d Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sun, 17 Sep 2023 11:42:10 +0100 Subject: [PATCH 05/23] Continue writing JavaScript cheatsheet --- cheatsheets/gleam-for-javascript-users.md | 57 +++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index 079c2faa..9d0a5881 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -345,3 +345,60 @@ are fully type checked. | Concatenate | `+` | `<>` | In Gleam both values must be **strings** | | Pipe | | `|>` | Gleam's pipe can pipe into anonymous functions | +### Notes on operators + +- JavaScript operators are short-circuiting as in Gleam. +- Gleam's `/` operator always returns an integer. +- Chains and pipes: + - In JavaScript 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. + - 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 + +#### JavaScript + +In JavaScript constants are just regular variables using the `const` keyword. + +```javascript +const THE_ANSWER = 42; + +function main() { + const justANormalVariable = "can also use the const keyword"; + return THE_ANSWER; +} +``` + +#### Gleam + +In Gleam constants are also created using the `const` keyword. The difference to +JavaScript is that Gleam constants can only live at the top-level of a module +(not inside a function), and variables defined using `let` can only live inside +functions (not at the top-level of a module). + +```gleam +const the_answer = 42 + +pub fn main() { + the_answer +} +``` + +Additionally, Gleam constants can be referenced from other modules. + +```gleam +// in file other_module.gleam +pub const the_answer: Int = 42 +``` + +```gleam +import other_module + +fn main() { + other_module.the_answer +} +``` + From 67bae32968444960e04498ca374e27e0ca336039 Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sun, 17 Sep 2023 18:18:20 +0100 Subject: [PATCH 06/23] Add block syntax --- cheatsheets/gleam-for-javascript-users.md | 46 +++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index 9d0a5881..d6058ac1 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -402,3 +402,49 @@ fn main() { } ``` +## Blocks + +#### JavaScript + +In JavaScript statements can be grouped together using braces `{` `}`. These +blocks are usually associated with specific language constructs like functions, +conditionals, loops, etc. The only way to create multi-line expression blocks +like in Gleam is using an immediately-invoked function expression (IIFE). + +Parentheses `(` `)` are used to group arithmetic expressions. + +```javascript +function main() { + // x gets assigned the result of the IIFE + const x = (() => { + console.log(1); + return 2; + })(); + const y = x * (x + 10); // parentheses are used to change arithmetic operations order + return y; +} +``` + +#### Gleam + +In Gleam curly braces, `{` and `}`, are used to group expressions. + +```gleam +pub fn main() { + let x = { + print(1) + 2 + } + // Braces are used to change arithmetic operations order + let y = x * { x + 10 } + y +} +``` + +Unlike in JavaScript, 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. + From 267b505958b89b19fc831e48f2c29e0459ad0148 Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sun, 17 Sep 2023 18:21:15 +0100 Subject: [PATCH 07/23] Fix some more PHP typos --- cheatsheets/gleam-for-php-users.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cheatsheets/gleam-for-php-users.md b/cheatsheets/gleam-for-php-users.md index 17f591d4..57dfd325 100644 --- a/cheatsheets/gleam-for-php-users.md +++ b/cheatsheets/gleam-for-php-users.md @@ -512,7 +512,7 @@ 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** +| Concatenate | `.` | `<>` | In Gleam both values must be **String** | | Pipe | `->` | |> | Gleam's pipe can chain function calls. See note for PHP | ### Notes on operators @@ -520,7 +520,7 @@ are fully type checked. - For bitwise operators, which exist in PHP but not in Gleam, see: . - `==` is by default comparing by value in PHP: - - Types may be autocast to be compareable. + - Types may be autocast to be comparable. - Two objects with the same members values will equal. - `===` is for comparing by strict equality in PHP: - Types will not be autocast for comparison From becc61ddef8c029ffcd09d6a563f78d0f142e052 Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sun, 17 Sep 2023 19:07:30 +0100 Subject: [PATCH 08/23] More PHP typos --- cheatsheets/gleam-for-php-users.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cheatsheets/gleam-for-php-users.md b/cheatsheets/gleam-for-php-users.md index 57dfd325..758d6d2d 100644 --- a/cheatsheets/gleam-for-php-users.md +++ b/cheatsheets/gleam-for-php-users.md @@ -1303,7 +1303,7 @@ pub fn main() { #### PHP PHP features ways to load arbitrary PHP code: `require`, `include` and -autoload such as `spl_autoload_register`. Once class pathes are known and +autoload such as `spl_autoload_register`. Once class paths are known and registered for autoloading, they can brought into the scope of a file by using the `use`statement which is part of PHP's namespacing. Also see . @@ -1453,12 +1453,12 @@ To iterate a few foundational differences: or the memory limit is exceeded. - Gleam on Erlang/BEAM allows to processes requests in a similar isolation level that PHP offers in contrast to applications running *Go* or *Ruby*. - The level of isoluation means that, very similar to PHP, if a process + The level of isolation means that, very similar to PHP, if a process crashes (in PHP 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 PHP developers are used - to and similar isolation guarantuees. + to and similar isolation guarantees. - 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 From 820e11021d5ee3df916073ed99be656d6265999a Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sat, 23 Sep 2023 19:13:39 +0100 Subject: [PATCH 09/23] Add lists section --- cheatsheets/gleam-for-javascript-users.md | 95 +++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index d6058ac1..f570fe15 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -4,6 +4,8 @@ title: Gleam for JavaScript users subtitle: Hello JavaScripticians! --- + + - [Comments](#comments) - [Variables](#variables) - [Match operator](#match-operator) @@ -448,3 +450,96 @@ 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 + +#### JavaScript + +In JavaScript strings are sequences of UTF-16 code units, and can be delimited +by single quotes `'`, double quotes `"`, or backticks `. +Strings using backticks support interpolation. + +```javascript +const world = 'world'; +"Hellø, world!" +`Hello, ${world}!` +``` + +#### Gleam + +In Gleam strings are encoded as UTF-8 binaries, and must be delimited by double +quotes. Gleam strings do not allow interpolation, yet. Gleam however offers a +`string_builder` via its standard library for performant string building. + +```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. + +#### JavaScript + +JavaScript doesn't have a concept of tuples, but some tuple behavior can be +imitated using arrays. + +```javascript +const myArray = ["username", "password", 10]; +const [_, password] = myArray; +console.log(password); // "password" +// Direct index access +console.log(myArray[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 JavaScript are allowed to be of mixed types, but not in Gleam. + +#### JavaScript + +JavaScript arrays are delimited by square brackets `[` `]`. The `...` operator +can insert one array into another. + +```javascript +let list = [2, 3, 4]; +list = [1, ...list, 3]; +const [firstElement, secondElement, ...rest] = list; +console.log(["hello", ...list]); // works +``` + +#### 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 +``` + +An important difference between Gleam's "cons" operator and JavaScript's `...` +is that the `..tail` can only appear as the last item between the brackets. + +```gleam +let list = [2, 3, 4] +let list = [1, ..list] // works +let list = [1, 2, ..list] // still works +let list = [1, ..list, 5] // compile error +``` + From 85f9b04deb62408cc9286510d236ed001c9e3ede Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sun, 1 Oct 2023 10:52:08 +0100 Subject: [PATCH 10/23] Add section on maps --- cheatsheets/gleam-for-javascript-users.md | 57 +++++++++++++++++------ 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index f570fe15..b2f9cf87 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -28,19 +28,10 @@ subtitle: Hello JavaScripticians! - [Lists](#lists) - [Atoms](#atoms) - [Maps](#maps) -- [Patterns] TODO -- [Flow control](#flow-control) TODO - - [Case](#case) TODO - - [Try](#try) TODO -- [Type aliases](#type-aliases) TODO -- [Custom types](#custom-types) - - [Records](#records) - - [Unions](#unions) - - [Opaque custom types](#opaque-custom-types) TODO -- [Modules](#modules) TODO - - [Imports](#imports) TODO - - [Nested modules](#nested-modules) TODO - - [First class modules](#first-class-modules) TODO +- [Flow control](#flow-control) + - [Case](#case) + - [Piping](#piping) + - [Try](#try) ## Comments @@ -73,8 +64,8 @@ class Bar {} /** * A quux function. * - * @param {string} str String passed to quux - * @returns {string} An unprocessed string + * @param {string} str String passed to quux + * @returns {string} An unprocessed string */ function quux(string) { return str; } ``` @@ -543,3 +534,39 @@ let list = [1, 2, ..list] // still works let list = [1, ..list, 5] // compile error ``` +### Maps + +#### JavaScript + +In JavaScript, key–value pairs are usually stored in objects, whose keys can +only be strings, numbers, or symbols. There is also the `Map` class, which +allows any type to be used for keys. In both cases, types of keys and values can +be mixed in a given map. + +```javascript +const map1 = { + key1: "value1", + key2: 5, +}; +``` + +#### Gleam + +In a Gleam map, the type for keys and the type for values are fixed. So, for +example, you can't have a map with some `String` values and some `Int` values, +and you can't have a map with some `String` keys and some `Int` values. But you +can have a map with `String` keys and `Int` values. + +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. (You +would usually translate a TypeScript `type`, `class`, or `interface` to a Gleam +custom type, and TypeScript `Map`s and `Record`s to Gleam maps.) + +```gleam +import gleam/map + +map.from_list([#("key1", "value1"), #("key2", "value2")]) +map.from_list([#("key1", "value1"), #("key2", 2)]) // Type error! +``` + + From 314c28c8538b40765f51fbf890c75ca0dea1755f Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Tue, 3 Oct 2023 13:10:04 +0100 Subject: [PATCH 11/23] Start control flow --- cheatsheets/gleam-for-javascript-users.md | 11 +++++++++++ cheatsheets/gleam-for-php-users.md | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index b2f9cf87..60d10f1f 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -569,4 +569,15 @@ map.from_list([#("key1", "value1"), #("key2", "value2")]) map.from_list([#("key1", "value1"), #("key2", 2)]) // Type error! ``` +## Flow control + +### Case + +Case is one of the most used control flow methods 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, which + Gleam doesn't have. + +#### JavaScript + diff --git a/cheatsheets/gleam-for-php-users.md b/cheatsheets/gleam-for-php-users.md index 758d6d2d..8c57435a 100644 --- a/cheatsheets/gleam-for-php-users.md +++ b/cheatsheets/gleam-for-php-users.md @@ -765,9 +765,9 @@ 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 -expression. It is also used to replace `if`/`else` statements. +Case is one of the most used control flow methods 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. #### PHP From abf0441cc22d7f3eceb13a68fbe6d69e9b13baa7 Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sat, 27 Apr 2024 17:23:28 +0100 Subject: [PATCH 12/23] Improve `case` paragraph --- cheatsheets/gleam-for-javascript-users.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index 60d10f1f..4d21e787 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -573,10 +573,10 @@ map.from_list([#("key1", "value1"), #("key2", 2)]) // Type error! ### Case -Case is one of the most used control flow methods 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, which - Gleam doesn't have. +`case` is one of the most used control flow methods 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, which Gleam +doesn't have. #### JavaScript From 13496e0fc6a1eda04217ede9facf5cf071ce12c9 Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sat, 27 Apr 2024 17:24:10 +0100 Subject: [PATCH 13/23] map -> dict --- cheatsheets/gleam-for-javascript-users.md | 33 ++++++++++++++--------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index 4d21e787..ed0eac15 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -27,7 +27,7 @@ subtitle: Hello JavaScripticians! - [Tuples](#tuples) - [Lists](#lists) - [Atoms](#atoms) - - [Maps](#maps) + - [Dicts](#dicts) - [Flow control](#flow-control) - [Case](#case) - [Piping](#piping) @@ -534,7 +534,7 @@ let list = [1, 2, ..list] // still works let list = [1, ..list, 5] // compile error ``` -### Maps +### Dicts #### JavaScript @@ -548,25 +548,32 @@ const map1 = { key1: "value1", key2: 5, }; + +const actualMap = new Map([ + ["key1", "value1"], + [9, 5], +]); ``` #### Gleam -In a Gleam map, the type for keys and the type for values are fixed. So, for -example, you can't have a map with some `String` values and some `Int` values, -and you can't have a map with some `String` keys and some `Int` values. But you -can have a map with `String` keys and `Int` values. +In a Gleam `dict`, the type for keys and the type for values are fixed. So, for +example, you can't have a dict with some `String` values and some `Int` values, +and you can't have a dict with some `String` keys and some `Int` keys. But you +can have a dict with `String` keys and `Int` values. + +There is no dict literal syntax in Gleam, and you cannot pattern match on a +dict. Maps are generally not used much in Gleam, custom types are more common. -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. (You -would usually translate a TypeScript `type`, `class`, or `interface` to a Gleam -custom type, and TypeScript `Map`s and `Record`s to Gleam maps.) +(You would usually translate a TypeScript `type` or `class` to a Gleam custom +type, and only use a Gleam `Map` for arbitrary key–value pairs, equivalent to a +TypeScript `Map` or `Record`.) ```gleam -import gleam/map +import gleam/dict -map.from_list([#("key1", "value1"), #("key2", "value2")]) -map.from_list([#("key1", "value1"), #("key2", 2)]) // Type error! +dict.from_list([#("key1", "value1"), #("key2", "value2")]) +dict.from_list([#("key1", "value1"), #("key2", 2)]) // Type error! ``` ## Flow control From 921035a811aa4ce9f37c139698cdd13723e3fe05 Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sat, 27 Apr 2024 17:24:55 +0100 Subject: [PATCH 14/23] Formatting --- cheatsheets/gleam-for-javascript-users.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index ed0eac15..968c0c36 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -102,7 +102,7 @@ let size = 50; size = size + 100; const height = 60; -const height = height + 100; // Error! +height = height + 100; // Error! ``` #### Gleam @@ -135,7 +135,10 @@ In Gleam type annotations can optionally be given when binding variables. let some_list: List(Int) = [1, 2, 3] ``` -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. +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 @@ -154,7 +157,8 @@ const mul = (x, y) => x * y; #### Gleam -Gleam's functions are declared using a syntax similar to Rust. Gleam's anonymous functions have a similar syntax, just without the function name. +Gleam's functions are declared using a syntax similar to Rust. Gleam's anonymous +functions have a similar syntax, just without the function name. ```gleam pub fn sum(x, y) { From 6212b39677ed344a36be9dd58ade104c1344b458 Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sat, 27 Apr 2024 17:25:52 +0100 Subject: [PATCH 15/23] Improve code examples --- cheatsheets/gleam-for-javascript-users.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index 968c0c36..29a15891 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -282,7 +282,7 @@ order, but this behavior can be approximated using an object literal. ```javascript function replace({ inside: string, each: pattern, with: replacement }) { - go(string, pattern, replacement) + return string.replace(new RegExp(pattern, "g"), replacement); } ``` @@ -301,7 +301,7 @@ inside the function. ```gleam pub fn replace(inside string, each pattern, with replacement) { - go(string, pattern, replacement) + // ... } ``` From 9ddfc7bf2c5fe23f3639eac5ca8620473f57a7cf Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sat, 27 Apr 2024 17:26:14 +0100 Subject: [PATCH 16/23] Get rid of function overloading --- cheatsheets/gleam-for-javascript-users.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index 29a15891..043c3332 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -14,7 +14,6 @@ subtitle: Hello JavaScripticians! - [Exporting functions](#exporting-functions) - [Function type annotations](#function-type-annotations) - [Function heads](#function-heads) - - [Function overloading](#function-overloading) - [Referencing functions](#referencing-function) - [Calling anonymous functions](#calling-anonymous-functions) - [Labelled arguments](#labelled-arguments) @@ -237,12 +236,6 @@ pub fn mul(x: Int, y: Int) -> Bool { // compile error, type mismatch } ``` -### Function overloading - -Like JavaScript, Gleam does not support function overloading, so there can only -be 1 function with a given name, and the function can only have a single -implementation for the types it accepts. - ### Referencing functions Referencing functions in Gleam works like in JavaScript, without any special From 9ac6e397ea9b902080f31659f0fc66feac2a00e2 Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sat, 27 Apr 2024 17:39:40 +0100 Subject: [PATCH 17/23] Add function capturing --- cheatsheets/gleam-for-javascript-users.md | 28 +++++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index 043c3332..5c0f900d 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -4,18 +4,15 @@ title: Gleam for JavaScript users subtitle: Hello JavaScripticians! --- - - - [Comments](#comments) - [Variables](#variables) - [Match operator](#match-operator) - [Variables type annotations](#variables-type-annotations) - [Functions](#functions) + - [Function capturing with `_`](#function-capturing-with-_) - [Exporting functions](#exporting-functions) - [Function type annotations](#function-type-annotations) - - [Function heads](#function-heads) - [Referencing functions](#referencing-function) - - [Calling anonymous functions](#calling-anonymous-functions) - [Labelled arguments](#labelled-arguments) - [Modules](#modules) - [Operators](#operators) @@ -30,7 +27,6 @@ subtitle: Hello JavaScripticians! - [Flow control](#flow-control) - [Case](#case) - [Piping](#piping) - - [Try](#try) ## Comments @@ -80,7 +76,8 @@ In Gleam comments are written with a `//` prefix. // Hello, Joe! ``` -Comments starting with `///` are used to document the following statement. Comments starting with `////` are used to document the current module. +Comments starting with `///` are used to document the following statement. +Comments starting with `////` are used to document the current module. ```gleam //// This module is very important. @@ -168,6 +165,23 @@ let mul = fn(x, y) { x * y } mul(1, 2) ``` +### Function capturing with `_` + +To turn a multi-parameter function into a function with just one parameter, +Gleam has a special function-capturing syntax: + +```gleam +fn add(a: Int, b: Int) -> Int { + a + b +} + +let add2 = fn(x) { add(x, 2) } +// is equivalent to: +let add2 = add(_, 2) +``` + +This is particularly useful in combination with the [pipe operator](#piping). + ### Exporting functions #### JavaScript @@ -271,7 +285,7 @@ fn main() { #### JavaScript JavaScript doesn't really have a syntax for passing arguments by name and in any -order, but this behavior can be approximated using an object literal. +order, but this behaviour can be approximated using an object literal. ```javascript function replace({ inside: string, each: pattern, with: replacement }) { From 18fac814e8964b7d56ffbfd78292aa7f27eca538 Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sat, 27 Apr 2024 17:59:29 +0100 Subject: [PATCH 18/23] Add pipe operator --- cheatsheets/gleam-for-javascript-users.md | 30 ++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index 5c0f900d..dd26269e 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -592,10 +592,34 @@ dict.from_list([#("key1", "value1"), #("key2", 2)]) // Type error! ### Case `case` is one of the most used control flow methods 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, which Gleam +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, which Gleam doesn't have. -#### JavaScript +### Piping + +In JavaScript, method calls are easy to chain together: +```javascript +"hello, world".toUpperCase().repeat(2).split(',') +``` + +Since Gleam doesn't have objects with methods, the equivalent code might look +like this: + +```gleam +import gleam/string +string.split(string.repeat(string.uppercase("hello, world"), times: 2), ",") +``` + +To make this more readable, Gleam has the pipe operator `|>` + +```gleam +import gleam/string + +"hello, world" +|> string.uppercase +|> string.repeat(2) // defaults to piping into the first argument +|> string.split(_, ",") // you can use _ to specify the argument to pipe into +``` From 88fede280420d89d12892a6a81715e88c0519ca8 Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sat, 27 Apr 2024 18:07:45 +0100 Subject: [PATCH 19/23] Add note on heterogeneous lists --- cheatsheets/gleam-for-javascript-users.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index dd26269e..8c5d435c 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -545,6 +545,18 @@ let list = [1, 2, ..list] // still works let list = [1, ..list, 5] // compile error ``` +To store items of different types in a list, you need to create a custom type: + +```gleam +type Value { + Number(Int) + Text(String) + BinaryData(BitArray) +} + +let my_list = [BinaryData(<<"hello":utf8>>), Text("👋"), Number(5)] +``` + ### Dicts #### JavaScript From 94896f824b5d5adb3e54a060f4daac6d83efe239 Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sat, 27 Apr 2024 18:22:25 +0100 Subject: [PATCH 20/23] Add modules section --- cheatsheets/gleam-for-javascript-users.md | 56 +++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index 8c5d435c..4c3f895f 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -320,6 +320,62 @@ 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. +## Modules + +Just like in JavaScript, each Gleam file is a module, and values can only be +accessed if they are explicitly made public. Gleam doesn't have an equivalent of +JavaScript's `export default` -- all exports are named. + +### JavaScript + +In JavaScript, `export` marks values as public. Import paths are usually +relative to the current file. + +```javascript +//// my_library/tools/math.js +export function add(a, b) { + return a + b; +} + +//// my_library/other_file.js +import { add } from "./tools/math"; +import * as math from "./tools/math"; + +add(2, 2); +math.add(2, 2); +``` + +### Gleam + +In Gleam, `pub` marks values as public. Import paths are always absolute, +starting at the project root. + +```gleam +//// my_library/tools/math.gleam +pub type Color { + Red + Green + Blue +} + +pub fn add(a, b) { + a + b +} + +//// my_library/other_file.gleam +// You can import a whole module +import my_library/tools/math + +let pixel = math.Green +let sum = math.add(2, 2) + +// Or specify exactly what you want +import my_library/tools/math.{type Color, Red, add} + +let colors: Color = [Red, math.Green] +let sum = add(2, 2) +``` + ## Operators | Operator | JavaScript | Gleam | Notes | From 419d4ced19100033da9fc56702471c22b28a98e5 Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sat, 27 Apr 2024 18:26:58 +0100 Subject: [PATCH 21/23] Remove left-over items from TOC --- cheatsheets/gleam-for-javascript-users.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index 4c3f895f..33e32b11 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -6,7 +6,6 @@ subtitle: Hello JavaScripticians! - [Comments](#comments) - [Variables](#variables) - - [Match operator](#match-operator) - [Variables type annotations](#variables-type-annotations) - [Functions](#functions) - [Function capturing with `_`](#function-capturing-with-_) @@ -22,7 +21,6 @@ subtitle: Hello JavaScripticians! - [Strings](#strings) - [Tuples](#tuples) - [Lists](#lists) - - [Atoms](#atoms) - [Dicts](#dicts) - [Flow control](#flow-control) - [Case](#case) From 44aae0be637247d5d6cb19b0a3e40331fc63d9e8 Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sat, 27 Apr 2024 19:52:55 +0100 Subject: [PATCH 22/23] Add link to JavaScript cheatsheet --- cheatsheets/gleam-for-javascript-users.md | 4 +++- documentation.md | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index 33e32b11..864d8f6b 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -305,8 +305,10 @@ used at the call-site does not have to match the name used for the variable inside the function. ```gleam +import gleam/string + pub fn replace(inside string, each pattern, with replacement) { - // ... + string.replace(string, pattern, replacement) } ``` diff --git a/documentation.md b/documentation.md index 7617ee38..2327191e 100644 --- a/documentation.md +++ b/documentation.md @@ -47,6 +47,7 @@ layout: page - [Gleam for Elixir users](/cheatsheets/gleam-for-elixir-users) - [Gleam for Elm users](/cheatsheets/gleam-for-elm-users) - [Gleam for Erlang users](/cheatsheets/gleam-for-erlang-users) +- [Gleam for JavaScript users](/cheatsheets/gleam-for-javascript-users) - [Gleam for PHP users](/cheatsheets/gleam-for-php-users) - [Gleam for Python users](/cheatsheets/gleam-for-python-users) - [Gleam for Rust users](/cheatsheets/gleam-for-rust-users) From 269f89ac91ca01757bfd4e2a20e75ec0fa525164 Mon Sep 17 00:00:00 2001 From: Nino Annighoefer Date: Sat, 27 Apr 2024 21:34:51 +0100 Subject: [PATCH 23/23] Explain variable shadowing --- cheatsheets/gleam-for-javascript-users.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/cheatsheets/gleam-for-javascript-users.md b/cheatsheets/gleam-for-javascript-users.md index 864d8f6b..03d706e7 100644 --- a/cheatsheets/gleam-for-javascript-users.md +++ b/cheatsheets/gleam-for-javascript-users.md @@ -101,13 +101,20 @@ height = height + 100; // Error! #### Gleam -Gleam has the `let` keyword before each variable assignment. Variables can be -reassigned, but each assignment must start with the `let` keyword. +Gleam has the `let` keyword before each variable assignment. Variables can't be +mutated or reassigned. If a new variable has the same name as an existing +variable, the new definition _shadows_ the old one, but the old variable is not +overwritten: ```gleam +import gleam/io + let size = 50 +let print_it = fn() { io.debug(size) } let size = size + 100 let size = 1 +io.debug(size) // prints 1 +print_it() // prints 50 ``` ### Variables type annotations