Generic brackets: bind and apply¶
Status: decided. Generics are written with angle brackets, in every position. Square brackets are value-level and never appear in a type.
fn first<T>(xs: Seq<T>) : T?
The rule¶
< > the type world — binding a parameter and applying a constructor
[ ] the value world — sequence literals and indexing
One symbol, one world. There is no second spelling for either job:
Seq<Concept> // apply a constructor
Map<String, Data>
Relation<Person, Project>
Renderable<T>
fn map<T, U>(xs: Seq<T>, f: T -> U) : Seq<U> // bind parameters
fn resolve<T>(x: Ref<T>) : T?
[alice, bob, charlie] // a sequence value
{alice, bob, charlie} // a set value
xs[0] // indexing
Why angle brackets¶
HQL wants [] at the value level, for sequence literals and for indexing. If
[] also meant type application, one pair of brackets would carry four
conceptually different jobs:
[alice, bob] // sequence literal
xs[0] // indexing
Seq[Person] // type application
fn foo[T](...) // generic declaration
A parser can tell those apart — Scala and Python prove it. The question is whether a reader should have to. With angle brackets reserved for types, an angle bracket always means the type world and a square bracket always means the value world, and neither ever has to be disambiguated by context.
The spelling is also the conventional one. Seq<T> and fn first<T> read the
same way in C++, Java, C#, TypeScript, Rust and Kotlin, so nothing here has to
be learned before it can be read.
The hybrid is rejected¶
One arrangement was considered and turned down: [...] to bind type
variables and <...> to apply a constructor.
fn map[T, U](xs: Seq<T>, f: T -> U) : Seq<U> // rejected
fn resolve[T](x: Ref<T>) : T? // rejected
The distinction is coherent — binding and application genuinely are different
operations — but it buys a reader nothing they did not already know from
position, and it costs the property the whole choice exists to secure: that a
bracket shape tells you which world you are in. It also reintroduces the
overload of [] that motivated angle brackets in the first place. No
hybrids.
Syntax migration must preserve semantics¶
Adopting this across doc/** was a mechanical rewrite, and a mechanical rewrite
is allowed to change spelling and nothing else. Set<T> for Set[T] is such a
change. This is not:
card.metadata.concepts : List<Concept>
List is no longer part of the decided collection vocabulary, so the occurrence
cannot simply be respelled — it needs a semantic choice between Seq<Concept>
and Set<Concept>. That choice follows from whether the order of a card's
concepts carries information, which is a question about what concepts means.
It was therefore left unresolved in Card
rather than settled in passing.
The separation matters more than the bracket choice itself: a syntax migration that quietly decides semantics leaves no record that a decision was made.
Consequences¶
- type-system states the rule and no longer lists bracket style as an open question.
- core and
design-status restate it; the vocabulary
tables are
Set<T>,Seq<T>,Map<K, V>. - Carrying the spelling through every file is tracked as
CON-13in consolidation. The example corpus is not in this working tree and is the outstanding residue. - Quotations that are evidence of the former divergence keep their original
spelling:
INC-06in inconsistencies quotesOption<List[Card]>, which is the finding.
What this does not decide¶
ListversusSeqversusSetat any particular site, includingcard.metadata.concepts—INC-05and the note on Card.- Whether type arguments are ever written at a call site.
validate<Person>(card)is one candidate spelling for explicit application; inference is the other. type-system records that as open. - Bound syntax.
fn show<T, R>(x: T) where T : Renderable<R>and the inlinedfn show<T : Renderable<R>, R>(x: T)are both open; that the relation is spelled:in either is not. - Variance, which depends on whether constructed values stay immutable.
See type-system for generics and subtyping, collections for the collection vocabulary, and optional fields and optional values for the other spelling question settled alongside this one.