Hello, World
The classic first program, recast for seven GC-free systems languages: print the single line Hello, systems!. Even this trivial task exposes each language's personality - what the entry point looks like (or whether one is needed), how a string literal lives in static read-only memory (no allocation, nothing to free), and how output reaches the terminal. Watch that none of these need the heap: the text is baked into the binary, so this is the rare topic with no malloc/free in sight - the perfect baseline before the memory-heavy topics that follow.
#include <stdio.h>
int main(void) {
/* "Hello, systems!" is a string literal: stored in static,
read-only memory, not on the heap. Nothing to free. */
printf("Hello, systems!\n");
return 0;
}Idiomatic C11: the literal "Hello, systems!" lives in a static read-only segment baked into the executable, so there is no malloc and nothing to free. printf writes it to stdout, and return 0 reports success to the OS.
#include <iostream>
int main() {
// The string literal sits in static storage; std::cout streams it.
// No heap allocation, no RAII cleanup needed for this.
std::cout << "Hello, systems!\n";
}Modern C++ uses the <iostream> stream std::cout with operator<<. The literal is static read-only data (no new/delete, no smart pointer required), and main may omit return 0 - reaching the end implicitly returns success.
// Top-level code runs in TempleOS - no main() needed.
// Print writes the literal straight to the screen.
Print("Hello, systems!\n");HolyC executes top-level statements directly (no main), so the whole program is one Print call. The string literal lives in the compiled binary, not the per-task heap, so there is no MAlloc/Free - Print is HolyC's printf-style formatter.
const std = @import("std");
pub fn main() void {
// The literal is a comptime-known *const [15:0]u8 in read-only data.
// std.debug.print needs no allocator -- no hidden allocations.
std.debug.print("Hello, systems!\n", .{});
}Zig string literals are comptime-known, null-terminated arrays in read-only memory - no allocator, nothing to free. std.debug.print takes a format string plus an empty args tuple .{} and writes to stderr without any hidden allocation.
use fmt;
export fn main() void = {
// The literal is a static const str (a slice into read-only data).
// fmt::println adds the newline; the trailing ! propagates I/O errors.
fmt::println("Hello, systems!")!;
};Hare's main is an exported fn returning void. The literal is a const str backed by static read-only memory (no alloc/free), and fmt::println appends the newline. The trailing ! handles the (size | io::error) result: since main returns plain void, it asserts on success and aborts the program on a write error rather than silently ignoring it.
package main
import "core:fmt"
main :: proc() {
// The string literal is static read-only data; the implicit
// context.allocator is never touched here. No new/delete.
fmt.println("Hello, systems!")
}Odin programs are a package with a main :: proc(). The literal is static read-only data - the implicit context.allocator is untouched, so there is no make/delete. fmt.println prints the string and a trailing newline.
\ ." prints the inline literal that follows, up to the closing ".
\ The text is compiled into the dictionary -- no runtime allocation.
: HELLO ( -- )
." Hello, systems!" CR \ CR emits the trailing newline
;
HELLOForth defines the word HELLO with : ... ;; ." prints the literal compiled inline into the dictionary, and CR emits the newline (Forth has no \n in strings). The text lives in the dictionary for the program's life - nothing is allocated or freed at runtime.