Hare
2022fragletsystemsimperativesystems.ha
docker run --rm --platform="linux/amd64" 100hellos/hare:latest
MCP + fragletc
MCPstdinargs
This language supports code execution via MCP and the fragletc CLI. Stdin piping and argument passing are both supported.
Install fragletc →Hare is a systems programming language designed by Drew DeVault. It targets POSIX-like kernels and produces statically linked, MUSL-compatible ELF binaries by default—perfect for the Alpine-based images used in 100hellos.
Why it's interesting
- Simple toolchain: The single
haredriver wraps the compiler (harec), QBE backend, assembler, and linker. - Safety without GC: Memory-safe idioms such as slices, option types, and bounds-checked arrays, yet no runtime garbage collector.
- First-class cross-compilation:
hare build -t aarch64produces binaries for other architectures with zero extra flags. - Low-level pragmatism: Familiar C-style syntax, but modern features like modules, defer statements, and algebraic data types.
Hello World explained
use fmt;
export fn main() void = {
fmt::println("Hello World!")!;
};use fmt;imports the fmt standard-library module for formatted I/O.export fn main()marks the entry point that will be visible to the linker.- The trailing
!afterprintlnpropagates any I/O error (similar to Rust's?). ;terminates the block with an explicit semicolon—a Hare quirk.
Try it yourself (inside the container)
# Build a static binary
hare build -o hello hello-world.ha
./helloOr iterate quickly:
hare run hello-world.haFurther exploration
- Official site & docs: https://harelang.org
- Community IRC:
#hareon Libera.Chat - Blog post "Cross-compiling Hare programs is easy" for multi-arch builds.
Hello World
// BEGIN_FRAGLET
use fmt;
export fn main() void = {
fmt::println("Hello World!")!;
};
// END_FRAGLETCoding Guide
Language Version
Hare (latest from Alpine edge repositories)
Execution Model
- Compiled language using
hare build - Code is compiled to a static binary, then executed
- Standard Hare execution model with
export fn main() voidas entry point - Can also use
hare runfor quick iteration (compiles and runs in one step)
Key Characteristics
- Statically typed systems programming language
- Case-sensitive
- Memory-safe idioms (slices, option types, bounds-checked arrays)
- No garbage collector (manual memory management)
- C-style syntax with modern features
- Module-based organization (
usestatements) - Error handling with
!operator (error propagation) - Explicit semicolons required
Fragment Authoring
Write valid Hare code. Your fragment can define functions, types, and the main() function. use statements are already in place. Your fragment will be compiled and executed.
Important:
- Functions must be marked with
exportif they're the entry point - Use
!operator to propagate errors (e.g.,fmt::println("text")!) - Semicolons are required to terminate statements
- Module imports use
usekeyword (e.g.,use fmt;)
Available Modules
The template includes the standard library module:
fmt- Formatted I/O (println, printf, etc.)
Additional standard library modules can be imported as needed:
strings- String manipulationstrconv- String conversionsos- Operating system interfaceio- I/O primitivesmath- Mathematical functionstime- Time operationstypes- Type utilitiesbufio- Buffered I/Oencoding::base64- Base64 encodingnet::http- HTTP client and server- And many more from the Hare standard library
Common Patterns
- Print:
fmt::println("message")!;orfmt::printfln("format {}", value)!; - Variables:
let x: int = 10;orlet x = 10;(type inference) - Functions:
fn add(a: int, b: int) int = a + b; - Structs:
type person = struct { name: str, age: int }; - Slices:
let numbers: []int = [1, 2, 3]; - Arrays:
let arr: [5]int = [1, 2, 3, 4, 5]; - Option types:
let x: (int | void) = 42; - Error handling:
result!;(propagates error, or usematchfor handling) - Loops:
for (let i = 0; i < len(arr); i += 1) { ... } - Range loops:
for (let i = 0z; i < len(slice); i += 1) { ... }
Examples
Simple output
export fn main() void = {
fmt::println("Hello from fragment!")!;
};Variables and calculations
export fn main() void = {
let a: int = 5;
let b: int = 10;
fmt::printfln("Sum: {}", a + b)!;
};Functions
fn add(a: int, b: int) int = a + b;
export fn main() void = {
let result = add(5, 10);
fmt::printfln("5 + 10 = {}", result)!;
};Slices and loops
export fn main() void = {
let numbers: []int = [1, 2, 3, 4, 5];
let sum = 0;
for (let i = 0z; i < len(numbers); i += 1) {
sum += numbers[i];
};
fmt::printfln("Sum: {}", sum)!;
};Structs
type person = struct {
name: str,
age: int,
};
export fn main() void = {
let p = person {
name = "Alice",
age = 30,
};
fmt::printfln("{} is {} years old", p.name, p.age)!;
};String operations
export fn main() void = {
let s = "Hello";
fmt::printfln("{} World!", s)!;
};Option types
fn maybe_value() (int | void) = 42;
export fn main() void = {
match (maybe_value()) {
case let v: int =>
fmt::printfln("Value: {}", v)!;
case void =>
fmt::println("No value")!;
};
};Caveats
- Semicolons are required: Hare requires explicit semicolons after statements
- Error propagation: Use
!operator to propagate errors from functions that can fail - Type annotations: While type inference works, explicit types are often clearer
- Memory management: No garbage collector - be mindful of memory allocation
- Module syntax: Use
use module;for imports, access withmodule::function() - Export functions: Only
export fn main()is required, but you can export other functions - Index types: Use
sizetype (suffixz) for array/slice indices:let i = 0z;
Fraglet Scripts
Echo Args
#!/usr/bin/env -S fragletc --vein=hare
use fmt;
use os;
use strings;
export fn main() void = {
let args = os::args[1..];
fmt::print("Args: ")!;
for (let i = 0z; i < len(args); i += 1) {
if (i > 0) fmt::print(" ")!;
fmt::print(args[i])!;
};
fmt::println("")!;
};Stdin Upper
#!/usr/bin/env -S fragletc --vein=hare
use fmt;
use os;
use io;
use bufio;
use ascii;
export fn main() void = {
const scan = bufio::newscanner(os::stdin, 4096);
defer bufio::finish(&scan);
for (true) {
match (bufio::scan_line(&scan)) {
case let line: const str =>
const upper = ascii::strupper(line);
fmt::println(upper as str)!;
free(upper as str);
case io::EOF =>
break;
case let err: io::error =>
break;
};
};
};Test
#!/usr/bin/env -S fragletc --vein=hare
use fmt;
export fn main() void = {
fmt::println("Hello World!")!;
};Connections
influenced by