05 - Language Basics
Verge feels fairly terse, fairly direct, and fairly C-adjacent, but with less ceremony in the obvious places. The language generally aims to stay out of your way.
This chapter is the “how does the syntax feel” tour. Nothing here is deep; it’s the handful of rules that make the rest of the code readable.
Braces, not vibes
Verge uses braces for blocks, and braces alone define where a block starts and ends:
import std.io
main: f() {
if true {
io.writeln("braces win again")
}
}
Indentation carries no meaning to the compiler. By convention you indent with tabs inside braced blocks so the structure stays visible, but formatting has no effect on how the code compiles. The braces are the source of truth.
Comments
Ordinary comments start with # and run to the end of the line. Documentation comments
start with ## and sit immediately above a declaration — the formatter preserves them and
the language server surfaces them on hover and in completions.
import std.io
## Greets a person by name.
greet: f(name: string) {
# greet the caller by name
io.writeln("Hello, ", name)
}
main: f() {
greet("Ada")
}
Hello, Ada
Get in the habit of ## on anything another human will call — it’s the same text your
editor shows them later.
Newlines end statements
Most statements end at the newline. You don’t need semicolons, which keeps lines uncluttered:
import std.io
main: f() {
x := 10
y := 20
sum := x + y
io.writeln("sum = ", sum)
}
sum = 30
Line continuation is automatic
If a line has an unclosed (, [, or {, Verge keeps reading onto the next line until the
bracket closes. That means you can break long expressions and collection literals across
lines without any special marker:
import std.io
main: f() {
total := (
10 +
20 +
30
)
values := []i32{
1,
2,
3,
}
io.writeln("total = ", total, ", first = ", values[0])
}
total = 60, first = 1
Explicit types vs inference
Write an explicit type when it helps the reader; reach for := when the value already makes
the type obvious:
import std.io
main: f() {
count: i32 = 3 # explicit type
name: string = "verge" # explicit type
inferred_count := 3 # inferred as i32
inferred_name := "verge" # inferred as string
limit: const i32 = 42 # a constant — cannot be reassigned
io.writeln(name, " ", inferred_name, " ", count + inferred_count, " ", limit)
}
verge verge 6 42
The rule of thumb: if the type matters to whoever reads the line, spell it out; if it’s
painfully obvious, let inference handle the boring part. const marks a value that must not
change, and it always takes an explicit type.
The overall feel
Verge aims to be readable without being verbose: compact declarations, braces for blocks,
plain # comments, and syntax that favours stating the intent directly over filling in
boilerplate. That’s enough to read Verge comfortably — the next chapter gets specific about
the values you’ll actually be moving around.