Logo

0x3d.site

is designed for aggregating information and curating knowledge.

Hook

The [Hook](https://github.com/hook-lang/hook/) cheat sheet is a one-page reference sheet for the Hook programming language.
Category: Programming


Getting Started

Introduction

What does Hook look like?

fn factorial(n) {
  if (n == 0)
    return 1;
  return n * factorial(n - 1);
}

Hook features a modern syntax similar to C.

Hello, world!

println("Hello, World!");
// Hello, World!

The Hello, World! program in Hook.

Installing with Homebrew

brew tap hook-lang/hook
brew install hook
hook --help

The interpreter is available on Homebrew.

Installing on Windows {.col-span-2}

cd %tmp%
curl -sSLO https://raw.githubusercontent.com/hook-lang/hook/main/scripts/install.bat
install

This is how you can install it on Windows.

Types and Values

Basic Types

Nil Bool
Number String
Range Array
Record Closure

List of basic types.

Bool

let x = true;
let y = false;

Bool is a boolean type. So, it can be true or false.

Numbers

let x = 0;
let degree = 45; // integer number
let pi = 3.14; // floating-point number

Numbers can be integers or floating-point.

Strings

let empty = "";

let name = "John";

let message = 'Hello, "John"!';

Strings can be single or double-quoted.

Ranges

let range = 1..5;

println(range);
// 1..5

Ranges are a sequence of integers.

Arrays

let fruits = ["apple", "banana", "cherry"];

println(fruits);
// ["apple", "banana", "cherry"]

Arrays are a sequence of elements.

Records

let p = { x: 5, y: 10 };

println(p);
// {x: 5, y: 10}

Records maps fields to values.

The nil value

let x = nil;
var y;
println(x); // nil
println(y); // nil

nil is the absence of a value.

Falsy values

if (nil) "true" else "false";   // false
if (false) "true" else "false"; // false
if (true) "true" else "false";  // true
if (0) "true" else "false";     // true
if (1) "true" else "false";     // true
if ("") "true" else "false";    // true
if ([]) "true" else "false";    // true
if ({}) "true" else "false";    // true

Just nil and false are falsy.

Syntax

Comments

// This is a single-line comment.

// And this is
// a multi-line
// comment. ;)

Hook supports single-line comments only. Sorry!

Semi-colons {.col-span-2}

println(1) ; println(2) ; println(3) ;
println(4) ; println(5)
; println(6) ;
;                                      // error: unexpected token `;`

Semi-colons are required and empty statements are not allowed.

Blocks

{
  println("Hello");
  {
    println("World");
  }
}

Blocks are used to define a scope.

Reserved words

as break continue do
else false fn for
from if import in
inout let loop match
nil return struct trait
true var while

There are few reserved words.

Identifiers

var lowercase;
var CAPS_LOCK;
var camelCase;
var PascalCase;
var snake_case;
var _123;

Identifiers are case-sensitive.

Variables

Variables

var x; // x contains nil
x = 5; // now, x contains a number
x = "foo"; // a string

println(x);

Values have types, but variables don't.

Immutable variables {.col-span-2}

let x = 5;

x = 10; // error: cannot assign to immutable variable `x`

let y; // error: unexpected token `;`

Immutable variables must be initialized when declared.

Scopes {.col-span-2}

let x = 5;
{
  let y = 15;
  println(x); // 10
  println(y); // 15
}
println(x); // 5
println(y); // error: variable `y` is used but not defined

When a heap-allocated variable goes out of scope, it is automatically deallocated.

Shadowing

let x = 5;
{
  let x = 10; // shadows the outer `x`
  println(x); // 10
}
println(x); // 5

Variables can be shadowed.

Operators and Expressions

Arithmetic

println(5 + 10); // 15
println(5 - 10); // -5
println(5 * 10); // 50
println(5 / 10); // 0.5
println(5 % 10); // 5
println(-5); // -5

The basic arithmetic operators.

Comparison

println(5 == 10); // false
println(5 != 10); // true
println(5 < 10); // true
println(5 > 10); // false
println(5 <= 10); // true
println(5 >= 10); // false

The comparison operators.

Logical

println(true && false); // false
println(true || false); // true
println(!true); // false

The logical operators.

Bitwise and shift

println(5 & 10); // 0
println(5 | 10); // 15
println(5 ^ 10); // 15
println(~5); // -6
println(5 << 1); // 10
println(5 >> 1); // 2

The bitwise and shift operators.

Assignments

var x = 5; // 5
x += 10; // 15
x -= 10; // 5
x *= 10; // 50
x /= 10; // 5
x %= 10; // 5
x &= 10; // 0
x |= 10; // 10
x ^= 5; // 15
x <<= 5; // 480
x >>= 5; // 15
x++; // 16
x--; // 15

The assignment operators.

Teh ternary operator

let x = 5;
let y = if (x > 5) 10 else 20;

println(y);
// 20

In Hook, the ternary operator is if else.

Branching

If

let x = 10;

if (x > 5) {
  println("x is greater than 5");
}
// x is greater than 5

The if statement.

If else

let x = 11;

if (x == 5) {
  println("x is 5");
} else if (x == 10) {
  println("x is 10");
} else {
  println("x is neither 5 nor 10");
}
// x is neither 5 nor 10

The if else statement.

Match

let x = 5;

match (x) {
  1 => println("one");
  2 => println("two");
  3 => println("three");
  _ => println("other");
}
// other

The match statement.

Looping

While

var x = 0;

while (x < 5) {
  print(x);
  x += 1;
}
// 01234

The while loop.

Do while

var x = 0;

do {
  print(x);
  x += 1;
} while (x < 5);
// 01234

The do while loop.

For

for (var i = 0; i < 5; i++) {
  print(i);
}
// 01234

The classic for loop.

Loop

loop {
  println("Press Ctrl+C to stop");
}

The unconditional loop.

Break

var i = 0;
loop {
  if (i == 5) break;

  print(i);
  i += 1;
}
// 01234

Use break to exit a loop.

Continue

var i = 0;
loop {
  i += 1;
  if (i % 2 == 0) continue;

  print(i);

if (i == 5) break;
}
// 135

Use continue to skip the rest of the loop body.

Strings

Indexing a string

let s = "Hello";

println(s[0]); // H
println(s[1]); // e
println(s[4]); // o

Indexing a string returns a 1-character string.

Slicing a string

let s = "Hello, World!";

println(s[0..5]);        // Hello,
println(s[7..12]);       // World!

Pass a range to slice a string.

Concatening strings

let greeting = "Hi" + " there!";

println(greeting);
// Hi there!

Use the + operator to concatenate strings.

Arrays

Indexing an array

let a = [1, 2, 3];

println(a[0]); // 1
println(a[1]); // 2
println(a[2]); // 3

Indexing an array returns an element.

Slicing an array

let a = [1, 2, 3, 4];

println(a[0..2]);            // [1, 2, 3]
println(a[1..3]);            // [2, 3, 4]
println(a[2 .. len(a) - 1]); // [3, 4]

Arrays are zero-indexed.

Appending an element

var a = [1, 2];

a[] = 3;

println(a);
// [1, 2, 3]

Arrays are mutable. Use [] to append an element.

Element assignment

var a = [1, 2, 3];

a[0] = 4;

println(a);
// [4, 2, 3]

Update an element in an array.

Concatening arrays

let a = [1, 2];
let b = [3];
let c = a + b;

println(c);
// [1, 2, 3]

Use the + operator to concatenate arrays.

Subtracting arrays

let a = [1, 2, 2, 3];
let b = [2];
let c = a - b;

println(c);
// [1, 3]

Get the difference between two arrays.

Functions and Closures

Function declaration

fn sum(a, b) {
  return a + b;
}

println(sum(5, 10));
// 15

Functions are first-class citizens.

Function call

fn greet(name) {
  println("Hi, " + name + "!");
}

greet("John", "Doe");
// Hi, John!

The number of arguments is adjusted.

Anonymous functions

let sum = |a, b| {
  return a + b;
};

println(sum(5, 10));
// 15

Anonymous functions are also supported.

Closures

let pi = 3.14;
fn area(r) {
  return pi * r * r;
}

println(area(5));
// 78.5

Closures in Hook capture values only.

Higher-order functions

fn apply(f, x) {
  return f(x);
}

fn double(x) {
  return x * 2;
}

println(apply(double, 5));
// 10

Functions can be passed as arguments or returned.

Syntax sugar for functions

fn factorial(n) =>
  if (n == 0) 1
  else n * factorial(n - 1);

println(factorial(5));
// 120

Use => when the body is a single expression.

Recursion

fn fib(n) {
  if (n < 2)
    return n;
  return fib(n - 1) + fib(n - 2);
}

println(fib(10));
// 55

Recursion is supported.

Built-in functions

println(type(5));
// number
println("1" + to_string(2));
// 12
println(len("foo"));
// 3

There are many built-in functions.

More built-in functions

print println type
is_nil is_bool to_number
to_string hex len
exit assert panic

See: Built-in Functions

Structs

Structs

struct Point {
  x, y
}
let p = Point { 5, 10 };

println(p);
// {x: 5, y: 10}

A struct is a prototype for a record.

Accessing fields

println(p.x); // 5
println(p.y); // 10

Use . to access a field in a record.

Field assignment

p.x = 10;
p.y = 20;

println(p);
// {x: 10, y: 20}

Update a value of a field in a record.

Destructuring

Destructuring an array

let a = [1, 2];
let [x, y] = a;

println(x); // 1
println(y); // 2

Varuables are declared and assigned.

Destructuring a record

let p = { x: 5, y: 10 };
let { x } = p;

println(x);
// 5

Use {} to destructure a record.

Placeholder

let a = [1, 2];
let [x] = a;
let [_, y] = a;

println(x); // 1
println(y); // 2

Use _ skip leading or middle elements.

Modularity

Importing a module

import math;
println(math.sqrt(25));
// 5

Use import to bring a module into scope.

Exporting symbols

// my_module.hk
fn useful_fn() {
  return "Nothing";
}

return { useful: useful_fn };

Return a record with the symbols to export.

Importing local modules

import "./my_module.hk" as my;
println(my.useful());
// Nothing

Specify the path to the local module.

Selective import

import { pow, sqrt } from math;

let [ b, c ] = [ 4, 3 ];
let a = sqrt(pow(b, 2) + pow(c, 2));

println(a);
// 5

Use {} to import specific symbols.

Core modules

math os io numbers
strings arrays utf8 hashing
encoding socket json lists

See: Core Modules

Extension modules

bigint crypto curl fastcgi
geohash leveldb mysql redis
regex sqlite uuid zeromq

This is a list of extension modules.

io module

import { stderr, writeln } from io;

writeln(stderr, "Something went wrong");
// Something went wrong

Printing to stderr using io module.

hashing module

import hashing as h;
let d = h.sha256("Hello, world!");

println(hex(d));
// 315f5bdb76d078c43b8ac0064e4a...

hashing module provides hash functions.

json module

import json;
let j = '{"x": 1, "y": 2}';
let p = json.decode(j);

println(p.x); // 1

let k = json.encode(p);
println(type(k)); // string

Use json module for working with JSON.

Error Handling

Errors {.col-span-2}

println(to_int("foo"));

// runtime error: type error: argument #1 is not a convertible string
//   at to_int() in <native>
//   at main() in example.hk:1

Hook uses panic mode for error handling. When an error occurs, the interpreter stops.

Syntax error

println("Hello, World!");

// syntax error: unexpected end of file
//   at main() in example.hk:1,25

Hook has a strict syntax.

Panic

panic("Something went wrong");

// panic: Something went wrong
//   at main() in example.hk:1

Use the panic built-in function to raise an error.

Assert {.col-span-2}

assert(5 > 10, "5 is not greater than 10");

// assert: 5 is not greater than 10
//   at main() in example.hk:1

Use the assert built-in function to check a condition.

Returning errors {.col-span-2}

fn divide(a, b) {
  if (b == 0)
    return [nil, "division by zero"];
  return a / b;
}

if (let [ok, err] = divide(5, 0); ok) {
  println(ok);
} else {
  println(err);
}
// division by zero

Use a pair to return a value and an error.

Passing errors

if (let [ok, err] = divide(5, 0); err) {
  return [nil, err];
}

Pass an error without handling it.

Bookmark This Page Now!