Hare 0.24.2 released July 14, 2024 by Drew DeVault
I am pleased to announce the release of Hare 0.24.2 🎉. This release comes with new language features, improvements to the standard library, and a healthy dose of breaking changes. Let’s go through the highlights together.
Hare 0.24.2
- Release notes
- Hare 0.24.2
- Download
- compiler harec-0.24.2.tar.gz • stdlib hare-0.24.2.tar.gz
Hare 0.24.2 is compatible with version 1.2 of qbe.
New here? Hare is a systems programming language designed to be simple and robust, using a static type system, manual memory management, and a minimal runtime. You can learn about it here.
Release highlights
The headline features of Hare 0.24.2 are:
- NetBSD support
- for-each loops
- Optional function parameters
- Improved performance for bufio and related APIs
- Revised and improved APIs for unix::
- Multiple alternation support for regex::
- Support for shared memory and memfds on supported platforms
- New cryptography APIs:
- crypto::ec
- crypto::ecdh
- crypto::ecdsa
NetBSD support
New to Hare’s list of supported platforms is NetBSD, thanks to the hard work of Mallory Adams – who is now counted among the upstream maintainers of Hare to ensure this target remains in good working order for the foreseeable future. This expands Hare’s platform support to include all three major BSD derivatives – NetBSD, OpenBSD, and FreeBSD – and Linux.
for-each loops
OpenBSD maintainer Lorenz championed the addition of for-each loops to Hare over the past several months, and it’s included in 0.24.2. You can read about it in depth in Lorenz’s blog post on the subject. Here are some brief examples.
First, when iterating over the elements of a slice or an array:
let items = [1, 2, 3, 4, 5];
for (let item .. items) {
fmt::println(item)!;
};
You can additionally iterate using pointers to each member, like so:
let items = [1, 2, 3, 4, 5];
for (let item &.. items) {
*item += 1;
};
// Prints 2 3 4 5 6
for (let item .. items) {
fmt::println(item)!;
};
Rounding out the new feature is the addition of the “done” type, which implements a simple approach to first-class iterators. Some stdlib types, previously subtypes of void, now use “done” types to take advantage of the new feature, e.g. io::EOF. You can combine these done types with a new loop syntax to concisely implement a loop which repeatedly calls a function that eventually returns done.
Here’s an example that uses the new for-each loops to read lines from a file:
// Before
const scan = bufio::newscanner(os::stdin);
for (true) {
let line = match (bufio::scan_line(&scan)?) {
case let s: const str =>
yield line;
case io::EOF => break;
};
fmt::println(line)!;
};
// After
const scan = bufio::newscanner(os::stdin);
for (let line => bufio::scan_line(&scan)?) {
fmt::println(line)!;
};
Optional function parameters
Functions can now define default values for optional function parameters using the following syntax:
fn example(x: int, y: int = 34) void = {
// ...
};
example(12); // Equivalent to example(12, 34);
This feature was designed by Sebastian and implemented by Joe Finney for Hare 0.24.2. Many standard library functions have been updated to take advantage of this feature. For example, the strconv module previously had separate functions like “utos” and “utosb”, which respectively converted uints to strings using the default base (base 10), or with a caller-specified base. The “utosb” family of functions has been removed in favor of generalizing the “utos” family with optional parameters:
fn utos(u: uint, b: base = base::DEC) const str;
Improvements to bufio performance
The bufio module (buffered I/O) is designed to improve I/O performance by batching many small reads or writes into less frequent, larger I/O operations, maintaining an internal buffer of pending I/O to flush periodically. However, its implementation performance has traditionally been very poor, and it was often the bottleneck for I/O bound Hare programs, which is quite unfortunate given its purpose is to improve performance!
Max Schillinger, Jose Lombera, and Lorenz worked together in the Hare 0.24.2 release cycle to improve its performance by eliminating memory copies wherever possible, making the performance comparable to other buffered I/O implementations.
A number of standard library modules which depend on buffered I/O have also been refactored or rewritten to improve performance and API design, notably modules in unix::, such as unix::resolvconf, unix::hosts, and unix::passwd – this work was led by Drew DeVault in an effort to eventually deprecate the last few “slow” paths in bufio.
Multiple alternation for regex::
Max Schillinger has finally rounded out Hare’s regex:: module with support for
multiple alternation – patterns like (ha|py|sh)
– which completes our
implementation of POSIX Extended Regular Expressions. Hooray!
Shared memory and memfd support
Drew DeVault worked on expanding support for shared memory constructs, useful for multiprocessing and inter-process communication on Unix. An implementation of shm_open et al is now available for all supported platforms, which is compatible with the libc implementations for these platforms, allowing for Hare programs to use POSIX shared memory to interact with C programs. memfd support was also added for platforms that support it, namely FreeBSD and Linux. This is particularly useful, for example, when implementing Wayland clients and servers in Hare – hare-wayland previously used the appropriate syscalls directly.
Thanks to Mallory for putting the finishing touches on the NetBSD implementation!
Breaking changes
This release includes a number of breaking changes from 0.24.0, which may require downstream users to update their code. These are summarized in the release notes, which I’ve copied here for your convenience.
The introduction of the “done” type to improve the iterator pattern introduces the following changes:
- “done” is now a reserved word and cannot be used in user-defined names
- The following standard library symbols have been updated to use done
types in their API:
- bytes::next_token/bytes::prev_token
- encoding::utf8
- fs::next
- glob::next
- io::EOF
- mime
- path::nextiter
- strings::next/strings::prev
- strings::next_token/strings::prev_token
- In short, if your program matches on a function using the iterator pattern with “void” and this causes an error from 0.24.2, the correct solution is likely to rewrite it to use a for-each loop, or replace “void” with “done” in the relevant match case.
bytes::tokenize now accepts multiple single-byte delimiters and removes support for multi-byte delimiters. strings::tokenize accepts multiple delimiters, limited to the set of ASCII characters.
The following APIs have been overhauled and programs depending on them may need to be refactored:
- unix::hosts
- unix::passwd
- unix::resolvconv
Several breaking changes have been made to time:
- time::date now accepts a zone offset (zoff) parameter in time::date::reckon and time::date::truncate.
- time::date::calculus has been renamed to time::date::rflag.
- time::date::realize requires .vloc to be set, and no longer defaults to UTC.
- time::date::now() is renamed to time::date::localnow() and time::date::nowutc() is renamed to time::date::now()
- time::date::EPOCHAL_JULIAN and EPOCHAL_GREGORIAN have been renamed to EPOCHDAY_JULIAN and EPOCHDAY_GREGORIAN respectively
- time::chrono::eq has been removed and replaced with time::chrono::simultaneous and time::chrono::coincident
- time::chrono::mzone has been renamed to time::chrono::ozone
- The type of time::date::parsefail has been changed from rune (storing the offending format specifier) to (size, rune), which adds the index of the position where the parsing failure occured.
- Several constants for format layouts in time::date have been renamed:
EMAILZ => EMAILZONE
STAMP_NANO => STAMPNANO
STAMP_ZOFF => STAMPZOFF
STAMP_ZONE => STAMPZONE
STAMP_NOZL => STAMPLOC
strconv’s “b” family of functions (those which accept a base for the conversion) have been removed, and the remaining functions accept the desired base as an optional parameter.
The following modules have been removed from the standard library and placed in the extended library: