Beta Release 0.1.12

This intermediate release brings quality of life improvements to the pipe operator, small syntax refinements, and small improvements to WebAssembly module generation.

Pipe improvements

The pipe operator (|>) saw a number of semantic improvements in this release.

You can now pipe into a method call. This has the semantics you would expect: the implicit argument from the method call becomes the first argument, and the piped argument becomes the second argument. In other words,
x |> y->z() === y.z(&y, x).

Here is one example where this could be useful.

main :: () {
    my_arr := make([..] i32)

    |> iter.take(10)
    |> => x * 2)
    |> my_arr->concat()     // Piping directly into this method call


You can also now pipe into a try operator (?). This also has the semantics you would expect: the try operator is left on the outside of the call and the piped argument is placed normally in the call. In other words,
x |> y()? === y(x)?.

This feature enables an interesting pattern of computation that allows for chaining of fallible operations, letting you focus on the "happy path" of your code.

do_something :: x => {
    return x
        |> fallible_operation_1()?
        |> fallible_operation_2()?
        |> fallible_operation_3()

Phasing out of #auto

In the on-going effort to simply Onyx, the #auto directive is being phased out in favor of _.

As a reminder, #auto was used when you don't want to spell out the type explicitly, but have the type solved by the compiler. This was allowed in two places: as a return type, and as a local variable type.

// Old way
foo :: () -> #auto {
    x: #auto
    x = "test"
    return x

Now, the (arguably) ugly #auto directive is no longer necessary.

// New way
foo :: () -> _ {
    x: _
    x = "test"
    return x

Like many other things, #auto still works in 0.1.12, but will be removed in a future version.

Simplified onyx.js

The JavaScript file generated as a part of compiling with -r js is no longer an ES6 module. While ES6 modules are generally the standard nowadays, there are still some cases where having an ES6 module is a problem. To make Onyx easier to use in a variety of JS environment, ES6 modules were ditched in this release. You should be able to load the JS file in a normal <script> tag on the browser, or using require in something like Node JS.

This is now what you need to run Onyx in a browser, for example.

<script src="/out.wasm.js"></script>
    Onyx.load("/out.wasm").then(program => program.start())

WebAssmebly name section

When looking at a WebAssembly module, whether it be through a inspection tool like wasm-tools or wasm-objdump, or in the Developer Tools of your favorite browser, having names on functions can be very useful. While there is not a great standard for debug information in WebAssembly as of today (though work is being done by the community), at least having function names can help you figure out from a stack trace where your program is currently executing.

Onyx now supports emitting the special name table that is understood by all WebAssembly tooling. Currently, only function names are generated, as they are the most useful, but local names may be added in the future. To actually generate the name table, you need to pass the --generate-name-section flag to onyx build. This is not done by default, as it does inflate the binary size.


To update to the newest version of Onyx simply use the same install script found on the homepage. It will automatically detect your previous install and will override it with the new version.

$ sh <(curl -sSfL)

You can also run onyx self-upgrade if you are on MacOS or Linux!

Happy programming!

Full Changelog


  • Ability to pipe into a method call.
    • x |> y->z() === y->z(x)
  • Ability to pipe into a try operator.
    • x |> y()? === y(x)?
  • Ability to use _ where #auto is used.
    • This will be come the default soon and #auto will be removed.
  • return #from_proc to return all the way from the procedure.
  • Variant of new that accepts an r-value and places it in the heap.
  • Builtin panic procedure that is equivalent to assert(false, ...)
  • Format parameter "a" that unpacks an any and formats its internal value.
  • --generate-name-section CLI flag


  • Optional.try as it is incompatible with new semantics of ?.


  • str.as_str is now preferred over string.as_str
  • is now preferred over
  • str.to_cstr_on_stack is now preferred over string.to_cstr_on_stack
  • str.join is now preferred over string.join
  • Implementation of ? for Optional and Result to return from the enclosing procedure.


  • Fixed WASI compilation due to syntax issue.
  • Fixed WASI platform __file_open implementation for wasmtime.
  • Weird edge case when using multiple placeholder arguments in a quick procedure.
© 2020-2024 Brendan Hansen