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

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:

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:

Several breaking changes have been made to time:

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: