Dependent Object Types: Type Members, Bad Bounds, and Recursive Self
Prerequisites. Direct starred prerequisites: none. No later core chapter depends on this route.
An existential package can hide a representation type, but a client cannot name that type in the result of a second method after the package has been opened and closed. A family-polymorphic object needs a persistent name. If 𝑥 denotes the object and 𝐴 denotes its abstract type member, the client needs the type 𝑥.𝐴. Bounds make that name useful: 𝑥:{𝐴:𝑆..𝑈}⟹𝑆<:𝑥.𝐴<:𝑈. The same two inequalities also create the central obstruction. An arbitrary assumption 𝑥:{𝐴:⊤..⊥} yields ⊤<:⊥ and collapses every pair of types. The soundness proof must therefore distinguish hypotheses written in a function body from hypotheses justified by values at run time.
The selected calculus is A-normal and restricts paths to variables. Its types, terms, values, and definitions are 𝑇,𝑈::=⊤∣⊥∣{𝑎:𝑇}∣{𝐴:𝑆..𝑈}∣𝑇∧𝑈∣∀(𝑥:𝑆)𝑈∣𝜇(𝑥:𝑇)∣𝑥.𝐴.𝑡,𝑢::=𝑥∣𝜆(𝑥:𝑇).𝑡∣𝑥𝑦∣𝑥.𝑎∣𝜈(𝑥:𝑇)𝑑∣𝗅𝖾𝗍𝑥=𝑡𝗂𝗇𝑢,𝑣::=𝜆(𝑥:𝑇).𝑡∣𝜈(𝑥:𝑇)𝑑,𝑑::={𝑎=𝑡}∣{𝐴=𝑇}∣𝑑∧𝑑. Labels combined by 𝑑1∧𝑑2 are disjoint. In the recursive object type𝜇(𝑥:𝑇), 𝑥 binds a term receiver that may occur in 𝑇. In the object value𝜈(𝑥:𝑇)𝑑, the same receiver names the object while checking 𝑑. This binder is not the recursive type variable 𝑋 in 𝜇𝑋.𝑅(𝑋), not the OO family type Self, not a same-subject intersection binder, and not an identity path.
The first family object stores an abstract element type and a value of that type: 𝖢𝖾𝗅𝗅=𝜇(𝑐:{𝐴:⊥..⊤}∧{𝑣𝑎𝑙𝑢𝑒:𝑐.𝐴}). An implementation with representation ℕ is 𝜈(𝑐:{𝐴:ℕ..ℕ}∧{𝑣𝑎𝑙𝑢𝑒:𝑐.𝐴})({𝐴=ℕ}∧{𝑣𝑎𝑙𝑢𝑒=0}). After binding this value to 𝑛, a client may project 𝑛.𝑣𝑎𝑙𝑢𝑒:𝑛.𝐴 without learning that 𝑛.𝐴=ℕ. The type member persists as the path-dependent name that the existential encoding lacked.
The delta that makes the calculus dependent consists of the following rules.
Γ⊢𝑥:{𝐴:𝑆..𝑈}
Γ⊢𝑆<:𝑥.𝐴
DOT-Sel-L
Γ⊢𝑥:{𝐴:𝑆..𝑈}
Γ⊢𝑥.𝐴<:𝑈
DOT-Sel-U
Γ⊢𝑆2<:𝑆1Γ⊢𝑈1<:𝑈2
Γ⊢{𝐴:𝑆1..𝑈1}<:{𝐴:𝑆2..𝑈2}
DOT-Type-Mem-Sub
Dependent-function subtyping is the displayed rule
Γ⊢𝑆2<:𝑆1Γ,𝑥:𝑆2⊢𝑇1<:𝑇2
Γ⊢∀(𝑥:𝑆1)𝑇1<:∀(𝑥:𝑆2)𝑇2
DOT-Π-Sub
Γ⊢𝑥:𝑇
Γ⊢𝑥:𝜇(𝑥:𝑇)
DOT-Rec-I
Γ⊢𝑥:𝜇(𝑧:𝑇)
Γ⊢𝑥:𝑇[𝑥/𝑧]
DOT-Rec-E
Γ,𝑥:𝑇⊢𝑑:𝑇
Γ⊢𝜈(𝑥:𝑇)𝑑:𝜇(𝑥:𝑇)
DOT-Obj-I
Γ⊢𝑥:{𝑎:𝑇}
Γ⊢𝑥.𝑎:𝑇
DOT-Fld-E
Definition typing contains
Γ⊢{𝐴=𝑇}:{𝐴:𝑇..𝑇}
DOT-Def-Type
Γ⊢𝑡:𝑇
Γ⊢{𝑎=𝑡}:{𝑎:𝑇}
DOT-Def-Val
Γ⊢𝑑1:𝑇1Γ⊢𝑑2:𝑇2dom(𝑑1)∩dom(𝑑2)=∅
Γ⊢𝑑1∧𝑑2:𝑇1∧𝑇2
DOT-Def-And
Thus dependent-function subtyping is contravariant in the domain and compares the codomains under the smaller domain. The calculus has no subtyping rule between two recursive types. Recursion is introduced and eliminated through typing, which is one source of cycles in typing derivations.
Compare the two binders. DOT-All-I requires 𝑥∉fv(𝑇), because the parameter type is checked before the parameter is bound; its codomain 𝑈 may depend on 𝑥. By contrast, DOT-Let requires 𝑥∉fv(𝑈), because the result type escapes the let binder. DOT-Obj-I carries neither premise, and it must not: the receiver 𝑥 is exactly what 𝑇 is allowed to mention, and 𝜇(𝑥:𝑇) retains the binder in the conclusion. A freshness condition on DOT-Obj-I would make every object whose member type selects its own receiver untypable.
Put 𝑑ℕ={𝐴=ℕ}∧{𝑣𝑎𝑙𝑢𝑒=0} and 𝑇={𝐴:ℕ..ℕ}∧{𝑣𝑎𝑙𝑢𝑒:𝑐.𝐴}. The implementation above has the two-stage derivation Γ,𝑐:𝑇⊢{𝐴=ℕ}:{𝐴:ℕ..ℕ}Γ,𝑐:𝑇⊢{𝑣𝑎𝑙𝑢𝑒=0}:{𝑣𝑎𝑙𝑢𝑒:𝑐.𝐴}Γ,𝑐:𝑇⊢𝑑ℕ:𝑇DOT−Def−And. Consequently, Γ,𝑐:𝑇⊢𝑑ℕ:𝑇Γ⊢𝜈(𝑐:𝑇)𝑑ℕ:𝜇(𝑐:𝑇)DOT−Obj−I. The field-definition premise uses DOT-Sel-L and subsumption to derive 0:𝑐.𝐴. A neutral projection 𝑥.𝑎 has no reduction until a surrounding let binds 𝑥 to an object value.
★★☆ Bind the displayed cell implementation to 𝑛. Derive 𝑛.𝑣𝑎𝑙𝑢𝑒:𝑛.𝐴 and 𝑛.𝐴<:ℕ. Then replace the declaration by {𝐴:⊥..⊤} and identify the exact derivation step that no longer gives 𝑛.𝐴<:ℕ.
Proof of Proposition 107.3 — Collapse under a bad bound
Proof. The declaration 𝑥:{𝐴:⊤..⊥} makes both selection rules applicable to the same member, so DOT-Sel-L and DOT-Sel-U give Γ⊢⊤<:𝑥.𝐴 and Γ⊢𝑥.𝐴<:⊥. One use of DOT-Trans between them gives Γ⊢⊤<:⊥.(∗) The chain 𝑆𝐷𝑂𝑇−𝑇𝑜𝑝<:⊤(∗)<:⊥𝐷𝑂𝑇−𝐵𝑜𝑡<:𝑈 then yields Γ⊢𝑆<:𝑈 by two further uses of DOT-Trans. ◻
The assumption is well formed: ⊥<:⊤. It need not be inhabited by an object value. Definition typing assigns a concrete member only the tight declaration {𝐴:𝑇..𝑇}. A proof that globally inverts every well-formed context would therefore reason from assumptions that no run-time object can justify. Ordinary global narrowing and a transitivity proof based on such inversion are the wrong induction hypotheses.
★☆☆ Delete the lower selection rule from proposition 107.3 and construct a two-element subtype lattice in which the remaining premises hold but ⊤<:⊥ fails. Repeat after restoring DOT-Sel-L and deleting DOT-Sel-U.
Run-time values force a syntactic repair. A function value has a dependent function type. An object value has a recursive type whose concrete type members have equal bounds.
An inert type is either a dependent function ∀(𝑥:𝑆)𝑇 or a recursive type 𝜇(𝑥:𝑇) such that 𝑇 is an intersection of field declarations {𝑎:𝑆} and tight type declarations {𝐴:𝑆..𝑆} with pairwise distinct type labels. A context is inert if every declaration assigns an inert type.
The type 𝜇(𝑐:{𝐴:ℕ..ℕ}∧{𝑣𝑎𝑙𝑢𝑒:𝑐.𝐴}) is inert. The type 𝜇(𝑐:{𝐴:⊥..⊤}) is not: its member bounds differ. Inertness does not assert inhabitation; for example, ∀(𝑥:⊤)⊥ is inert and has no closed value in the calculus.
A precise variable judgment Γ⊢!𝑥:𝑇 starts from 𝑇=Γ(𝑥) and eliminates outer recursive types and intersections. It never applies subsumption. The tight typing judgmentΓ⊢#𝑡:𝑇 has the general DOT rules except that type selection requires an equal-bounds precise declaration:
Γ⊢!𝑥:{𝐴:𝑇..𝑇}
Γ⊢#𝑇<:𝑥.𝐴
DOT-T-Sel-L
Γ⊢!𝑥:{𝐴:𝑇..𝑇}
Γ⊢#𝑥.𝐴<:𝑇
DOT-T-Sel-U
Rules whose premises do not extend the context use tight premises. Lambda, let, and object introduction use general typing in the extended context, because their written parameter type need not be inert.
Tight typing still contains cycles, because DOT-Sub may both widen and narrow. Stratify it once more; the recipe is worth stating because it explains the variable-or-value restriction in theorem 107.9. Delete every elimination rule; specialize what remains to variables and values; and take the leaves from precise typing, which keeps only the rules that decomposeΓ(𝑥). What survives is the invertible typing judgmentΓ⊢##𝑡:𝑇: recursion introduction, intersection introduction, DOT-Top, tight selection, and the three covariance rules for fields, type members, and dependent functions. Every one of them builds a larger type from a smaller one, and none consumes a type it has just built, so induction on ⊢## terminates and each derivation exposes the outer form of its subject.
Because the second step of the recipe specializes to variables and values, ⊢## is defined only for those. That is not a technicality to be optimized away: it is why the bridge from tight typing carries a variable-or-value hypothesis, and it is enough, because canonical forms are asked only about variables and values.
Tight selection cannot reproduce the bad-bounds derivation: a precise declaration {𝐴:𝑇..𝑇} gives only 𝑇<:𝑥.𝐴<:𝑇. The restriction would be too weak for arbitrary DOT programs, but it loses no derivation in an inert context.
Proof. Induct simultaneously on the tight typing derivation and on each tight subtyping premise used by its final rule. A precise-variable leaf is already an invertible leaf. Rules for recursion introduction, intersection introduction, top, and covariance of fields, type members, and dependent functions rebuild the corresponding invertible rule from the induction hypotheses.
Elimination rules require inversions of the induction hypothesis rather than new invertible eliminators. For recursion elimination, the induction hypothesis for the premise ends in recursion introduction, so inversion returns its body type after self substitution. For either intersection projection, the premise ends in intersection introduction, and inversion selects the requested component. A subsumption conclusion uses the typing induction hypothesis for its subject and the simultaneous subtyping induction hypothesis for the comparison. Tight selection has a precise equal-bounds premise; its two rules therefore rebuild the same selected type from that precise leaf. A lambda, let, or object-introduction derivation can contribute only when its conclusion is a value, in which case the rule’s general premise is retained exactly as required by the invertible introduction rule. Application and field elimination cannot conclude a typing judgment for a syntactic variable or value. These cases cover every tight rule family and establish both simultaneous claims. ◻
Proof. Apply lemma 107.6, then induct on the resulting invertible derivation of Γ⊢##𝑥:{𝐴:𝑆..𝑈}. A precise-variable leaf starts from Γ(𝑥). Since Γ is inert, recursion elimination and intersection elimination reach a unique declaration {𝐴:𝑇..𝑇}; unequal bounds cannot occur in an inert recursive object type. This gives Γ⊢!𝑥:{𝐴:𝑇..𝑇}. The covariance rule for a type-member declaration changes its lower bound only by a premise 𝑆<:𝑇 and its upper bound only by a premise 𝑇<:𝑈. Recursive and intersection introduction preserve those two premises. No other invertible rule concludes a type-member declaration. The induction therefore yields 𝑆<:𝑇 and 𝑇<:𝑈 in every case. Applying DOT-T-Sel-L and DOT-T-Sel-U yields 𝑆<:𝑇<:𝑥.𝐴and𝑥.𝐴<:𝑇<:𝑈, and tight transitivity gives the two conclusions. ◻
Proof of Theorem 107.8 — General typing becomes tight in an inert context
Proof. Use mutual rule induction on general typing and subtyping. The induction hypotheses state the two displayed implications for every premise whose context is still Γ. Variable, application, projection, recursion, intersection, top, bottom, declaration, and subsumption cases rebuild the corresponding tight rule from those hypotheses. Dependent-function subtyping applies the induction hypothesis to the domain premise; its codomain premise extends the context, so the tight rule, like the definition, uses the general premise there. Lambda, let, and object introduction also retain their general extended-context premises. Only DOT-Sel-L and DOT-Sel-U lack tight counterparts. For those two cases, lemma 107.7 supplies the tight conclusions. This list exhausts the rule families. ◻
If inertness is deleted, the bad-bound context in proposition 107.3 derives ⊤<:⊥ generally, while tight typing cannot derive it. Thus the theorem’s substantive hypothesis is not removable.
Canonical forms and the safety interface
Tight typing still contains introduction/elimination cycles. Splitting it into precise elimination followed by invertible introduction makes the outer form of a run-time value recoverable by induction.
If Γ⊢𝑧:∀(𝑥:𝑇)𝑈, then Γ(𝑧)=∀(𝑥:𝑇′)𝑈′ for some 𝑇′ and 𝑈′ with Γ⊢𝑇<:𝑇′ and Γ,𝑥:𝑇⊢𝑈′<:𝑈.
If Γ⊢𝑣:∀(𝑥:𝑇)𝑈, then 𝑣=𝜆(𝑥:𝑇′).𝑡 for some 𝑇′ and 𝑡 with Γ⊢𝑇<:𝑇′ and Γ,𝑥:𝑇⊢𝑡:𝑈.
If Γ⊢𝑥:{𝑎:𝑇}, then Γ(𝑥)=𝜇(𝑥:𝑆) where 𝑆 is an intersection one of whose components is {𝑎:𝑇′}, and Γ⊢𝑇′<:𝑇.
If Γ⊢𝑣:𝜇(𝑥:𝑆) and 𝑆 is an intersection one of whose components is {𝑎:𝑇}, then 𝑣=𝜈(𝑥:𝑆)𝑑 where 𝑑 is an intersection one of whose components is {𝑎=𝑡}, and Γ⊢𝑡:𝑇.
Proof of Theorem 107.9 — Canonical forms in inert contexts
Proof. By theorem 107.8, each premise has a tight derivation. The subject is a variable or a value, so lemma 107.6 gives an invertible derivation.
For clause 1, precise decomposition of Γ(𝑧) removes outer recursive types and intersections. Inertness leaves either a dependent-function entry or an equal-bounds recursive-object entry. Only the first can acquire the outer type ∀(𝑥:𝑇)𝑈 in the invertible judgment. Its declaration is ∀(𝑥:𝑇′)𝑈′, and the covariance premises accumulated while rebuilding the type are 𝑇<:𝑇′ and, under 𝑥:𝑇, 𝑈′<:𝑈.
For clause 2, induct on the invertible typing of 𝑣. Recursive and intersection introductions preserve the induction hypothesis. Tight selection cannot be the base rule for a value of function type, because its precise premise is a variable judgment. Thus the base rule is DOT-All-I, which gives 𝑣=𝜆(𝑥:𝑇′).𝑡, 𝑇<:𝑇′, and Γ,𝑥:𝑇′⊢𝑡:𝑈′. Narrowing along 𝑇<:𝑇′ gives Γ,𝑥:𝑇⊢𝑡:𝑈′, and DOT-Sub along 𝑈′<:𝑈 gives the stated body judgment.
Clause 3 uses the first phase of clause 1. Precise decomposition of Γ(𝑥) reaches the unique field declaration {𝑎:𝑇′} in its inert recursive intersection, and the field covariance premises compose to 𝑇′<:𝑇. For clause 4, the invertible derivation cannot end at a function introduction. Its base is DOT-Obj-I, so 𝑣=𝜈(𝑥:𝑆)𝑑; intersection decomposition locates the unique definition {𝑎=𝑡}, and inversion of DOT-Def-And and DOT-Def-Val gives Γ⊢𝑡:𝑇. These are all invertible base rules, proving the four clauses. ◻
The runtime is A-normal. Evaluation contexts contain let bindings of values. The critical roots are 𝐸[𝑥𝑦]⟶𝐸[𝑡[𝑦/𝑧]]if𝐸binds𝑥=𝜆(𝑧:𝑆)𝑡,𝐸[𝑥.𝑎]⟶𝐸[𝑡]if𝐸binds𝑥=𝜈(𝑧:𝑇)𝑑and𝑑contains{𝑎=𝑡},𝐸[𝗅𝖾𝗍𝑥=𝑦𝗂𝗇𝑡]⟶𝐸[𝑡[𝑦/𝑥]].
Proof of Theorem 107.10 — Structural and safety theorem for simple DOT
Proof. For clause 1, use mutual induction on typing and subtyping. A variable case uses the narrowed declaration 𝑇′ and subsumption along 𝑇′<:𝑇. Dependent-function subtyping applies the induction hypothesis to its domain and codomain premises; alpha-rename its binder away from 𝑥 first. Recursive types and intersections apply the induction hypotheses componentwise. Selection uses lemma 107.7; all remaining rules rebuild directly. These are the binder, selection, conversion, and structural rule families, so the mutual induction is complete.
For clause 2, use mutual induction on the derivations of typing, subtyping, and precise typing. The variable equal to 𝑥 uses the supplied judgment for 𝑦; every other variable is unchanged. Under a lambda, let, recursive type, or object self binder, choose the binder outside FV(𝑦)∪FV(𝑇)∪dom(Γ) and apply the induction hypothesis to the renamed body. Application and field selection use the induction hypotheses on their subjects. Type selection commutes with substitution because paths are variables in this calculus. Intersection, recursion, and subsumption rebuild their rules. Thus every syntax and rule family is covered.
For progress, decompose a closed term as its longest evaluation context 𝐸[𝑟]. The values bound by 𝐸 determine a runtime context Γ𝐸. Each value has a precise inert type, so Γ𝐸 is inert. If 𝑟=𝑥𝑦, clauses 1–2 of theorem 107.9 show that 𝑥 is bound by 𝐸 to a lambda, and the application root applies. If 𝑟=𝑥.𝑎, clauses 3–4 show that 𝑥 is bound to an object with a unique 𝑎 definition, and the projection root applies. A let with a value applies its let root. If no such redex exists, the term is a normal form. These cases exhaust the A-normal runtime.
For preservation, use the same decomposition. In the application case, canonical forms give a lambda 𝜆(𝑧:𝑆)𝑡 and the codomain comparison; clause 2 types 𝑡[𝑦/𝑧], and subsumption gives the redex’s result type. In the projection case, precise object typing and disjoint labels give the unique definition {𝑎=𝑡} with the required field type. In the let case, clause 1 narrows the written binder type to the precise inert type of the installed value, after which clause 2 performs substitution. Rebuilding the typing derivation of 𝐸[−] preserves the outer result type. This proves clauses 4–5 and completes the theorem. ◻
★★★ Consider the application root 𝐸[𝑥𝑦]⟶𝐸[𝑡[𝑦/𝑧]]. Starting from an inert context extracted for 𝐸, use clauses 1 and 2 of theorem 107.9 to recover the lambda bound to 𝑥. State the exact variable-substitution judgment needed to type 𝑡[𝑦/𝑧], including the codomain substitution. Explain where the proof would stop if the extracted context were not inert.
The declarative rules contain transitivity, recursive typing cycles, and path-dependent selection. Soundness does not make them an algorithm. In particular, full D-subtyping with lower and upper bounds is undecidable. Kernel D-subtyping is decidable by the Step algorithm, strong-kernel D-subtyping is decidable by Stare-at, and full D-subtyping and full term typing are undecidable. The variants that retain subtyping reflection while restricting dependent-function subtyping remain open. The earlier one-direction reduction from System F with bounded quantification does not establish the undecidability result.
No theorem in this chapter states decidability of full DOT typing, subtyping, or inference. A checker for an annotated fragment would require a separate syntax-directed relation, a termination measure, and soundness and completeness proofs. The finite decision problem in the seminar checks only the inertness precondition and selection chains.
Suggested first pass.
None of these problems is a prerequisite for a later chapter. Begin with exercise 107.4, then complete exercise 107.8.
★★☆ Construct the bad-bounds collapse for two distinct closed record types 𝑆 and 𝑈. Then prove that no object definition typed by DOT-Def-Type contributes the unequal declaration {𝐴:⊤..⊥} to an inert runtime context.
★★★ Reconstruct the object-projection case of preservation. Name the precise recursive type of the object value, locate its unique field label using disjointness, and rebuild the surrounding let context.
Implement in Kappa a finite representation of dependent-function and recursive-object context entries. Check that recursive entries contain pairwise distinct field labels and only equal-bounds type members. For an accepted entry, calculate the tight selection chain 𝑇<:𝑥.𝐴<:𝑇. The invariant is that no unequal-bounds member reaches the selection calculator. The acceptance test must accept the cell context, reject {𝐴:⊤..⊥}, reject a duplicate label, print the two equal-bound selection steps, reject lookup of a missing member, and report that a dependent-function entry has no type-member selection. The named outcomes are cell context accepted, bad bounds rejected, lower tight selection printed, upper tight selection printed, missing member lookup rejected, and function entry has no member selection. A mutation that ignores the upper-bound equality must leave the Kappa source well typed but fail both the bad-bounds and unequal-bound oracles. Identify the exact DOT-T-Sel-U premise lost by that mutation.
Sources. Rapoport, Kabir, He, and Lhoták give the calculus, its Figure 2 rules, and the inert-context safety package in Lemmas 3.7–3.11 and 3.19 and Theorems 3.6 and 3.17–3.18 [RKHL17]. Rompf and Amin give the earlier rich-DOT proof [RA16]; Hu and Lhoták give the corrected D-subtyping decision boundary [HL20]. Each source proof package is shorter than ten pages and is proved locally.