← Code Compare

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.

Show: CC++HolyCZigHareOdinForth
C
#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.

C++
#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.

HolyC
// 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.

Zig
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.

Hare
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.

Odin
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.

Forth
\ ." 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
;
HELLO

Forth 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.