Hoot 0.8.0 released!

Dave Thompson —

We are excited to announce the release of Hoot 0.8.0! Hoot is a Scheme to WebAssembly compiler backend for Guile, as well as a general purpose WebAssembly toolchain. In other words, Scheme in the browser!

This release contains new features and bug fixes and since the 0.7.0 release back in October.

New features

  • New (hoot repl) module. At long last, there is now a built-in read-eval-print loop implementation! Previous releases added a macro expander, a Scheme interpreter, and a runtime module system, but now it’s possible to do live hacking from a Hoot program inside a WebAssembly runtime!

    • To use the REPL, compile your Wasm binary with the necessary debug flag during development: guild compile-wasm -g1. This will include the runtime module system in the resulting binary. Expect compilation time and binary size to increase significantly. The trade-off is that a live hacking workflow will make recompilations fewer and farther between.

  • While not shipping in Hoot directly, initial support for using the Hoot REPL from Emacs has been added in the new geiser-hoot extension. We have submitted geiser-hoot for inclusion in MELPA and Guix so it will be easy to install in the very near future.

  • Enhanced (hoot web-server) module. To support the use of REPLs running within a web browser tab, the most common development use case, the web server doubles as a REPL server, proxying TCP traffic from REPL clients (more about that below) over a WebSocket to the connected browser tab.

    • These enhancements introduce two new, optional depedencies to Hoot: Fibers and guile-websocket. If either of these dependencies are not present at build time, the (hoot web-server) module will not be built.

    • The web server can now be extended with a user-supplied request router. An example of this can be found in our hoot-slides repository.

  • New (hoot web-repl) module. This module can be imported and compiled into the Wasm binary so that it can act as a REPL server. This is complicated by the fact that a browser client cannot act as a server, it is strictly a client. Instead, it connects to the aforementioned (hoot web-server) which acts as a proxy for all connected REPL clients.

  • New hoot command-line tool. This command will be used as a place to collect handy Hoot development tools. So far, there are two subcommands:

    • hoot repl: Open a REPL running in Node. Useful for quickly trying out basic Scheme expressions in Hoot without having to compile a standalone WebAssembly program.

    • hoot server: Conveniently launch the development web server in (hoot web-server).

  • New (web request) and (web response) modules that export a sliver of the API defined in Guile’s modules of the same names.

  • New (web socket) module that provides a input/output interface to WebSocket client connections. Mimicks the module of the same name in guile-websocket.

  • Added customizable module loader interface via new current-module-loader parameter. Two concrete loaders are provided: By default, modules are loaded from the file system by searching a load path. This is useful when running in a non-browser runtime such as NodeJS. When run-web-repl in (web repl) is used, connected REPLs are configured to use an HTTP-based loader. This loader makes HTTP requests to a special endpoint on the development web server to fetch source code.

    • Note that modules loaded at runtime are loaded from source and then interpreted. Unlike Guile, where modules are automatically compiled to bytecode, Hoot cannot compile individual modules to Wasm (which would require compiling the compiler to Wasm which is an interesting future possibility).

Community highlights

Check out this chiptune tracker made with Hoot by Vivianne Langdon!

Additionally, check out Wastrel, a Wasm GC to C compiler developed by Andy Wingo. Wastrel notably uses Hoot’s Wasm toolchain. A Wasm program compiled with Wastrel runs faster than the same program on NodeJS!

Documentation changes

  • Updated Installation chapter to mention new optional dependencies.

  • Added Modules and REPL sections to the Scheme reference chapter.

  • Added Development chapter.

  • Update Status section to remove mention of missing R7RS support that we have now.

  • Removed docs for obsolete --emit-names flag

  • Add documentation for -g flag to guild compile-wasm.

  • Fixed example in the JavaScript reflection section that was using the obsolete load_main signature.

Toolchain changes

  • Split Wasm validation out of (wasm vm) and into new (wasm validation) module.

  • Keep data computed within the validation pass in <validated-wasm> records so that data can be used during instantiation rather than redundantly recomputing it.

  • Added explicit support for representing a “canonicalization”: a world in which structurally equal types are equal.

  • (wasm vm) types <wasm-func>, <wasm-struct>, <wasm-array> now refer to their types by index into a canonicalized set.

  • Added untagged <wasm-array> backing stores to (wasm vm) for all simple scalar numeric types, including i8 and i16 packed types.

  • Modified (wasm vm) to look up named heap type references in the instance’s canonicalization.

  • Added bytevector->wasm-array, wasm-array->bytevector to (wasm vm).

  • Added support for some of the “none” bottom types.

  • Packed array data is now stored signed, wrapped from i32 when set, and only unwrapped to unsigned in get_u functions.

  • Added string.from_code_point and string.concat lowerings in (wasm lower-stringrefs).

  • Renamed outdated extern.internalize and extern.externalize to their current names, any.convert_extern and extern.convert_any.

  • Added new has-wasm-header? procedure to (wasm parse).

  • Parse core reference types to <ref-type> records rather than symbol abbreviations in (wasm parse).

Miscellaneous changes

  • Modified schedule-task in (fibers scheduler) (which is implemented using inline Wasm on the target) to be a no-op when called at expansion time on the host i.e. used at the module top-level or from a procedural macro.

  • Added support for vector and call-with-values primitives to (hoot primitives) module so they can be used in interpreted code.

  • truncate is now exported from (guile).

  • Allow exports to clobber each other in module-declare! to support live hacking of modules where define-module forms are often re-evaluated many times.

  • Extracted JS Uint8Array bindings from internals of (fibers streams) to new (hoot typed-arrays) module.

  • Implement subset of Guile’s procedural module API for hackable programs (i.e. programs that are built with runtime module support).

  • Added (hoot config) target-side module for accessing certain build-time constants (currently just the Hoot version string).

  • Extracted (hoot library) module from (hoot library-group) so that the library parser can be used on the target for live hacking purposes.

  • Added define-module implementation to (guile) that simply throws an error if used during compilation. A separate implementation is installed for use by the interpreter in hackable programs.

  • Added #:replace? argument to module-export! to allow replacement of exports for live hacking purposes.

  • Exported module-root from (hoot modules).

  • Added module-imported-modules procedure to (hoot modules).

  • Changed file I/O host functions to return null when a file cannot be opened so a Scheme exception that can be handled by user code rather than a host exception that cannot.

  • Extracted contents of (scheme file) to new (hoot file) module for use in internal code such as the implementation of the file system module loader in (hoot hackable).

  • Moved implementation of string-join, string-concatenate, string-prefix?, and string-prefix-ci? from (guile) to (hoot strings).

  • Moved case-insensitive string procedures from (scheme char) to (hoot strings).

  • Added string-drop to (hoot strings).

  • Added every and fold-right procedures to (hoot lists).

  • Moved implementation of and-map and or-map from (guile) to (hoot lists).

  • Added symbol-append to (hoot symbols).

  • Added less verbose custom printer for <module> record type.

  • Switched from positional to keyword arguments for make-soft-port in (hoot ports).

  • Added list-index to (guile).

Bug fixes

  • Fixed format-exception not writing all of its output to the current error port.

  • Fix eof-object export in (ice-9 binary-ports).

  • Fixed off-by-one error for procedures with rest args in (hoot eval).

  • Fixed min/max to only accept real numbers, handle NaNs, and normalize exact zeroes.

  • Fixed continuation composition leaving an unwind continuation on the stack.

  • Fixed prompt unwinding in certain join continuation situations.

  • Fixed compilation of unwind primcalls at join points.

  • Fixed runtime module system ignoring replacement bindings in Guile modules.

Browser compatibility

  • Compatible with Safari 26 or later.

  • Compatible with Firefox 121 or later.

  • Compatible with Chrome 119 or later.

Get Hoot

Hoot is available in GNU Guix:

$ guix pull
$ guix install guile guile-hoot

Also, Hoot is now available in Debian, though it will take awhile for this release to make it there.

Otherwise, Hoot can be built from source via our release tarball. See the Hoot homepage for a download link and GPG signature.

Documentation for Hoot 0.8.0, including build instructions, can be found here.

Get in touch

For bug reports, pull requests, or just to follow along with development, check out the Hoot project on Codeberg.

If you build something cool with Hoot, let us know on our community forum!

Thanks to our supporters

Your support makes our work possible! If you like what we do, please consider becoming a Spritely supporter today!

Diamond tier

  • Aeva Palecek
  • David Anderson
  • Holmes Wilson
  • Lassi Kiuru

Gold tier

  • Alex Sassmannshausen
  • Juan Lizarraga Cubillos

Silver tier

  • Austin Robinson
  • Brit Butler
  • Charlie McMackin
  • Dan Connolly
  • Danny OBrien
  • Deb Nicholson
  • Eric Bavier
  • Eric Schultz
  • Evangelo Stavro Prodromou
  • Evgeni Ku
  • Glenn Thompson
  • James Luke
  • Jonathan Frederickson
  • Jonathan Wright
  • Joshua Simmons
  • Justin Sheehy
  • Matt Panhans
  • Michel Lind
  • Mike Ledoux
  • Nathan TeBlunthuis
  • Nia Bickford
  • Noah Beasley
  • Steve Sprang
  • Travis Smith
  • Travis Vachon

Bronze tier

  • Alan Zimmerman
  • Aria Stewart
  • BJ Bolender
  • Ben Hamill
  • Benjamin Grimm-Lebsanft
  • Brooke Vibber
  • Brooklyn Zelenka
  • Carl A
  • Crazypedia No
  • François Joulaud
  • Gerome Bochmann
  • Grant Gould
  • Gregory Buhtz
  • Ivan Sagalaev
  • James Smith
  • Jason Wodicka
  • Jeff Forcier
  • Marty McGuire
  • Mason DeVries
  • Michael Orbinpost
  • Neil Brudnak
  • Nelson Pavlosky
  • Philipp Nassua
  • Robin Heggelund Hansen
  • Rodion Goritskov
  • Ron Welch
  • Stefan Magdalinski
  • Stephen Herrick
  • Steven De Herdt
  • Tamara Schmitz
  • Thomas Talbot
  • William Murphy
  • a b
  • r g
  • terra tauri

Until next time, happy hooting! 🦉