SaturnineA Glonbook

Glon in 5 minutes

Loading the Glon runtime…

Glon is a small Rebol-family language that runs on a tiny frozen machine (S1), natively and as WebAssembly in the browser. This primer teaches enough Glon to read and change simple programs.

This primer is instructional. The normative rules are in GLON-ALPHA-LAWS.md; where the two differ, the laws win.

Every example here is real: the live primer runs each one through the actual Glon WebAssembly runtime, and the native test suite checks every result shown below. The result of an example is shown after =>: it is the value of the program's last expression. A result starting ** uncaught means the program was stopped by a raised SIN! that nothing caught.

Live, editable version: https://gchiu.github.io/rebol-substrate-experiment/shop/primer.html

1. Values and words

A program is a sequence of values. Numbers are integers. A word names a value; a set-word (a word with a trailing colon) gives it one.

Ctrl+Enter runs

Glon calls are prefix: the function comes first and takes a fixed number of arguments. There is no operator precedence and there are no parentheses; each function simply takes the next complete expressions it needs. + 1 * 2 3 reads as + 1 (* 2 3).

Ctrl+Enter runs

A word with a leading quote ('tea) is a word used as data, not looked up.

Ctrl+Enter runs

2. Blocks are data

Square brackets make a block. A block is just data (a list of values) until something evaluates it. do evaluates a block.

Ctrl+Enter runs

Ctrl+Enter runs

3. Functions

func [params] [body] makes a function. Calling it needs no parentheses or commas: the function takes as many following values as it has parameters.

Ctrl+Enter runs

Ctrl+Enter runs

Calls nest by arity: double double 5 is double (double 5).

Ctrl+Enter runs

4. Conditionals

either condition [then] [else] evaluates one of two blocks. Comparisons are prefix too. none and 0 are false; every other value is true (there are no true/false words; use 1 and 0).

Ctrl+Enter runs

Ctrl+Enter runs

5. CASE

case takes ONE block of pairs: a condition block followed by an action block. Conditions are tried in order; the first true one runs its action and case returns the action's result. [1] is a catch-all condition. With no match, case returns none. (case is ordinary Glon from case.glon, loaded as a library.)

Ctrl+Enter runs

6. Closures and lexical scope

A function remembers the context it was made in. A function returned from another function is a closure: it keeps its parameters alive.

Ctrl+Enter runs

A set-word inside a function updates the nearest existing binding of that word; if there is none, it creates a local of the current call.

Ctrl+Enter runs

The lexical fence. A plain block that refers to a function's locals depends on that one call. It may be used while the call is running, but it may not escape it. To take behaviour out of a call, make a closure.

Legal: the block [ + x 1 ] is evaluated inside the call that owns x.

Ctrl+Enter runs

Illegal: do [ [x] ] returns the inner block [x] out of f, but that block still refers to f's x. The runtime refuses, at the moment of escape, by raising a SIN! of type escape, id return. Its last field, shown here as <site>, is the block's internal lexical site id: an implementation number (the live page shows the real one).

Ctrl+Enter runs

The legal way to take x out is a closure (does makes a function with no parameters):

Ctrl+Enter runs

7. SIN!, raise and judge

A SIN! is a first-class value describing a failure: a type, an id and an argument. A SIN! is inert data until it is raised: you can store it, pass it and inspect it freely.

Ctrl+Enter runs

raise starts propagation: it abandons the current work and unwinds to the nearest judge. judge block runs the block; if something inside raises, judge returns the SIN! as ordinary inert data.

Ctrl+Enter runs

Inspect a SIN! with sin?, sin-type, sin-id and sin-arg:

Ctrl+Enter runs

After judge returns, execution simply continues:

Ctrl+Enter runs

With no judge, a raised SIN! stops the program:

Ctrl+Enter runs

Runtime checks raise SIN!s too. The lexical fence above can be judged like any other raise:

Ctrl+Enter runs

8. Strings

Text in double quotes is a STRING!. Strings are immutable: string operations return new strings and never change their inputs. They have qualified names: s/+ joins two strings, s/= compares their contents, s/length counts their bytes and s/print prints one. (For now s/+ is simply one word; a / inside a word is reserved for qualified names. A bare / is still division.)

Ctrl+Enter runs

s/+ built a new string; s itself is unchanged:

Ctrl+Enter runs

s/length counts stored bytes (Glon has no Unicode character semantics yet):

Ctrl+Enter runs

s/= compares contents. = is identity, so two separately built strings with the same text are s/= but not =:

Ctrl+Enter runs

Ctrl+Enter runs

s/print "hello" writes the string's bytes and a newline to the output (print prints integers only). Giving a string operation something that is not a string raises a SIN! of type type:

Ctrl+Enter runs

9. Tasks

Glon tasks are cooperative: spawn block creates a task, yield hands control to the next task, and run-tasks runs them until all finish. These words come from the task library shipped with the demos (demos/tuple-space.glon), loaded for the examples below. Two tasks interleave their digits:

Ctrl+Enter runs

A task body obeys the lexical fence: a block that depends on the spawning call is rejected with 'escape 'transport before the task is created.

Ctrl+Enter runs

10. Coming from Rebol or Red

Glon looks familiar, which is exactly why these differences matter:

In Rebol / RedIn Glon today
1 + 2 * 3 (infix)prefix only: + 1 * 2 3; comparisons too: > n 0
( ... ) groups an expressionno parentheses; fixed arity decides grouping
0 is true; true / false0 and none are false; no true / false words (use 1 / 0)
case [cond [action] ...], case/allcase [ [cond] [action] ... ]: conditions are blocks; no /all
foreach, each, while, repeat, loopno loop words; use recursion
switchnone; use case
type?none
try, attempt, error!, catch / throwSIN!, create-sin, raise, judge
an unset word is a catchable erroran unset word halts the run (a machine fail-stop, not a SIN!)
func set-words are global (Rebol); function collects locals (Red)a set-word updates the nearest existing binding, else makes a local
a bound block can travel anywherea block that uses a call's locals may not outlive that call; use a closure
[1] = [1] is true= is identity for blocks and strings (= [1] [1] is 0); str-eq compares strings
threads, portscooperative tasks: spawn, yield, run-tasks (library words)
print shows any valueprint shows integers only; s/print prints a string
append changes a string in placestrings are immutable: s/+ returns a new string

11. Next