Files
sx/examples/types/0202-types-void-empty-parens.sx
agra 76689a1ea6 feat: multiple return values — bare-paren signatures, named returns, must-set, defaults
A function may return multiple values via a bare-paren return signature:
`-> (A, B)` / `-> (x: A, y: B)` / `-> (A, B, !)` (error always the last slot),
and `-> ()` is `void`. This is DISTINCT from a `Tuple(…)` value — return-position
only (a dedicated `ReturnTypeExpr` AST node resolving to a reused `.tuple`
TypeId); a parameter / field / variable annotation `x: (A, B)` is rejected. A
single-value `-> (T, !)` stays a plain failable (= `-> T !`).

Returns use the bare comma form `return a, b` / `return x = a, y = b` (no `.( … )`
literal). Consume by destructuring (`a, b := f()`) or single-bind + field access
(`c := f(); c.sum`); a failable bound value holds only the value slots (the error
stays on the `!` channel).

Named return slots are in-scope assignable locals; with no explicit `return` the
implicit return is synthesized from them. Path-sensitive definite-assignment
enforces the must-set rule, and a slot may carry a default that exempts it.
Validation rejects arity mismatches, out-of-slot-order named elements, a
slot/parameter name collision, a comma list from a single-value function, and a
multi-return signature used as a value type.

Examples 0202-0213; readme + specs updated. issues/0197 files a pre-existing
annotated-assignment type-check gap (`x: i32 = "hi"` segfaults) surfaced by the
adversarial review.
2026-06-27 12:31:23 +03:00

22 lines
696 B
Plaintext

// Empty parens `()` as a return type mean `void`: `f :: () -> () { … }` is
// exactly `f :: () -> void { … }`. The zero-parameter FUNCTION type `() -> R`
// (a callable taking no args) is unaffected — only an empty `()` in the
// return-TYPE slot folds to void.
#import "modules/std.sx";
// `-> ()` is void: no value returned.
greet :: () -> () { print("hi\n"); }
// A `-> void` spelling, for contrast — identical behavior.
greet2 :: () -> void { print("bye\n"); }
// Zero-param function-typed parameter still parses as a callable, not void.
run :: (f: () -> i64) -> i64 { return f(); }
main :: () -> i64 {
greet();
greet2();
print("{}\n", run(() => 7));
return 0;
}