Jaime López

Data Science Systems Developer

Home Blog Tracker About


My first program in Hare

Jun. 11, 2026 (draft version)

I'm taking a look into the Hare programming language by writing a small program, my first one in this completly unbloted C's alternative.

Hare is a systems programming language designed to be simple, stable, and robust. Hare uses a static type system, manual memory management, and a minimal runtime. It is well-suited to writing operating systems, system tools, compilers, networking software, and other low-level, high performance tasks.

When trying a new language, instead of going with the "Hello, world", I use to write a basic http request example. Besides introducing the syntax, it gives me an idea of the input/output and the network interfaces.

However, first of all, I needed to install Harde in my system. Here my steps that you can take as a reference and adapt to your system. Because I'm working in a voidlinux laptop, to install Hare I used this command:

sudo xbps-install hare

Altough the http library is developed by the Hare team, it is not considered part of the standard library. Therefore, it needs to be installed separately (copy the respective files).

git clone https://git.sr.ht/~sircmpwn/hare-http
cd hare-http
sudo make install

In order to enable the Hare compiler to find the library files, the respective paths should set in an environment variable. Review if yours is already defined and add the http sources:

echo $HAREPATH
export HAREPATH=$HAREPATH:/usr/local/src/hare/third-party

# in case, it is not defined, you can try:

export HAREPATH=/usr/src/hare/stdlib:/usr/local/src/hare/third-party

I have included this export permanently in my .profile file.

Hare's modules live in directories. Functions require the export keyword to be public, otherwise, they are private by default. A module's functions can be written acress different files within the same directory. Submodules are place in subdirectories.

Starting with my example, here is how to import modules:

use fmt;
use io;
use os;
use net::uri;
use net::http;

To obtain help about a module, you can use the command haredoc, so you don't need to search in Internet or to abandon the terminal to review the documentation. If you prefer, you can also read a module's source code. It is well commented and easy to read.

haredoc fmt::println
haredoc net::uri
haredoc net::http

Functions are declared using the fn keyword with the argument list in parenthesis and the return type following them, separated by an = symbol. This is the signature of my main function:

export fn main() void = {
    ...
};

In Hare, memory and resource management is manual. It is responsability of the programmer to release them. The language, similar to Go, offers the defer feature, to include expressions to be executed at the end of the current scope.

Let's apply this to create the http client:

    let client = http::newclient("hare/1.0")!;
    defer http::client_finish(&client);

The same as in C, the operator & is used to obtain the address of a variable to use it as a pointer.

The next step is to create an uri struct, that contains attributes like hostname, port, and path (check haredoc net::uri). This can be created from an string using the function parse. This function can return an error. The operator ! is the simplest error management approach, assuming that the error is not going to occur.

    let url = uri::parse("http://example.com/")!;

We are ready to send the request:

    let resp = http::get(&client, &url)!;
    defer http::response_finish(&resp);
    if (resp.status != http::STATUS_OK) {
        fmt::fatalf("Failure: {}\n", resp.status);
    };

If no error occurs, we can display the response body in the standard output device.

    io::copy(os::stdout, resp.body)!;

Here is the full listing:

use fmt;
use io;
use os;
use net::uri;
use net::http;

export fn main() void = {
    let client = http::newclient("hare/1.0")!;
    defer http::client_finish(&client);

    let url = uri::parse("http://example.com")!;
    let resp = http::get(&client, &url)!;
    defer http::response_finish(&resp);

    if (resp.status != http::STATUS_OK) {
        fmt::fatalf("Failuer: {}\n", resp.status);
    };

    io::copy(os::stdout, resp.body)!;
};

To compile and run the program:

hare build request.ha
./request

# or

hare run request.ha

Hare is intended to be used as C replacement for or complement to. The same as C, Hare is a minimalist language. The development team's promise is that when Hare reaches version 1.0, the language syntax and semantics will be freezed, ensuring that programs written with Hare remain stable for the long-term.

The language has its own independent standard library, so no libc dependency. It uses an extended set of the C ABI. C funcions can be call from Hare and also, it's easy to call Hare functions from C. Unlike C, Hare includes namespaces and a more modern approach to error management.

As a minimalist language, Hare trades multithreading for strict predictibility and isolation (event loops and multiprocessing). It excludes macros, generics, comptime and other metaprogramming features. Certainly, Hare is not for programmers looking for high-level abstractions.

Hare is an, may be extreme, compromise in favor of simplicity and freedom, that want to be aligned with the core values of the free software tradition. In pragmatic terms, it is a small language easy to learn and keep completly in your head, while providing the essential features to deal with the always challenging systems programming problems.

Resources: