Skip to content

Editing this Documentation

Guides lead a user through a specific task they want to accomplish, often with a sequence of steps. Writing a good guide requires thinking about what your users are trying to do.

Further reading: how-to guides in the Diátaxis framework

Reference pages are ideal for outlining how things work in terse and clear terms. Less concerned with telling a story or addressing a specific use case, they should give a comprehensive outline of what you’re documenting.

Further reading: reference pages in the Diátaxis framework

public fun main() {
print("Hello, World!")
}
src/main.hylo
public fun main() {
print("Hello, World!")
}

No frame:

echo "Command without frame"

With frame (default):

Terminal window
echo "This terminal frame has no title"

With title:

PowerShell terminal example
Write-Output "This one has a title!"

No wrapping (default):

Terminal window
cmake -D LLVM_DIR=<LLVM>/lib/cmake/llvm -D CMAKE_BUILD_TYPE=<build-type> -D BUILD_TESTING=1 -G Ninja -S . -B .build

Wrap:

Terminal window
cmake -D LLVM_DIR=<LLVM>/lib/cmake/llvm -D CMAKE_BUILD_TYPE=<build-type> -D BUILD_TESTING=1 -G Ninja -S . -B .build

Hanging indent:

Terminal window
cmake -D LLVM_DIR=<LLVM>/lib/cmake/llvm -D CMAKE_BUILD_TYPE=<build-type> -D BUILD_TESTING=1 -G Ninja -S . -B .build
module struct SpawnFrame<E: Movable & Deinitializable>: Deinitializable {
/// The base frame object needed by the underlying implementation.
private var base_frame: SpawnFrameBase
/// What needs to be called to produce the value in the future.
private var f: [E]() -> Int
/// The result of the computation.
private var r: Optional<Int>
/// Initializes `self` with `f`, and spawns the computation.
module init(_ f: sink [E]() -> Int) {
&self.base_frame = .new()
&self.f = f
&self.r = .none()
let local_f = fun (_ frame: inout SpawnFrameBase) -> Void {
var this = PointerToMutable<Self>(type_punning: mutable_pointer[to: &frame])
&this.unsafe[].r = this.unsafe[].f() as _
}
concore2full_spawn2(&self.base_frame, local_f)
}
/// Awaits the result of the computation.
///
/// - Note: May return on a different OS thread than the one that called this.
fun await() inout -> Int {
concore2full_await(self.base_frame)
if let r: Int = self.r {
let copy = r.copy()
&self.r = .none()
return copy
} else {
fatal_error()
}
}
/// Allocate an object of `Self` on the heap and initialize it with `f`.
internal static fun allocate(_ f: sink [E]() -> Int) -> PointerToMutable<Self> {
let p: PointerToMutable<Self> = .allocate(count: 1)
Self.`init`(self: &p.unsafe[], f)
return p
}
}
public fun main() {
let gravity = 9.81
&gravity = 11.2error: cannot assign, `gravity` is a `let` binding
}
  • DirectorySources
    • DirectoryHello
      • Hello.hylo
    • DirectoryGreetings
      • Greetings.hylo

Wrap a code block in <Playground> to let readers run it in their browser, edit it, and open it in the full-screen playground. The code block renders as any other, highlights and all; the compiler, compiled to WebAssembly (the npm package @hylo-lang/hylo-wasm), is only downloaded when a reader first runs a snippet. That is about 15 MB compressed, once, which the browser then caches.

Only make a snippet runnable if the compiler can run it today. The expect attribute says what it does, and the site’s tests check every snippet still does it; the site does not build if a snippet has none, or if it misuses an attribute.

The import path is relative to the page: from a page in src/content/docs/docs/<section>/, the component is four directories up.

import Playground from '../../../../components/playground/Playground.astro';

Every attribute of <Playground> and every marker of its code fences, with an example. Each example shows its MDX and, under Preview, what it renders, which runs.

Attribute Values Default
expect exit N, trap, error, ok required
outputs result, diagnostics, raw-ir, ir, llvm, assembly result
focus names of functions every function
optimization {0} to {3} {0}
stopAfter parsing, scoping, typing, lowering runs the program
standardLibrary {true}, {false} {true}
editable {true}, {false} {true}
name a name, unique on the page none
continues the name of an earlier snippet of the page none
contributes {true}, {false} {true}
Fence marker Effect
hidden compiled, not shown
title="…" the file, shown as the caption
file="…" the file, not shown
Several shown fences tabs, one per file
Expressive Code’s markers as in any code block

What the snippet does, which the site’s tests check: exit N (it runs and exits with status N), trap (it runs and traps), error (it does not compile), or ok (it compiles, and runs to completion if it is a program). Required.

<Playground expect="exit 42">
```hylo
public fun main() -> Int32 {
var x = 40
&x = x + 2
return if x == 42 { 42 } else { 1 }
}
```
</Playground>

A snippet that does not compile shows its diagnostics; clicking one takes the reader to it.

<Playground expect="error">
```hylo
public fun main() -> Int32 {
40 + 2 // Integer literals are `Int` unless something says otherwise.
}
```
</Playground>
<Playground expect="trap">
```hylo
public fun main() -> Int32 {
let divisor: Int32 = 0
return (1 as Int32) / divisor
}
```
</Playground>

What to show once the code has run, as tabs, in this order: result (the exit status, what the program printed, and the diagnostics), diagnostics, raw-ir (Hylo IR before the mandatory transformations), ir (Hylo IR), llvm (LLVM IR) and assembly (WebAssembly).

<Playground outputs="result diagnostics ir llvm assembly" expect="exit 7">
```hylo
public fun main() -> Int32 { 7 }
```
</Playground>

The functions to show in Hylo IR, by name, rather than all of them: main shows main, factorial shows factorial(n:), and Int32.infix+ shows that operator.

<Playground outputs="ir" focus="factorial" expect="exit 120">
```hylo
fun factorial(n: sink Int32) -> Int32 {
var m: Int32 = 1
while n > (0 as Int32) {
&m = m * n
&n = n - (1 as Int32)
}
return m
}
public fun main() -> Int32 { factorial(5 as Int32) }
```
</Playground>

LLVM’s optimization level, from {0} to {3}. Here the whole program folds to a constant.

<Playground outputs="result llvm" optimization={2} expect="exit 120">
```hylo
fun factorial(n: sink Int32) -> Int32 {
var m: Int32 = 1
while n > (0 as Int32) {
&m = m * n
&n = n - (1 as Int32)
}
return m
}
public fun main() -> Int32 { factorial(5 as Int32) }
```
</Playground>

The phase after which compilation stops, for code that is not a program: typing checks it, lowering also produces its Hylo IR. The button says Check rather than Run.

<Playground stopAfter="lowering" outputs="result ir" focus="sum" expect="ok">
```hylo
struct Pair is Deinitializable {
public memberwise init
public var a: Int32
public var b: Int32
}
fun sum(_ p: Pair) -> Int32 { p.a + p.b }
```
</Playground>

{false} compiles the code without the standard library.

<Playground standardLibrary={false} stopAfter="typing" expect="ok">
```hylo
trait Shape {}
struct Point is Shape {}
fun identity<T>(_ x: sink T) -> T { x }
```
</Playground>

{false} keeps the reader from editing the snippet; it still runs.

<Playground editable={false} expect="exit 3">
```hylo
public fun main() -> Int32 { 3 }
```
</Playground>

A snippet named with name can be continued by any snippet after it on the same page, with continues: the later one starts from all the files of the earlier one, hidden code included, so a chain of snippets builds a program up as the prose explains it. Nothing of the snippets after one is compiled with it, and “Open in the playground” opens the program as it stands there.

<Playground name="ref-point" stopAfter="typing" expect="ok">
```hylo
public struct Point is Deinitializable {
public memberwise init
public var x: Int32
public var y: Int32
}
```
</Playground>
<Playground continues="ref-point" expect="exit 3">
```hylo
public fun main() -> Int32 {
let p = Point(x: 1 as Int32, y: 2 as Int32)
return p.x + p.y
}
```
</Playground>

{false} leaves the snippet’s own code out of the snippets continuing it, which start from what it continues instead: a mistake or a digression does not end up in the program.

<Playground name="ref-mistake" continues="ref-point" contributes={false} expect="error">
```hylo
public fun main() -> Int32 {
Point(x: 1, y: 2).x
}
```
</Playground>
<Playground continues="ref-mistake" expect="exit 1">
```hylo
public fun main() -> Int32 {
Point(x: 1 as Int32, y: 2 as Int32).x
}
```
</Playground>

A fence marked hidden is compiled with the snippet but not shown. Each fence adds its code at the end of its file, in the order written, so a hidden fence may open what a shown one closes. Readers edit only the code they see.

<Playground expect="exit 42">
```hylo hidden
public fun main() -> Int32 {
```
```hylo
var x: Int32 = 40
&x = x + (2 as Int32)
return x
```
```hylo hidden
}
```
</Playground>

The file the fence goes into, which the code block shows as its caption. A fence naming no file goes into the snippet’s own file: main.hylo, or main2.hylo and so on if the program already has a file of that name. A later snippet continues a file by naming it. Diagnostics name the files.

<Playground name="ref-shapes" stopAfter="typing" expect="ok">
```hylo title="shape.hylo"
trait Shape {
fun area() -> Int32
}
```
</Playground>
<Playground continues="ref-shapes" stopAfter="typing" expect="ok">
```hylo title="shape.hylo"
fun twice<T is Shape>(s: T) -> Int32 { s.area() + s.area() }
```
</Playground>

The file the fence goes into, without showing its name; a title is then any caption.

<Playground expect="exit 6">
```hylo hidden file="rect.hylo"
struct Rect is Deinitializable {
public memberwise init
public var w: Int32
public var h: Int32
}
```
```hylo file="main.hylo" title="Using a type from another file"
public fun main() -> Int32 {
let r = Rect(w: 2 as Int32, h: 3 as Int32)
return r.w * r.h
}
```
</Playground>

A snippet shows at most one fence of each file, and shows the fences of several files as tabs, named after the files. Editing it gives each its own editor, and a diagnostic takes the reader to the right tab.

<Playground expect="exit 10">
```hylo title="main.hylo"
public fun main() -> Int32 { triangle(4 as Int32) }
```
```hylo title="triangle.hylo"
/// Returns 1 + 2 + … + n.
fun triangle(n: Int32) -> Int32 {
var total: Int32 = 0
var i: Int32 = 1
while i <= n {
&total = total + i
&i = i + (1 as Int32)
}
return total
}
```
</Playground>

The markers of every code block apply to the fences shown, such as highlighting lines ({7}) and folding them away until the reader unfolds them (collapse={1-3}).

<Playground expect="exit 120">
```hylo {7} collapse={1-3}
fun factorial(n: sink Int32) -> Int32 {
var m: Int32 = 1
while n > (0 as Int32) {
&m = m * n
&n = n - (1 as Int32)
}
return m
}
public fun main() -> Int32 { factorial(5 as Int32) }
```
</Playground>

The Hylo IR and the WebAssembly assembly LLVM prints have code fence languages of their own, hylo-ir and wasm-asm:

fun main(set %p0: Int32) {
%b0:
%r0 = subfield %p0 at 0 as i32
%r1 = access [set] %r0
%r2 = store i32 42 to %r1
%r3 = end %r1
%r4 = return
}