;;;; Two spellings a struct value gained, both decided by the checker. ;;;; ;;;; A bare {.field v} has no type written in front of it. The fields alone do ;;;; not name one, but the position usually does: a defn's return type, a ;;;; parameter, a field of an enclosing literal, a place being set. The parser ;;;; cannot see any of that -- it has no symbol table and no expectation -- so ;;;; it builds the field list and the checker reads the type off the want and ;;;; hands the very same list to the named form's own code. Everything below ;;;; that follows -- ZII for an omitted field, the unknown-field and ;;;; duplicate-field refusals -- is therefore not a copy of the named form's ;;;; rules, it is the named form's rules. ;;;; ;;;; (Cell 1 2) is the other half, and it is a call until the checker looks the ;;;; head up: a struct name where a function name would be. Arity is exact. ;;;; ZII is still available and is what the braces do; what a positional list ;;;; cannot do is SAY which field it left out, so it is not allowed to leave ;;;; one out. (defstruct Cell [row i32 col i32]) (defstruct Grid [a Cell b Cell]) ;; The case from the notes: a defn whose return type is the only place the ;; type is written. This is what used to fail at parse, before any checking. (defn origin [] Cell {.row 0 .col 0}) ;; An omitted field is zeroed, exactly as (Cell {.row 3}) zeroes .col. (defn just-row [r i32] Cell {.row r}) ;; A parameter is an expectation too -- as the only argument and as a later ;; one, which are two different paths into the checker and both arrive here. (defn sum [c Cell] i32 (+ (.row c) (.col c))) (defn offset-sum [n i32 c Cell] i32 (+ n (sum c))) ;; A field of an enclosing literal. The inner braces are bare and the outer ;; ones are not, so both readings stand side by side in one form. (defn grid [] Grid (Grid {.a {.row 1 .col 2} .b (Cell 3 4)})) ;; Positional, in the position that names the type anyway. (defn diag [n i32] Cell (Cell n n)) ;; Nested positional, and positional feeding a bare literal's field. (defn pair [] Grid (Grid {.a (Cell 5 6) .b (Cell 7 8)})) (defn main [] () (println (sum (origin))) (println (sum (just-row 9))) (println (sum {.row 10 .col 20})) (println (offset-sum 1 {.row 2})) (let [g (grid)] (println (.row (.a g))) (println (.col (.a g))) (println (.row (.b g))) (println (.col (.b g)))) (println (sum (diag 11))) (let [p (pair)] (println (sum (.a p))) (println (sum (.b p)))) ;; A bare literal set into a typed place: the place's type is the want. (let [c (Cell 0 0)] (set c {.row 7 .col 8}) (println (sum c)) ;; And into a field, whose type is the want one level down. (let [g (Grid {.a c .b c})] (set (.b g) {.row 100}) (println (sum (.b g))))) ;; The dyn map literal is untouched by any of this: keyword keys, and a ;; .field-keyed brace was never part of that spelling. (let [m {:a 1 :b 2}] (println (len m)) (println (get m :b))))