Odin · the first program

Hellope! — the smallest program, taken apart

The whole program is four lines that do real jobs and nothing decorative — there is no boilerplate here to ignore. Click any line to see exactly what it contributes.

The output below is real — captured from odin run main.odin -file (claim: solution).
main.odin  —  the entire program

      

What it prints

$ odin run main.odin -file
Hellope!

The whole story

A package line names the file's package, an import brings in a package to call, :: binds the name main to a procedure, and that procedure's one statement asks fmt to print a string. Run it, the line is written, the program is over.

the “ln” in println is the newline fmt.println writes its text and then a newline. Its sibling fmt.print writes the same text with no trailing newline. So println("Hellope!") followed by print("Hellope!") then print(" again") lands on stdout as two lines — Hellope!, then Hellope! again with nothing after it. The break between them is the ln doing its one job.

Level 1 was what each line does. Level 2 is the idea hiding in the punctuation: :: is one universal “bind this name to this value” operator, and main is a name with a fixed type the compiler will not let you change.

One operator binds them all

main :: proc() { … } looks like special entry-point syntax, but it isn't. The :: reads “the name on the left is permanently this value on the right” — and that value can be a string, a number, or a procedure. A procedure is just another value you can bind to a name. All three of these are the same construction, and they compile together in one file:

name  ::  value  —  the same binding, three kinds of value
GREETING::"Hellope!"a string value
TIMES::3an int value
main::proc() { … }a procedure value

Why this matters: there is no separate grammar to memorise for “declaring a function” versus “declaring a constant.” You learned :: once on line 5 of your first program, and it is the exact same operator you'll use to name a constant, a type, or any procedure for the rest of the language. main is not blessed syntax — it's an ordinary :: binding whose value happens to be a procedure. (All three bindings above compile in one file — claim: colon-colon-binds-both.)

But main has one rule it can't break

The name main is special in exactly one way: when the program starts, the runtime calls it. That call has a fixed shape — no arguments, no return — so the type of main is locked to proc(). You're free to bind main to a procedure value; you are not free to give that procedure a different signature. The compiler checks this at build time. Pick a way to break it:


    

these are compiler errors, not crashes Both messages above stop the build — the program is never produced, so it never runs. The first is a Syntax Error: the parser reaches the import on line 3 before it ever saw a package line, and refuses to continue. The second is a type Error: the file parses fine, but main's type doesn't match the proc() the runtime requires. Reading which kind of error you got tells you whether the problem is in the shape of the text or in the meaning of the code.

That's the arc: L1 four working lines — a package, an import, a :: binding, and one printed string — produce Hellope!L2 that :: is one universal “name binds to value” operator, and main is just a binding whose proc() type the compiler holds fixed because the runtime calls it.

probes reproduce with odin run / odin build · the printed output & both compile errors are real compiler output (claims/lessons/01-hellope)