The type of a method may mention the type of its receiver. This is harmless until the object is extended. Then two demands pull in opposite directions. The old code should be inherited without being rechecked, while every occurrence of the receiver type in that code should now denote the extended object. Ordinary recursive subtyping can satisfy the demand when all those occurrences are covariant. A binary method puts the receiver type in an argument position and exposes the obstruction. Heuristically, a covariant recursive record body can preserve a subtype comparison through one unfolding, whereas an antitone occurrence reverses the comparison and blocks the argument. The Point/ColorPoint pair below makes that obstruction concrete in the recursive target calculus of chapter 13.
Where the receiver type changes sign
Let the functional record operators 𝖯𝗈𝗂𝗇𝗍𝖥(𝑋):={𝑥:𝖭𝖺𝗍,clone:𝖴𝗇𝗂𝗍→𝑋,move:𝖭𝖺𝗍→𝑋},𝖢𝗈𝗅𝗈𝗋𝖯𝗈𝗂𝗇𝗍𝖥(𝑋):={𝑥:𝖭𝖺𝗍,color:𝖡𝗈𝗈𝗅,clone:𝖴𝗇𝗂𝗍→𝑋,move:𝖭𝖺𝗍→𝑋} describe the two interfaces. Define 𝖯𝗈𝗂𝗇𝗍=𝜇𝑋.𝖯𝗈𝗂𝗇𝗍𝖥(𝑋),𝖢𝗈𝗅𝗈𝗋𝖯𝗈𝗂𝗇𝗍=𝜇𝑋.𝖢𝗈𝗅𝗈𝗋𝖯𝗈𝗂𝗇𝗍𝖥(𝑋). Unlike the invariant primitive object components of chapter 13, these are immutable covariant records. The Point/ColorPoint comparison therefore succeeds here; the binary-method case below is the obstruction that remains. This opening calculation takes place specifically in the 𝐹<:𝜇 target calculus of definition 15.16; it is not a derivation in any of the three calculi defined later in this chapter. Its recursive-subtyping premise is the Amber-style premise, checked under 𝑋<:𝑌. Record width and arrow covariance in the result give 𝖢𝗈𝗅𝗈𝗋𝖯𝗈𝗂𝗇𝗍𝖥(𝑋)<:𝖯𝗈𝗂𝗇𝗍𝖥(𝑌), and hence the desired 𝖢𝗈𝗅𝗈𝗋𝖯𝗈𝗂𝗇𝗍<:𝖯𝗈𝗂𝗇𝗍. At the more precise static type, move returns 𝖢𝗈𝗅𝗈𝗋𝖯𝗈𝗂𝗇𝗍, and so does clone applied to unit. After subsumption to 𝖯𝗈𝗂𝗇𝗍, they return only 𝖯𝗈𝗂𝗇𝗍. This loss is safe: the shorter view no longer promises color. The premise that drives proposition 15.12 is absent here: that counterexample overrides a method retained through a shorter view, while this record grammar contains no update term. Subsumption therefore changes only the static view of an immutable record.
Now add an equality-like binary method: 𝖤𝗊𝖯𝗈𝗂𝗇𝗍𝖥(𝑋):={𝑥:𝖭𝖺𝗍,eq:𝑋→𝖡𝗈𝗈𝗅},𝖤𝗊𝖢𝗈𝗅𝗈𝗋𝖯𝗈𝗂𝗇𝗍𝖥(𝑌):={𝑥:𝖭𝖺𝗍,color:𝖡𝗈𝗈𝗅,eq:𝑌→𝖡𝗈𝗈𝗅}. The recursive-subtyping attempt reaches 𝑋<:𝑌⊢(𝑋→𝖡𝗈𝗈𝗅)<:(𝑌→𝖡𝗈𝗈𝗅). Arrow subtyping asks for 𝑌<:𝑋, exactly the premise we do not have. Declaring the comparison covariant would be unsound. Code in the colored method may inspect its argument’s color component, while a context that sees the receiver merely as an equality point may pass an uncolored point.
For immutable records, a receiver occurrence in a method result supports the recursive-subtyping comparison above. A receiver occurrence in a method argument reverses the required comparison. Therefore width extension and ordinary recursive subtyping do not supply the desired specialization of a binary-method argument from 𝖯𝗈𝗂𝗇𝗍 to 𝖢𝗈𝗅𝗈𝗋𝖯𝗈𝗂𝗇𝗍. For a result occurrence the new arrow premise is 𝑋<:𝑌, the recursive assumption. For an argument occurrence, arrow subtyping exchanges the domain comparison and asks instead for 𝑌<:𝑋, which width does not provide.
★☆☆ Add a method copyFrom:𝑋→𝑋 to both operators. Under the recursive assumption 𝑋<:𝑌, write both arrow-subtyping premises. Identify which one is available and which one fails. Then replace the argument type in both interfaces by the fixed type 𝖯𝗈𝗂𝗇𝗍 and repeat the calculation.
Put the changing receiver type inside the object while hiding its exact representation from clients. The calculus is intentionally functional: records never change in place, and no store occurs in its safety theorem.
Positive families and the two Self operations
For a distinguished variable 𝑋, define positive and negative occurrence simultaneously. An 𝑋-free type has both polarities; 𝑋 itself is positive; records preserve polarity componentwise; and an arrow reverses it in the domain and preserves it in the codomain. Thus 𝑋 and 𝖭𝖺𝗍→𝑋 are positive, whereas 𝑋→𝖡𝗈𝗈𝗅 is negative. We do not permit a free occurrence of the distinguished 𝑋 beneath a nested Self binder.
Proof. Induct on the type, proving the positive and negative statements simultaneously. The 𝑋 case is the given subtyping; an 𝑋-free type gives reflexivity. Records use fieldwise covariance. For an arrow 𝐴(𝑋)→𝐵(𝑋), the induction hypothesis for the domain has the reversed orientation and the hypothesis for the codomain has the direct orientation. Arrow subtyping combines exactly those two comparisons. The negative case exchanges the two induction hypotheses. ◻
This is the fragment of chapter 8 with records, arrows, 𝖳𝗈𝗉, and bounded type variables—without bounded quantifiers, 𝖡𝗈𝗍, products, or sums—extended by general recursion and two Self-specific term forms. A Self package hides its representation while retaining a public upper bound. The rules below therefore compare Self packages, introduce a hidden witness, and eliminate that witness under an escape condition. Self formation also requires the displayed payload family to be positive in its bound variable. Types, terms, and values are 𝐴,𝐵::=𝖭𝖺𝗍∣𝖡𝗈𝗈𝗅∣𝖴𝗇𝗂𝗍∣𝖳𝗈𝗉∣𝑋∣𝐴→𝐵∣{ℓ𝑖:𝐴𝑖}𝑖∈𝐼∣𝖲𝖾𝗅𝖿𝑋.{ℓ𝑖:𝐵𝑖(𝑋)}𝑖∈𝐼,𝑎,𝑏::=𝑥∣𝑛∣𝗍𝗋𝗎𝖾∣𝖿𝖺𝗅𝗌𝖾∣𝗎𝗇𝗂𝗍∣𝗌𝗎𝖼𝖼(𝑎)∣𝜆𝑥:𝐴.𝑎∣𝑎𝑏∣𝗂𝖿𝑎𝗍𝗁𝖾𝗇𝑏𝖾𝗅𝗌𝖾𝑐∣{ℓ𝑖=𝑎𝑖}𝑖∈𝐼∣𝑎.ℓ∣𝖿𝗂𝗑𝑥:𝐴.𝑎∣𝗉𝖺𝖼𝗄𝖲𝖾𝗅𝖿𝐶𝗐𝗂𝗍𝗁𝑎𝖺𝗌𝑆∣𝗎𝗌𝖾𝖲𝖾𝗅𝖿𝑎𝖺𝗌𝑋<:𝑆,𝑥:𝑅𝑆(𝑋)∣𝗎𝗌𝖾𝖲𝖾𝗅𝖿𝑎𝗂𝗇𝑏,𝑣::=𝑛∣𝗍𝗋𝗎𝖾∣𝖿𝖺𝗅𝗌𝖾∣𝗎𝗇𝗂𝗍∣𝜆𝑥:𝐴.𝑎∣{ℓ𝑖=𝑣𝑖}𝑖∈𝐼∣𝗉𝖺𝖼𝗄𝖲𝖾𝗅𝖿𝐶𝗐𝗂𝗍𝗁𝑣𝖺𝗌𝑆. Here a Self type𝑆=𝖲𝖾𝗅𝖿𝑋.𝑅𝑆(𝑋) hides the representation named by 𝑋 while exposing the public payload family 𝑅𝑆(𝑋)={ℓ𝑖:𝐵𝑖(𝑋)}𝑖∈𝐼. The labels are distinct, and every 𝐵𝑖(𝑋) is positive in 𝑋. The binder 𝑋 names the hidden representation type; opening a package substitutes its witness only for this bound type variable. It is distinct from the term variable bound by 𝖿𝗂𝗑. The intended expansion is the bounded-existential recursive type 𝖲𝖾𝗅𝖿𝑋.𝑅(𝑋):=𝜇𝑌.∃𝑋<:𝑌.𝑅(𝑋), with 𝑌∉𝖥𝖵(𝑅). We keep the two operations primitive so that their type and term substitutions remain visible. Equation (16.1) is a design explanation, not a definitional equality or a translation theorem between this primitive calculus and the target of chapter 13. The primitive rules below expose the same public bound, hidden witness, payload family, and escape condition; no result is transferred silently between the systems.
The ordinary rules are call-by-value simply typed lambda calculus, immutable covariant records, bounded type variables, and subsumption. Subtyping is the least relation closed under reflexivity, transitivity, and the following rules:
𝑋<:𝐴∈Δ
Δ⊢𝑋<:𝐴
S-Bound
Δ⊢𝐴<:𝖳𝗈𝗉
S-Top
Δ⊢𝐴′<:𝐴Δ⊢𝐵<:𝐵′
Δ⊢𝐴→𝐵<:𝐴′→𝐵′
S-Arrow
𝐽⊆𝐼Δ⊢𝐴𝑗<:𝐵𝑗(𝑗∈𝐽)
Δ⊢{ℓ𝑖:𝐴𝑖}𝑖∈𝐼<:{ℓ𝑗:𝐵𝑗}𝑗∈𝐽
S-Record
Δ,𝑋<:𝖳𝗈𝗉⊢𝑅(𝑋)<:𝑅′(𝑋)
Δ⊢𝖲𝖾𝗅𝖿𝑋.𝑅(𝑋)<:𝖲𝖾𝗅𝖿𝑋.𝑅′(𝑋)
S-Self
All types in a rule are well formed. A type context is formed from left to right; a declaration 𝑋<:𝐴 requires 𝐴 to be formed in the preceding context. Arrow and record formation require their displayed component types, and Self formation additionally requires the positive-family condition above. The complete ordinary term rules are
𝑥:𝐴∈Γ
Δ;Γ⊢𝑥:𝐴
T-Var
Δ;Γ⊢𝑛:𝖭𝖺𝗍
T-Const
𝑏∈{𝗍𝗋𝗎𝖾,𝖿𝖺𝗅𝗌𝖾}
Δ;Γ⊢𝑏:𝖡𝗈𝗈𝗅
T-Bool
Δ;Γ⊢𝗎𝗇𝗂𝗍:𝖴𝗇𝗂𝗍
T-Unit
Δ;Γ⊢𝑎:𝖭𝖺𝗍
Δ;Γ⊢𝗌𝗎𝖼𝖼(𝑎):𝖭𝖺𝗍
T-Succ
Δ;Γ,𝑥:𝐴⊢𝑎:𝐵
Δ;Γ⊢𝜆𝑥:𝐴.𝑎:𝐴→𝐵
T-Abs
Δ;Γ⊢𝑎:𝐴→𝐵Δ;Γ⊢𝑏:𝐴
Δ;Γ⊢𝑎𝑏:𝐵
T-App
Δ;Γ⊢𝑎:𝖡𝗈𝗈𝗅Δ;Γ⊢𝑏:𝐴Δ;Γ⊢𝑐:𝐴
Δ;Γ⊢𝗂𝖿𝑎𝗍𝗁𝖾𝗇𝑏𝖾𝗅𝗌𝖾𝑐:𝐴
T-If
Δ;Γ⊢𝑎𝑖:𝐴𝑖(𝑖∈𝐼)
Δ;Γ⊢{ℓ𝑖=𝑎𝑖}𝑖∈𝐼:{ℓ𝑖:𝐴𝑖}𝑖∈𝐼
T-Record
Δ;Γ⊢𝑎:{ℓ𝑖:𝐴𝑖}𝑖∈𝐼𝑗∈𝐼
Δ;Γ⊢𝑎.ℓ𝑗:𝐴𝑗
T-Proj
Δ;Γ,𝑥:𝐴⊢𝑎:𝐴
Δ;Γ⊢𝖿𝗂𝗑𝑥:𝐴.𝑎:𝐴
T-Fix
Δ;Γ⊢𝑎:𝐴Δ⊢𝐴<:𝐵
Δ;Γ⊢𝑎:𝐵
T-Sub
The Self-specific typing rules are
𝑆=𝖲𝖾𝗅𝖿𝑋.𝑅𝑆(𝑋)Δ⊢𝐶<:𝑆Δ;Γ⊢𝑎:𝑅𝑆(𝐶)
Δ;Γ⊢𝗉𝖺𝖼𝗄𝖲𝖾𝗅𝖿𝐶𝗐𝗂𝗍𝗁𝑎𝖺𝗌𝑆:𝑆
T-PackSelf
𝑆=𝖲𝖾𝗅𝖿𝑋.𝑅𝑆(𝑋)Δ;Γ⊢𝑎:𝑆Δ,𝑋<:𝑆;Γ,𝑥:𝑅𝑆(𝑋)⊢𝑏:𝐷𝑋∉𝖥𝖵(𝐷)
Δ;Γ⊢𝗎𝗌𝖾𝖲𝖾𝗅𝖿𝑎𝖺𝗌𝑋<:𝑆,𝑥:𝑅𝑆(𝑋)𝗂𝗇𝑏:𝐷
T-UseSelf
Rule T-Fix is unrestricted general recursion. Consequently this safety calculus is not normalizing: for example 𝖿𝗂𝗑𝑥:𝖭𝖺𝗍.𝗌𝗎𝖼𝖼(𝑥) has type 𝖭𝖺𝗍 and reduces forever.
The notation in equation 16.1 does not assert equi-recursive equality. Rule T-PackSelf combines bounded-existential packaging with fold; T-UseSelf combines opening with unfold. Thus the public type 𝑆, hidden witness 𝐶, and payload type 𝑅𝑆(𝐶) remain distinct.
For 𝑎:𝑆 and ℓ𝑗:𝐵𝑗(𝑋) in 𝑅𝑆(𝑋), define selection by 𝑎⋅ℓ𝑗:=𝗎𝗌𝖾𝖲𝖾𝗅𝖿𝑎𝖺𝗌𝑋<:𝑆,𝑥:𝑅𝑆(𝑋)𝗂𝗇𝑥.ℓ𝑗, where the body is subsumed from 𝐵𝑗(𝑋) to 𝐵𝑗(𝑆). This last step exists by lemma 16.3 and 𝑋<:𝑆. The result type does not contain 𝑋, so the escape condition is satisfied. This is the exact point at which the positive-family condition performs work. Selection therefore has a one-line root behavior: (𝗉𝖺𝖼𝗄𝖲𝖾𝗅𝖿𝐶𝗐𝗂𝗍𝗁𝑣𝖺𝗌𝑆0)⋅ℓ𝑗⟼𝑣.ℓ𝑗, where the step abbreviates expansion by equation 16.2 followed by (UseSelf); an ordinary projection step follows when 𝑣 is a record value.
★☆☆ Classify each family as positive, negative, both, or neither in 𝑋: 𝑋,𝖭𝖺𝗍→𝑋,𝑋→𝖡𝗈𝗈𝗅,(𝑋→𝖡𝗈𝗈𝗅)→𝖭𝖺𝗍,{𝑎:𝑋,𝑏:𝖭𝖺𝗍→𝑋}. For every positive case, write the subtyping obtained from 𝐶<:𝐷. For every rejected method family, identify the arrow premise with the wrong orientation.
Define 𝑃:=𝖲𝖾𝗅𝖿𝑋.𝖯𝗈𝗂𝗇𝗍𝖥(𝑋),𝐶:=𝖲𝖾𝗅𝖿𝑋.𝖢𝗈𝗅𝗈𝗋𝖯𝗈𝗂𝗇𝗍𝖥(𝑋). Every family is positive. Under 𝑋<:𝖳𝗈𝗉, immutable-record width gives 𝖢𝗈𝗅𝗈𝗋𝖯𝗈𝗂𝗇𝗍𝖥(𝑋)<:𝖯𝗈𝗂𝗇𝗍𝖥(𝑋); therefore S-Self derives 𝐶<:𝑃.
The following are closed terms: 𝑝0:=𝖿𝗂𝗑𝑝:𝑃.𝗉𝖺𝖼𝗄𝖲𝖾𝗅𝖿𝑃𝗐𝗂𝗍𝗁{𝑥=0,clone=𝜆𝑢:𝖴𝗇𝗂𝗍.𝑝,move=𝜆𝑑:𝖭𝖺𝗍.𝑝}𝖺𝗌𝑃,𝑐0:=𝖿𝗂𝗑𝑐:𝐶.𝗉𝖺𝖼𝗄𝖲𝖾𝗅𝖿𝐶𝗐𝗂𝗍𝗁{𝑥=0,color=𝗍𝗋𝗎𝖾,clone=𝜆𝑢:𝖴𝗇𝗂𝗍.𝑐,move=𝜆𝑑:𝖭𝖺𝗍.𝑐}𝖺𝗌𝐶. For 𝑝0, the recursion assumption 𝑝:𝑃 types the payload at 𝖯𝗈𝗂𝗇𝗍𝖥(𝑃)={𝑥:𝖭𝖺𝗍,clone:𝖴𝗇𝗂𝗍→𝑃,move:𝖭𝖺𝗍→𝑃}. By reflexivity, 𝑃<:𝑃, so T-PackSelf gives the body type 𝑃 and the recursion rule gives 𝑝0:𝑃. The derivation for 𝑐0:𝐶 has the same five steps with the additional Boolean field. It follows both that 𝑐0⋅clone:𝖴𝗇𝗂𝗍→𝐶 and, after subsuming the receiver, that (𝑐0:𝑃)⋅clone:𝖴𝗇𝗂𝗍→𝑃. Here and below (𝑎:𝐴) is a displayed elaboration cue: it means that the term 𝑎 is first used at type 𝐴 by T-Sub. It is not an additional term constructor or reduction rule.
The root contractions are (𝜆𝑥:𝐴.𝑎)𝑣⟼𝑎[𝑣/𝑥],𝗌𝗎𝖼𝖼(𝑛)⟼𝑛+1,𝗂𝖿𝗍𝗋𝗎𝖾𝗍𝗁𝖾𝗇𝑎𝖾𝗅𝗌𝖾𝑏⟼𝑎,𝗂𝖿𝖿𝖺𝗅𝗌𝖾𝗍𝗁𝖾𝗇𝑎𝖾𝗅𝗌𝖾𝑏⟼𝑏,{ℓ𝑖=𝑣𝑖}𝑖∈𝐼.ℓ𝑗⟼𝑣𝑗(𝑗∈𝐼),𝖿𝗂𝗑𝑥:𝐴.𝑎⟼𝑎[𝖿𝗂𝗑𝑥:𝐴.𝑎/𝑥],𝗎𝗌𝖾𝖲𝖾𝗅𝖿(𝗉𝖺𝖼𝗄𝖲𝖾𝗅𝖿𝐶𝗐𝗂𝗍𝗁𝑣𝖺𝗌𝑆0)𝖺𝗌𝑋<:𝑆,𝑥:𝑅𝑆(𝑋)𝗂𝗇𝑏⟼𝑏[𝐶/𝑋][𝑣/𝑥].(𝑈𝑠𝑒𝑆𝑒𝑙𝑓) Evaluation is the compatible closure under the deterministic left-to-right contexts 𝐸::=[−]∣𝗌𝗎𝖼𝖼(𝐸)∣𝐸𝑎∣𝑣𝐸∣𝗂𝖿𝐸𝗍𝗁𝖾𝗇𝑎𝖾𝗅𝗌𝖾𝑏∣𝐸.ℓ∣{ℓ1=𝑣1,…,ℓ𝑘−1=𝑣𝑘−1,ℓ𝑘=𝐸,ℓ𝑘+1=𝑎𝑘+1,…}∣𝗉𝖺𝖼𝗄𝖲𝖾𝗅𝖿𝐶𝗐𝗂𝗍𝗁𝐸𝖺𝗌𝑆∣𝗎𝗌𝖾𝖲𝖾𝗅𝖿𝐸𝖺𝗌𝑋<:𝑆,𝑥:𝑅𝑆(𝑋)𝗂𝗇𝑏. No context enters a lambda, a recursion body, or a 𝗎𝗌𝖾𝖲𝖾𝗅𝖿 body.
Put 𝑟0={𝑥=0,clone=𝜆𝑢:𝖴𝗇𝗂𝗍.𝑝0,move=𝜆𝑑:𝖭𝖺𝗍.𝑝0}. For a readable trace, abbreviate the opened clone body by 𝑢clone:=𝗎𝗌𝖾𝖲𝖾𝗅𝖿(𝗉𝖺𝖼𝗄𝖲𝖾𝗅𝖿𝑃𝗐𝗂𝗍𝗁𝑟0𝖺𝗌𝑃)𝖺𝗌𝑋<:𝑃,𝑧:𝖯𝗈𝗂𝗇𝗍𝖥(𝑋)𝗂𝗇𝑧.clone. Expanding the derived selection and taking one recursion step gives (𝑝0⋅clone)𝗎𝗇𝗂𝗍⟼∗𝑢clone𝗎𝗇𝗂𝗍𝑈𝑠𝑒𝑆𝑒𝑙𝑓⟼𝑟0.clone𝗎𝗇𝗂𝗍𝑝𝑟𝑜𝑗𝑒𝑐𝑡𝑖𝑜𝑛⟼(𝜆𝑢:𝖴𝗇𝗂𝗍.𝑝0)𝗎𝗇𝗂𝗍𝛽⟼𝑝0𝑢𝑛𝑓𝑜𝑙𝑑𝑟𝑒𝑐𝑢𝑟𝑠𝑖𝑜𝑛⟼𝗉𝖺𝖼𝗄𝖲𝖾𝗅𝖿𝑃𝗐𝗂𝗍𝗁𝑟0𝖺𝗌𝑃. The (UseSelf) step substitutes the witness type 𝑃 for the type binder 𝑋, then the payload for the term binder 𝑧. It does not substitute the recursive term 𝑝0 for 𝑋. The last step unfolds the returned fixpoint once; its result is a package value. Stopping at 𝑝0 is useful when naming the recursive object but is not a complete call-by-value reduction.
★★☆ Expand equation 16.2 and reduce (𝑐0⋅move)3 to the named recursive term 𝑐0. This requested endpoint is not a normal form: take one further fixpoint-unfolding step to display its package value. At the (UseSelf) step, display the type substitution and the term substitution separately. Give the type of every intermediate application.
The Self redex can be opened at a supertype of the package annotation. The proof must therefore recover the relation between the actual and expected families; merely observing that a package is present is insufficient.
Type weakening and term weakening hold. Moreover, if a judgment is derivable under Δ0,𝑋<:𝐴,Δ1 and Δ0⊢𝐶<:𝐴, it remains derivable under Δ0,𝑋<:𝐶,Δ1.
If a formation, subtyping, or typing judgment is derivable under Δ0,𝑋<:𝐴,Δ1 and Δ0⊢𝐶<:𝐴, then substituting 𝐶 for 𝑋 in the judgment and trailing contexts yields a derivable judgment.
Proof of Lemma 16.6 — Structural properties of Self_+
Proof. For item 1, weakening is induction on derivations after alpha-renaming every binder away from the appended declarations. For bound narrowing, the distinguished S-Bound conclusion 𝑋<:𝐴 is recovered from 𝑋<:𝐶<:𝐴 by transitivity; every other rule applies the induction hypotheses to its premises and restores the same rule.
For item 2, use simultaneous induction on formation, subtyping, and typing. The distinguished S-Bound case is the premise 𝐶<:𝐴. Records apply the hypotheses fieldwise; arrows apply them contravariantly to the domain and covariantly to the codomain. In S-Self, alpha-rename the inner Self variable away from 𝐶, substitute in the family comparison, and restore the rule. For T-PackSelf, the required family identity is (𝑅𝑆(𝐷))[𝐶/𝑋]=𝛼𝑅𝑆[𝐶/𝑋](𝐷[𝐶/𝑋]), after freshening the Self binder. The T-UseSelf case uses the same identity, substitutes in the scrutinee and body, and preserves the escape condition because the bound variable was chosen fresh.
For item 3, induct on typing. The distinguished variable case uses the assumed typing of the substituend; every other variable retains its declaration. Alpha-rename lambda and recursion binders away from the substituend. In T-PackSelf, substitute in the payload. In T-UseSelf, substitute independently in the scrutinee and, after freshening both binders, in the body; its result type and escape condition are unchanged. Records, applications, and conditionals apply the induction hypotheses to their immediate premises. These cases exhaust the term grammar. ◻
Suppose Δ⊢𝐶<:𝐴, 𝐶 is not a type variable, and the outer constructor of 𝐴 is an arrow, a record, or 𝖲𝖾𝗅𝖿. Then 𝐶 has the same outer constructor as 𝐴. Moreover, if 𝐶 is not a type variable, there is no derivation of 𝐶<:𝑋.
Proof. Prove both statements simultaneously by rule induction. Reflexivity is immediate. The arrow, record, and Self rules preserve their displayed outer constructors. Rule S-Top cannot end at any of the three target shapes. Rule S-Bound has a type variable on the left and therefore cannot be the last rule for the stated 𝐶.
For transitivity, write 𝐶<:𝐷<:𝐴. Both premises have smaller derivation height, so both simultaneous induction hypotheses are available. For the outer-shape claim, split on whether 𝐷 is a type variable. If it is, the no-nonvariable-below-variable hypothesis applied to 𝐶<:𝐷 contradicts the assumption that 𝐶 is not a variable. If it is not, the outer-shape hypothesis applied to 𝐷<:𝐴 gives 𝐷 the outer constructor of 𝐴; applying it once more to 𝐶<:𝐷 gives 𝐶 that constructor.
For the no-nonvariable-below-variable claim, the target is a variable 𝑋. Again split on 𝐷. If 𝐷 is a variable, the hypothesis for 𝐶<:𝐷 is a contradiction. If 𝐷 is not a variable, the hypothesis for 𝐷<:𝑋 is a contradiction. These two splits also cover 𝐷=𝖳𝗈𝗉, which lies in the nonvariable branch; no unproved outer-shape assertion about the intermediate is required. ◻
If Δ⊢𝑆0<:𝑆, where 𝑆0=𝖲𝖾𝗅𝖿𝑋.𝑅0(𝑋)and𝑆=𝖲𝖾𝗅𝖿𝑋.𝑅(𝑋), then, after alpha-renaming the binders to agree, Δ,𝑋<:𝖳𝗈𝗉⊢𝑅0(𝑋)<:𝑅(𝑋). Moreover, in every factorization Δ⊢𝑆0<:𝐶<:𝑆, the intermediate type 𝐶 is a Self type up to alpha-equivalence; it is not a type variable, 𝖳𝗈𝗉, an arrow, or a record.
Proof. Induct on the subtyping derivation. Reflexivity gives 𝑅0(𝑋)<:𝑅0(𝑋), and S-Self has the required family comparison as its premise. In a transitive derivation with Self type at both ends, the shape claim gives 𝐶=𝛼𝖲𝖾𝗅𝖿𝑋.𝑅1(𝑋). The two induction hypotheses give 𝑅0(𝑋)<:𝑅1(𝑋) and 𝑅1(𝑋)<:𝑅(𝑋) under 𝑋<:𝖳𝗈𝗉; transitivity gives the required comparison. Lemma 27.6 excludes a type-variable intermediate and gives the Self outer shape directly; in particular, no derivation can return from 𝖳𝗈𝗉, an arrow, or a record to a Self type. ◻
Proof. Strip final subsumption rules. The remaining value-introduction type is not a type variable, so lemma 27.6 applies to the accumulated subtype chain. At arrow type it forces an arrow introduction; the only such value rule is T-Abs, and inversion returns 𝑣=𝜆𝑥:𝐶.𝑎. At record type it forces T-Record, which returns a record value with one typed field for every label in the conclusion. At Self type it forces T-PackSelf; lemma 16.7 gives 𝑆0<:𝑆, and inversion of T-PackSelf gives 𝐶<:𝑆0 and 𝑤:𝑅0(𝐶). ◻
Proof. Induct on the reduction derivation. Compatible cases rebuild their typing rule after applying the induction hypothesis to the active subterm. Beta and recursion use term substitution. Record projection and the ground roots follow by inversion.
It remains to prove the generalized (UseSelf) root. Suppose the actual package annotation is 𝑆0=𝖲𝖾𝗅𝖿𝑋.𝑅0(𝑋), while the use is checked at 𝑆=𝖲𝖾𝗅𝖿𝑋.𝑅(𝑋). Typing inversion through final subsumption is an induction on the typing derivation: T-PackSelf gives the witness and payload judgments, and each T-Sub composes one more subtype step. Hence 𝐶<:𝑆0,𝑣:𝑅0(𝐶),𝑆0<:𝑆. By lemma 16.7, 𝑋<:𝖳𝗈𝗉⊢𝑅0(𝑋)<:𝑅(𝑋). Type substitution with the well-formed type 𝐶 gives 𝑅0(𝐶)<:𝑅(𝐶), so subsumption yields 𝑣:𝑅(𝐶). The body premise is Δ,𝑋<:𝑆;Γ,𝑥:𝑅(𝑋)⊢𝑏:𝐷,𝑋∉𝖥𝖵(𝐷). Since 𝐶<:𝑆0<:𝑆, type substitution gives Δ;Γ,𝑥:𝑅(𝐶)⊢𝑏[𝐶/𝑋]:𝐷. Term substitution then gives Δ;Γ⊢𝑏[𝐶/𝑋][𝑣/𝑥]:𝐷, precisely the reduct. Thus the actual hidden witness, not the public annotation, controls the contraction. ◻
★★☆ Assume 𝐶<:𝑆0<:𝑆1<:𝑆 and a package created at 𝑆0 is opened by a use checked at 𝑆. Reconstruct the (UseSelf) preservation case, including the two applications of transitivity, Self-family inversion, type substitution, payload subsumption, and term substitution. Explain why replacing the runtime witness 𝐶 by the public type 𝑆 is invalid.
Proof of Theorem 16.10 — Progress and functional safety
Proof. Induct on typing after removing final subsumption. Variables are impossible in the empty term context. Introduction forms are values after their left-to-right subterms become values. For application, the function steps, the argument steps, or lemma 16.8 proves that the function is a lambda and beta applies. The conditional and projection cases use the Boolean and record canonical forms. A recursion term always unfolds.
For 𝗎𝗌𝖾𝖲𝖾𝗅𝖿𝑎𝖺𝗌⋯, the induction hypothesis says that 𝑎 steps or is a value. In the latter case, the Self canonical form proves that 𝑎 is an actual package, so (UseSelf) applies even when its annotation is a proper subtype of the type expected by the use. These cases exhaust the grammar. Preservation keeps the same type along every finite reduction sequence, and progress applies to its last term. ◻
Why negative Self is rejected
The family 𝖡𝖺𝖽𝖤𝗊(𝑋)={𝑥:𝖭𝖺𝗍,eq:𝑋→𝖡𝗈𝗈𝗅} does not form a 𝖲𝖾𝗅𝖿+ type. To see the operational reason, consider the hypothetical calculus obtained by deleting only the positivity check. Put 𝑃𝐸:=𝖲𝖾𝗅𝖿𝑋.{𝑥:𝖭𝖺𝗍,eq:𝑋→𝖡𝗈𝗈𝗅},𝐶𝐸:=𝖲𝖾𝗅𝖿𝑋.{𝑥:𝖭𝖺𝗍,color:𝖡𝗈𝗈𝗅,eq:𝑋→𝖡𝗈𝗈𝗅},𝑝𝐸:=𝗉𝖺𝖼𝗄𝖲𝖾𝗅𝖿𝑃𝐸𝗐𝗂𝗍𝗁{𝑥=0,eq=𝜆𝑞:𝑃𝐸.𝖿𝖺𝗅𝗌𝖾}𝖺𝗌𝑃𝐸,𝑐𝐸:=𝗉𝖺𝖼𝗄𝖲𝖾𝗅𝖿𝐶𝐸𝗐𝗂𝗍𝗁{𝑥=0,color=𝗍𝗋𝗎𝖾,eq=𝜆𝑞:𝐶𝐸.𝑞⋅color}𝖺𝗌𝐶𝐸. The record-family premise of S-Self would indeed compare the two same-parameter fields 𝑋→𝖡𝗈𝗈𝗅<:𝑋→𝖡𝗈𝗈𝗅; width would then give 𝐶𝐸<:𝑃𝐸. That pointwise width calculation is not the error. The error is using the hidden bound 𝑋<:𝑃𝐸 at selection time to turn 𝑋→𝖡𝗈𝗈𝗅 into 𝑃𝐸→𝖡𝗈𝗈𝗅. Arrow subtyping gives the opposite comparison, 𝑃𝐸→𝖡𝗈𝗈𝗅<:𝑋→𝖡𝗈𝗈𝗅, and supplies no such coercion.
If the bad coercion is inserted, the closed term 𝑒𝐸:=((𝑐𝐸:𝑃𝐸)⋅eq)𝑝𝐸:𝖡𝗈𝗈𝗅 has the following reduction. Expanding the first derived selection and opening the colored package yields 𝑒𝐸𝑈𝑠𝑒𝑆𝑒𝑙𝑓⟼∗(𝜆𝑞:𝐶𝐸.𝑞⋅color)𝑝𝐸⟼𝑝𝐸⋅color⟼∗{𝑥=0,eq=𝜆𝑞:𝑃𝐸.𝖿𝖺𝗅𝗌𝖾}.color. The last term is neither a value nor a redex. The displayed packages show that the failure is not merely a failed proof of preservation. Rejecting the negative occurrence rules this stuck program out; admitting it would type the program just reduced.
★☆☆ Replace the Boolean result of eq by {𝑜𝑘:𝖡𝗈𝗈𝗅}, repeat the bad reduction above, and mark the one selection coercion that cannot be derived in 𝖲𝖾𝗅𝖿+. Explain why the pointwise record-width premise of S-Self is not itself that coercion.
Primitive covariant Self therefore handles clone-like and other self-returning methods. It does not handle a binary method whose argument was obtained independently of the receiver. Inside one open package, a method can consume another value of the same hidden witness if one is available; two separately opened packages need not choose the same witness. Matching addresses inheritance of such code by changing the relation on the one-step record families, not by weakening this safety condition.
F-bounds describe fluent code
The failed subtype judgment does not prevent us from writing one piece of code for every type that supports the same chain of methods returning that type; this is the sense of fluent used here. The bound must mention the type being bounded. This section changes calculi. Its recursive types are equi-recursive comparison types, not the iso-recursive package expansion of equation 16.1. Here equi-recursive means that a recursive type and its one-step unfolding are definitionally equal. No term-level fold or unfold is required; iso-recursive types instead keep the two types distinct and cross between them with explicit terms, as in chapter 12.
The types have bounded quantifiers, immutable records, arrows, and recursion. In 𝜇𝑋.𝐴, every occurrence of 𝑋 must lie beneath a record; call this condition contractiveness. Type equality contains alpha-equivalence and 𝜇𝑋.𝐴=𝐴[𝜇𝑋.𝐴/𝑋]. Formation, typing, and subtyping are closed under replacement by definitionally equal types. Subtyping, taken modulo this equality, is the least relation closed under reflexivity, transitivity, bounded-variable, arrow, and record subtyping. Equivalently, before applying a structural subtyping rule one may unfold either recursive type any finite number of times. There are no term-level fold and unfold operations in 𝖥eq.
An F-bound is a recursive upper bound 𝑋<:𝐹(𝑋) whose bound expression may mention the variable being bounded. F-bounded types and terms are ∀𝑋<:𝐹(𝑋).𝐴,Λ𝑋<:𝐹(𝑋).𝑎,𝑎[𝐶]. Call the one-step record family 𝐹(−) the object’s protocol: the record-shaped interface that an implementation must support. The binder 𝑋 ranges over client-chosen implementations of this protocol, and type application substitutes its argument only for that bound parameter. The bound is formed by checking 𝐹(𝑋) under 𝑋<:𝖳𝗈𝗉. The rules particular to the extension are
Δ,𝑋<:𝐹(𝑋)⊢𝐴𝗍𝗒𝗉𝖾
Δ⊢∀𝑋<:𝐹(𝑋).𝐴𝗍𝗒𝗉𝖾
F-All
Δ,𝑋<:𝐹(𝑋);Γ⊢𝑎:𝐴
Δ;Γ⊢Λ𝑋<:𝐹(𝑋).𝑎:∀𝑋<:𝐹(𝑋).𝐴
F-Intro
Δ;Γ⊢𝑎:∀𝑋<:𝐹(𝑋).𝐴Δ⊢𝐶<:𝐹(𝐶)
Δ;Γ⊢𝑎[𝐶]:𝐴[𝐶/𝑋]
F-Elim
Type application contracts by (Λ𝑋<:𝐹(𝑋).𝑎)[𝐶]⟼𝑎[𝐶/𝑋].
The calculus validates formation, typing of the displayed clients, and preservation of the type-application root. Equality and subtyping of its equi-recursive types are declarative here.
Call a type 𝐶 a post-fixpoint of 𝐹 when 𝐶<:𝐹(𝐶). Equi-recursive conversion proves concrete inequalities 𝐶<:𝐹(𝐶), and an F-bound says which of them may instantiate a given client. Neither choice adds a primitive Self package.
Put moveAll:=Λ𝑋<:𝖯𝗈𝗂𝗇𝗍𝖥(𝑋).𝜆𝑝:𝑋.𝜆𝑑:𝖭𝖺𝗍.𝑝.move𝑑. Under 𝑋<:𝖯𝗈𝗂𝗇𝗍𝖥(𝑋), subsumption gives 𝑝:𝖯𝗈𝗂𝗇𝗍𝖥(𝑋), hence 𝑝.move:𝖭𝖺𝗍→𝑋. Thus moveAll:∀𝑋<:𝖯𝗈𝗂𝗇𝗍𝖥(𝑋).𝑋→𝖭𝖺𝗍→𝑋. Any type 𝐶 satisfying 𝐶<:𝖯𝗈𝗂𝗇𝗍𝖥(𝐶) may instantiate this term, and the result remains 𝐶. This is the fluent use of an F-bound.
Here is a concrete legal instantiation. Define 𝖯𝗈𝗂𝗇𝗍eq:=𝜇𝑋.𝖯𝗈𝗂𝗇𝗍𝖥(𝑋). The two separate judgments needed are then available: 𝖯𝗈𝗂𝗇𝗍eq(21.3)=𝖯𝗈𝗂𝗇𝗍𝖥(𝖯𝗈𝗂𝗇𝗍eq),𝖯𝗈𝗂𝗇𝗍eq𝑟𝑒𝑓𝑙𝑒𝑥𝑖𝑣𝑖𝑡𝑦<:𝖯𝗈𝗂𝗇𝗍eq(21.3)=𝖯𝗈𝗂𝗇𝗍𝖥(𝖯𝗈𝗂𝗇𝗍eq). Therefore F-Elim derives moveAll[𝖯𝗈𝗂𝗇𝗍eq]:𝖯𝗈𝗂𝗇𝗍eq→𝖭𝖺𝗍→𝖯𝗈𝗂𝗇𝗍eq. This derivation would be incomplete in an iso-recursive calculus: there an explicit term fold cannot be replaced by a subtype premise. The familiar Java pattern 𝑇𝖾𝗑𝗍𝖾𝗇𝖽𝗌𝖢𝗈𝗆𝗉𝖺𝗋𝖺𝖻𝗅𝖾⟨𝑇⟩ has the same F-bound shape: the client chooses one 𝑇, and the bound mentions that very 𝑇 in its protocol.
Proof. Induct simultaneously on formation, subtyping, and typing. The distinguished bound-variable case is exactly the assumption 𝐶<:𝐹(𝐶). In an arrow, record, or application rule, substitute in every premise and restore the same rule. At a nested type binder, alpha-rename it away from 𝐶, apply the induction hypothesis, and restore the binder. The term-variable cases merely substitute in their declared types.
For equi-recursive conversion, choose the recursive binder 𝑌 distinct from 𝑋 and fresh for 𝐶. Substitution commutes with unfolding by the composition equation (𝐴[𝜇𝑌.𝐴/𝑌])[𝐶/𝑋]=𝛼𝐴[𝐶/𝑋][𝜇𝑌.𝐴[𝐶/𝑋]/𝑌], same binder-fresh induction as lemma 24.2. The induction is rerun for the 𝖥eq grammar: records, bounded quantifiers, and their term annotations add componentwise congruence cases. Thus a converted premise remains definitionally equal to the substituted conclusion; the congruence cases commute homomorphically with substitution. Applying the result to the premise of F-Intro gives the type of 𝑎[𝐶/𝑋], which is the reduct. ◻
F-bounds can also type a homogeneous binary operation. With 𝖤𝗊𝖥(𝑋):={𝑥:𝖭𝖺𝗍,eq:𝑋→𝖡𝗈𝗈𝗅}, the term Λ𝑋<:𝖤𝗊𝖥(𝑋).𝜆𝑝:𝑋.𝜆𝑞:𝑋.𝑝.eq𝑞 has type ∀𝑋<:𝖤𝗊𝖥(𝑋).𝑋→𝑋→𝖡𝗈𝗈𝗅. The two arguments have one chosen type 𝑋, so the contravariant occurrence causes no coercion. What F-bounded quantification does not prove is substitutability between the recursive binary-method types 𝖤𝗊𝖯𝗈𝗂𝗇𝗍eq:=𝜇𝑋.𝖤𝗊𝖥(𝑋),𝖤𝗊𝖢𝗈𝗅𝗈𝗋𝖯𝗈𝗂𝗇𝗍eq:=𝜇𝑋.{𝑥:𝖭𝖺𝗍,color:𝖡𝗈𝗈𝗅,eq:𝑋→𝖡𝗈𝗈𝗅}. Unfolding a proposed subtype comparison reverses the equality-method domain and asks for 𝖤𝗊𝖯𝗈𝗂𝗇𝗍eq<:𝖤𝗊𝖢𝗈𝗅𝗈𝗋𝖯𝗈𝗂𝗇𝗍eq, which record width cannot supply. F-bounds parameterize the client; they do not turn protocol extension into subsumption.
What an F-bound forgets about a Self package
For this comparison, let 𝑅 range only over the positive families generated by the common grammar 𝐿(𝑋)::=𝖭𝖺𝗍∣𝖡𝗈𝗈𝗅∣𝖴𝗇𝗂𝗍∣𝖳𝗈𝗉∣𝑋∣𝐿(𝑋)→𝐿(𝑋)∣{ℓ𝑖:𝐿𝑖(𝑋)}𝑖∈𝐼,𝑅(𝑋)::={ℓ𝑖:𝐿𝑖(𝑋)}𝑖∈𝐼. Only 𝑋 may occur free. There is no primitive Self, recursive type, or bounded quantifier inside an 𝐿. The outer record makes 𝑅 contractive, so the same 𝑅 is legal in 𝖲𝖾𝗅𝖿+ and beneath 𝜇 in 𝖥eq.
The two calculi agree on one construction and part company on another. For such a family 𝑅, form 𝑆=𝖲𝖾𝗅𝖿𝑋.𝑅(𝑋),̂𝑆=𝜇𝑋.𝑅(𝑋)in𝖥eq. On the F-bounded side, a record at the public witness ̂𝑆 has payload type 𝑅(̂𝑆)=̂𝑆, so it is a legal post-fixpoint. An F-bounded client ∀𝑋<:𝑅(𝑋).𝐷(𝑋) may therefore be instantiated at ̂𝑆. This is the public-witness fragment of primitive Self.
The general T-PackSelf premise is different: 𝐶<:𝑆,𝑐:𝑅(𝐶)⟹𝗉𝖺𝖼𝗄𝖲𝖾𝗅𝖿𝐶𝗐𝗂𝗍𝗁𝑐𝖺𝗌𝑆:𝑆. Erasing this package to ̂𝑆 would require a term of 𝑅(̂𝑆). The payload premise has type 𝑅(𝐶), not 𝑅(̂𝑆); moreover the package deliberately hides 𝐶. Revealing that witness, or replacing it everywhere by ̂𝑆, destroys the representation abstraction implemented by the bounded existential. Thus the public-witness construction is not a rulewise translation of primitive Self.
For a concrete instance, take 𝑅(𝑋)={next:𝑋},𝑆=𝖲𝖾𝗅𝖿𝑋.𝑅(𝑋),𝐶=𝖲𝖾𝗅𝖿𝑋.{next:𝑋,tag:𝖭𝖺𝗍}. Record width and S-Self give 𝐶<:𝑆. A recursive package 𝑐𝐶:𝐶 with payload {next=𝑐𝐶,tag=0} yields, by T-PackSelf, a second package at 𝑆 whose hidden witness is 𝐶 and whose payload is {next=𝑐𝐶}:𝑅(𝐶). The premise contains no judgment 𝐶<:̂𝑆, where ̂𝑆=𝜇𝑋.{next:𝑋} belongs to the distinct comparison calculus. Hence no premise derives a payload of type 𝑅(̂𝑆). This is a specific witness to the boundary, not merely a statement about notation.
The converse comparison loses a different property. An F-bounded client may quantify over the negative family 𝖤𝗊𝖥, because it assumes one homogeneous type 𝑋 and performs no coercion between distinct post-fixpoints. Primitive 𝖲𝖾𝗅𝖿+ admits first-class packages and covariant package subsumption, but rejects that negative family. Hence neither presentation contains the other: F-bounds lose hidden-witness packaging, while the positive Self calculus deliberately gives up binary Self selection.
For a positive contractive record family 𝑅, ̂𝑆=𝜇𝑋.𝑅(𝑋) is a legal instantiation of every 𝖥eq client bounded by 𝑅. The premises of T-PackSelf do not, in general, derive a payload at 𝑅(̂𝑆), and so do not define an erasure of every 𝖲𝖾𝗅𝖿+ package to ̂𝑆.
Proof of Proposition 21.12 — Boundary of the public-witness comparison
Proof. The first assertion is equation 21.3 followed by reflexivity and F-Elim. For the second, take the legal package of example 27.13, with hidden witness 𝐶<:𝑆. Its only payload judgment is 𝑐:𝑅(𝐶). Positivity can transport a payload along a proved subtype 𝐶<:̂𝑆, but the package premise is 𝐶<:𝑆, where 𝑆 is a 𝖲𝖾𝗅𝖿+ type and ̂𝑆 is an 𝖥eq type. No judgment form of either calculus contains types from both grammars, so no rule relates these two types. Consequently the required transport is absent. Adding it would expose precisely the representation relation that the existential hides. ◻
★★☆ Define 𝖱𝖾𝗌𝖾𝗍𝖥(𝑋)={𝑥:𝖭𝖺𝗍,reset:𝑋,same:𝑋→𝖡𝗈𝗈𝗅}. Give a complete typing derivation for a polymorphic term that takes 𝑝:𝑋, invokes reset, and compares the result with 𝑝. State why the derivation does not imply a subtype relation between two different post-fixpoints of 𝖱𝖾𝗌𝖾𝗍𝖥. Then instantiate it at 𝜇𝑋.𝖱𝖾𝗌𝖾𝗍𝖥(𝑋), displaying equi-recursive conversion and subtyping as two separate judgments.
Matching compares object types by their protocols before the recursive knot is tied. We make that sentence literal in a small higher-order target. The target is fixed here because a translation into an unnamed higher-kinded language would not be a theorem.
Kinds are 𝜅::=∗∣∗⇒∗. Type operators and proper types are 𝐹,𝐺::=Φ∣𝜆𝑋:∗.𝐴,𝐴,𝐵::=𝑋∣𝖭𝖺𝗍∣𝖡𝗈𝗈𝗅∣𝖴𝗇𝗂𝗍∣𝐴→𝐵∣{ℓ𝑖:𝐴𝑖}𝑖∈𝐼∣𝐹(𝐴)∣𝜇𝐹∣∀Φ⪯𝐹.𝐴. Kinds classify type-level expressions. The kind ∗ contains ordinary types such as 𝖭𝖺𝗍 and records; the kind ∗⇒∗ contains unary functions from ordinary types to ordinary types. For example, 𝜆𝑋:∗.{𝑛:𝖭𝖺𝗍,max:𝑋→𝑋} has kind ∗⇒∗, and applying it to 𝖭𝖺𝗍:∗ produces the proper record type {𝑛:𝖭𝖺𝗍,max:𝖭𝖺𝗍→𝖭𝖺𝗍}:∗. Operator beta is definitional equality: (𝜆𝑋:∗.𝐴)(𝐵)=𝐴[𝐵/𝑋], and type formation and subtyping are closed under this equality. Target terms extend the ordinary lambda-and-record terms by 𝑡::=⋯∣ΛΦ⪯𝐹.𝑡∣𝑡[𝐹]∣𝖿𝗈𝗅𝖽𝐹(𝑡)∣𝗎𝗇𝖿𝗈𝗅𝖽𝐹(𝑡),𝑣::=⋯∣ΛΦ⪯𝐹.𝑡∣𝖿𝗈𝗅𝖽𝐹(𝑣). An operator context contains 𝑋:∗ and Φ⪯𝐹:∗⇒∗. Every operator variable in such a declaration is stipulated contractive, and its bound must be contractive. In this restricted target, 𝜆𝑋:∗.𝐴 is contractive exactly when every occurrence of 𝑋 lies beneath a record constructor; operator variables declared contractive are contractive. Proper-type subtyping has reflexivity and transitivity together with the ordinary arrow and record rules:
Ω⊢𝐴′<:𝐴Ω⊢𝐵<:𝐵′
Ω⊢𝐴→𝐵<:𝐴′→𝐵′
S-H-Arrow
𝐽⊆𝐼Ω⊢𝐴𝑗<:𝐵𝑗(𝑗∈𝐽)
Ω⊢{ℓ𝑖:𝐴𝑖}𝑖∈𝐼<:{ℓ𝑗:𝐵𝑗}𝑗∈𝐽
S-H-Record
The ordinary target term rules are
𝑥:𝐴∈Γ
Ω;Γ⊢𝑥:𝐴
T-H-Var
Ω;Γ,𝑥:𝐴⊢𝑡:𝐵
Ω;Γ⊢𝜆𝑥:𝐴.𝑡:𝐴→𝐵
T-H-Abs
Ω;Γ⊢𝑡:𝐴→𝐵Ω;Γ⊢𝑢:𝐴
Ω;Γ⊢𝑡𝑢:𝐵
T-H-App
Ω;Γ⊢𝑡𝑖:𝐴𝑖(𝑖∈𝐼)
Ω;Γ⊢{ℓ𝑖=𝑡𝑖}𝑖∈𝐼:{ℓ𝑖:𝐴𝑖}𝑖∈𝐼
T-H-Record
Ω;Γ⊢𝑡:{ℓ𝑖:𝐴𝑖}𝑖∈𝐼𝑗∈𝐼
Ω;Γ⊢𝑡.ℓ𝑗:𝐴𝑗
T-H-Proj
Ω;Γ⊢𝑡:𝐴Ω⊢𝐴<:𝐵
Ω;Γ⊢𝑡:𝐵
T-H-Sub
The rules particular to higher-order operators and recursion are
Ω,𝑋:∗⊢𝐴:∗
Ω⊢𝜆𝑋:∗.𝐴:∗⇒∗
K-OpAbs
Ω⊢𝐹:∗⇒∗Ω⊢𝐴:∗
Ω⊢𝐹(𝐴):∗
K-OpApp
Ω⊢𝐹:∗⇒∗Contr(𝐹)
Ω⊢𝜇𝐹:∗
K-Mu
Ω,𝑋:∗⊢𝐹(𝑋)<:𝐺(𝑋)𝑋∉𝖥𝖵(Ω,𝐹,𝐺)
Ω⊢𝐹⪯𝐺
S-OpPoint
Φ⪯𝐹:∗⇒∗∈Ω
Ω⊢Φ⪯𝐹
S-OpBound
Ω⊢𝐹⪯𝐺Ω⊢𝐴:∗
Ω⊢𝐹(𝐴)<:𝐺(𝐴)
S-OpApp
Operator subtyping also has reflexivity and transitivity. Bounded operator quantification and iso-recursion have the rules
Ω⊢𝐹:∗⇒∗Contr(𝐹)Ω,Φ⪯𝐹:∗⇒∗⊢𝐴:∗
Ω⊢∀Φ⪯𝐹.𝐴:∗
K-AllOp
Ω,Φ⪯𝐹;Γ⊢𝑡:𝐴
Ω;Γ⊢ΛΦ⪯𝐹.𝑡:∀Φ⪯𝐹.𝐴
T-AllOp-I
Ω;Γ⊢𝑡:∀Φ⪯𝐹.𝐴Ω⊢𝐺:∗⇒∗Contr(𝐺)Ω⊢𝐺⪯𝐹
Ω;Γ⊢𝑡[𝐺]:𝐴[𝐺/Φ]
T-AllOp-E
Ω;Γ⊢𝑡:𝐹(𝜇𝐹)
Ω;Γ⊢𝖿𝗈𝗅𝖽𝐹(𝑡):𝜇𝐹
T-Fold
Ω;Γ⊢𝑡:𝜇𝐹
Ω;Γ⊢𝗎𝗇𝖿𝗈𝗅𝖽𝐹(𝑡):𝐹(𝜇𝐹)
T-Unfold
Here annotations on operator bounds include their kind even when suppressed typographically. The new call-by-value roots are (ΛΦ⪯𝐹.𝑡)[𝐺]⟼𝑡[𝐺/Φ],𝗎𝗇𝖿𝗈𝗅𝖽𝐹(𝖿𝗈𝗅𝖽𝐹(𝑣))⟼𝑣. The new evaluation contexts are 𝐸::=⋯∣𝐸[𝐹]∣𝖿𝗈𝗅𝖽𝐹(𝐸)∣𝗎𝗇𝖿𝗈𝗅𝖽𝐹(𝐸). Thus 𝜇𝐹 in 𝖧𝜇 is iso-recursive; it is not the equi-recursive 𝜇 of 𝖥eq.
The ordinary target rules have an immediate complete use before the operator translation begins. Put 𝑅={𝑛:𝖭𝖺𝗍}. Under 𝑥:𝖭𝖺𝗍, its lines are ⋅;𝑥:𝖭𝖺𝗍⊢𝑥:𝖭𝖺𝗍byT-H-Var,⋅;𝑥:𝖭𝖺𝗍⊢{𝑛=𝑥}:𝑅byT-H-Record,⋅;𝑥:𝖭𝖺𝗍,𝑟:𝑅⊢𝑟:𝑅byT-H-Var,⋅;𝑥:𝖭𝖺𝗍,𝑟:𝑅⊢𝑟.𝑛:𝖭𝖺𝗍byT-H-Proj,⋅;𝑥:𝖭𝖺𝗍⊢𝜆𝑟:𝑅.𝑟.𝑛:𝑅→𝖭𝖺𝗍byT-H-Abs,⋅;𝑥:𝖭𝖺𝗍⊢(𝜆𝑟:𝑅.𝑟.𝑛){𝑛=𝑥}:𝖭𝖺𝗍byT-H-App. Match abstraction uses T-AllOp-I, bounded instantiation uses T-AllOp-E, and exposure of a recursive protocol uses T-Unfold.
The translation has exactly the following source domain. Source protocols and their target images use the same Self-free family grammar 𝐿::=𝖭𝖺𝗍∣𝖡𝗈𝗈𝗅∣𝖴𝗇𝗂𝗍∣𝑍∣𝐿→𝐿∣{ℓ𝑖:𝐿𝑖}𝑖∈𝐼,𝑅(𝑍)::={ℓ𝑖:𝐿𝑖(𝑍)}𝑖∈𝐼. Every 𝑅 is contractive in 𝑍. The remaining source grammar is 𝑂::=𝑋∣𝜇𝑍.𝑅(𝑍),𝐷::=𝖭𝖺𝗍∣𝖡𝗈𝗈𝗅∣𝖴𝗇𝗂𝗍∣𝑂∣𝐷→𝐷∣∀𝑋#𝑂.𝐷,𝑡::=𝑥∣𝜆𝑥:𝐷.𝑡∣𝑡𝑡∣Λ𝑋#𝑂.𝑡∣𝑡[𝑂]∣𝑥.ℓ. Source contexts are Ξ::=⋅∣Ξ,𝑋#𝑂,Γ::=⋅∣Γ,𝑥:𝐷. In 𝑋#𝑂, the binder 𝑋 ranges over types whose protocols extend the protocol of 𝑂; instantiation substitutes only for this match-bound variable. The recursive binder of a concrete protocol remains the separate variable 𝑍 in 𝜇𝑍.𝑅(𝑍). The matching assumption does not assert 𝑋<:𝑂. The judgment Ξ;Γ⊢𝑡:𝐷 is generated by
𝑥:𝐷∈Γ
Ξ;Γ⊢𝑥:𝐷
T-Match-Var
Ξ;Γ,𝑥:𝐷⊢𝑡:𝐸
Ξ;Γ⊢𝜆𝑥:𝐷.𝑡:𝐷→𝐸
T-Match-Abs
Ξ;Γ⊢𝑡:𝐷→𝐸Ξ;Γ⊢𝑢:𝐷
Ξ;Γ⊢𝑡𝑢:𝐸
T-Match-App
Ξ,𝑋#𝑂;Γ⊢𝑡:𝐷
Ξ;Γ⊢Λ𝑋#𝑂.𝑡:∀𝑋#𝑂.𝐷
T-Match-I
Ξ;Γ⊢𝑡:∀𝑋#𝑂.𝐷Ξ⊢𝐶#𝑂
Ξ;Γ⊢𝑡[𝐶]:𝐷[𝐶/𝑋]
T-Match-E
𝑋#𝜇𝑍.𝑅(𝑍)∈Ξ𝑥:𝑋∈Γ𝑅(𝑋)(ℓ)=𝐷
Ξ;Γ⊢𝑥.ℓ:𝐷
T-Match-Proj
Here 𝑅(𝑋)(ℓ)=𝐷 means that the record protocol 𝑅(𝑋) contains the field ℓ:𝐷. Thus selection is admitted only when the receiver is a match-bound variable and the bound protocol displays the label. The source fragment has no object constructor, so theorem 16.15 covers protocol-polymorphic client code only. The target fold below constructs an example target object; it is not the translation of any source literal.
Translate source contexts from left to right. The translation is indexed by that context: beneath 𝑋#𝑂, the source variable 𝑋 denotes 𝜇Φ𝑋. The translation is defined by the clauses Oper(𝑋)=Φ𝑋,Oper(𝜇𝑍.𝑅(𝑍))=𝜆𝑍:∗.𝑅†(𝑍),𝑋†=𝜇Φ𝑋,(𝜇𝑍.𝑅(𝑍))†=𝜇(𝜆𝑍:∗.𝑅†(𝑍)),(∀𝑋#𝑂.𝐷)†=∀Φ𝑋⪯Oper(𝑂).𝐷†,(Λ𝑋#𝑂.𝑡)†=ΛΦ𝑋⪯Oper(𝑂).𝑡†,(𝑡[𝐶])†=𝑡†[Oper(𝐶)],(𝑥.ℓ)†=(𝗎𝗇𝖿𝗈𝗅𝖽Φ𝑋(𝑥)).ℓ. Ground, arrow, variable, abstraction, and application clauses are homomorphic. The context clauses are ⋅†=⋅,(Ξ,𝑋#𝑂)†=Ξ†,Φ𝑋⪯Oper(𝑂):∗⇒∗. Define Ξ⊢𝐴#𝐵⟺Ξ†⊢Oper(𝐴)⪯Oper(𝐵). This is protocol comparison. In particular, matching and value typing do not combine to give subsumption: 𝑎:𝐴,𝐴#𝐵⟹̸𝑎:𝐵.
Proof of Proposition 16.14 — Reflexivity and transitivity of matching
Proof. The translated operators have kind ∗⇒∗. Operator reflexivity gives Oper(𝐴)⪯Oper(𝐴), including the case 𝐴=𝑋, where this is Φ𝑋⪯Φ𝑋. For transitivity, compose the two translated operator judgments using transitivity in 𝖧𝜇. No value-typing judgment occurs in either proof. ◻
Consider the source types 𝖬𝖺𝗑:=𝜇𝑋.{𝑛:𝖭𝖺𝗍,max:𝑋→𝑋},𝖬𝗂𝗇𝖬𝖺𝗑:=𝜇𝑌.{𝑛:𝖭𝖺𝗍,max:𝑌→𝑌,min:𝑌→𝑌}. Their translated operators are 𝖬𝖺𝗑𝖮𝗉:=𝜆𝑋:∗.{𝑛:𝖭𝖺𝗍,max:𝑋→𝑋},𝖬𝗂𝗇𝖬𝖺𝗑𝖮𝗉:=𝜆𝑌:∗.{𝑛:𝖭𝖺𝗍,max:𝑌→𝑌,min:𝑌→𝑌}. The target fold rule now constructs an actual object. Put 𝑟max={𝑛=0,max=𝜆𝑞:𝜇𝖬𝖺𝗑𝖮𝗉.𝑞}. The annotated lambda has type 𝜇𝖬𝖺𝗑𝖮𝗉→𝜇𝖬𝖺𝗑𝖮𝗉, hence 𝑟max:𝖬𝖺𝗑𝖮𝗉(𝜇𝖬𝖺𝗑𝖮𝗉),𝑚max:=𝖿𝗈𝗅𝖽𝖬𝖺𝗑𝖮𝗉(𝑟max):𝜇𝖬𝖺𝗑𝖮𝗉. Since 𝑟max is a value, the explicit destructor computes: 𝗎𝗇𝖿𝗈𝗅𝖽𝖬𝖺𝗑𝖮𝗉(𝑚max)⟼𝑟max. For arbitrary 𝑍:∗, record width gives 𝖬𝗂𝗇𝖬𝖺𝗑𝖮𝗉(𝑍)<:𝖬𝖺𝗑𝖮𝗉(𝑍). Thus S-OpPoint derives 𝖬𝗂𝗇𝖬𝖺𝗑𝖮𝗉⪯𝖬𝖺𝗑𝖮𝗉, and hence 𝖬𝗂𝗇𝖬𝖺𝗑#𝖬𝖺𝗑. Recursive subtyping would instead compare 𝑋→𝑋 with 𝑌→𝑌 under only 𝑋<:𝑌, and fail at the contravariant premise.
Now suppose Φ𝑋⪯𝖬𝖺𝗑𝖮𝗉 and put 𝑋†=𝜇Φ𝑋, consistently with definition 16.13. The field derivation keeps typing and subtyping as separate judgments: 𝗎𝗇𝖿𝗈𝗅𝖽Φ𝑋(𝑥)𝑇−𝑈𝑛𝑓𝑜𝑙𝑑:Φ𝑋(𝑋†),Φ𝑋(𝑋†)𝑆−𝑂𝑝𝐴𝑝𝑝<:𝖬𝖺𝗑𝖮𝗉(𝑋†),𝗎𝗇𝖿𝗈𝗅𝖽Φ𝑋(𝑥)𝑇−𝐻−𝑆𝑢𝑏:{𝑛:𝖭𝖺𝗍,max:𝑋†→𝑋†},(𝗎𝗇𝖿𝗈𝗅𝖽Φ𝑋(𝑥)).max𝑇−𝐻−𝑃𝑟𝑜𝑗:𝑋†→𝑋†. Consequently the translated client is preMax:=Λ𝑋#𝖬𝖺𝗑.𝜆𝑝:𝑋.𝜆𝑞:𝑋.𝑝.max𝑞,preMax†:=ΛΦ𝑋⪯𝖬𝖺𝗑𝖮𝗉.𝜆𝑝:𝜇Φ𝑋.𝜆𝑞:𝜇Φ𝑋.(𝗎𝗇𝖿𝗈𝗅𝖽Φ𝑋(𝑝)).max𝑞,preMax†:∀Φ𝑋⪯𝖬𝖺𝗑𝖮𝗉.𝜇Φ𝑋→𝜇Φ𝑋→𝜇Φ𝑋. It can be instantiated with 𝖬𝖺𝗑𝖮𝗉 or 𝖬𝗂𝗇𝖬𝖺𝗑𝖮𝗉. In the second case both arguments and the result have type 𝜇𝖬𝗂𝗇𝖬𝖺𝗑𝖮𝗉; no value is coerced to 𝜇𝖬𝖺𝗑𝖮𝗉. For an end-to-end target calculation, instantiate at 𝖬𝖺𝗑𝖮𝗉 and use the object constructed above: 𝑢max:=preMax†[𝖬𝖺𝗑𝖮𝗉]𝑚max𝑚max,(𝗎𝗇𝖿𝗈𝗅𝖽𝖬𝖺𝗑𝖮𝗉𝑢max).𝑛⟼∗(𝗎𝗇𝖿𝗈𝗅𝖽𝖬𝖺𝗑𝖮𝗉𝑚max).𝑛⟼𝑟max.𝑛⟼0. Inside the first multistep, the translated client unfolds its first argument, selects max, and applies 𝜆𝑞.𝑞 to the second argument. Thus the protocol-polymorphic client and the target object compute together, not merely in separate typing derivations.
Proof of Theorem 16.15 — Soundness of the operator reading
Proof. For item 1, induct on 𝑂. A variable uses its translated context declaration. For 𝜇𝑍.𝑅(𝑍), translate each field type under 𝑍:∗, apply K-OpAbs, use the source contractiveness condition, and apply K-Mu. A bound extends the context only after the operator on its right has been checked, so bounded operator formation applies from left to right.
For item 2, match abstraction translates to T-AllOp-I. If 𝐶#𝑂, the definition of matching gives Oper(𝐶)⪯Oper(𝑂), exactly the second subtyping premise of T-AllOp-E; item 1 proves that both operators have kind ∗⇒∗ and are contractive. Finally, if the source bound exposes a field ℓ:𝐿(𝑋), T-Unfold gives the payload type Φ𝑋(𝜇Φ𝑋); S-OpApp instantiates the operator bound at 𝜇Φ𝑋; term subsumption gives the protocol record; projection gives 𝐿†(𝜇Φ𝑋). These are precisely the four judgments displayed above for max. No source subsumption rule has been used. ◻
★★☆ Add min:𝑋→𝑋 and a Boolean field marked to a third object operator 𝖬𝖺𝗋𝗄𝖾𝖽𝖬𝗂𝗇𝖬𝖺𝗑𝖥(𝑋), and define 𝖬𝖺𝗋𝗄𝖾𝖽𝖬𝗂𝗇𝖬𝖺𝗑=𝜇𝑋.𝖬𝖺𝗋𝗄𝖾𝖽𝖬𝗂𝗇𝖬𝖺𝗑𝖥(𝑋). Prove pointwise that 𝖬𝖺𝗋𝗄𝖾𝖽𝖬𝗂𝗇𝖬𝖺𝗑#𝖬𝗂𝗇𝖬𝖺𝗑#𝖬𝖺𝗑, and then use transitivity. Instantiate preMax at 𝖬𝖺𝗋𝗄𝖾𝖽𝖬𝗂𝗇𝖬𝖺𝗑, writing the exact argument and result types.
★★☆ In the deliberately restricted source, the monomorphic expression 𝜆𝑝:𝖬𝖺𝗑.𝑝.𝑛 is not admitted: field selection is available only through a match-bound variable. Define instead 𝑔=Λ𝑋#𝖬𝖺𝗑.𝜆𝑝:𝑋.𝑝.𝑛. Type 𝑔, instantiate it at 𝖬𝗂𝗇𝖬𝖺𝗑, and give the translated derivation: unfold, use subsumption, then project. Finally explain why this construction still provides no coercion from an independently supplied 𝑚:𝖬𝗂𝗇𝖬𝖺𝗑 to 𝖬𝖺𝗑.
In the equi-recursive comparison calculus, the tempting first-order reading is 𝐴#𝐵by𝐴<:Oper(𝐵)(𝐴),∀𝑋#𝐵.𝐷(𝑋)by∀𝑋<:Oper(𝐵)(𝑋).𝐷(𝑋). It explains the moveAll and homogeneous preMax examples. It does not translate a cascading bound ∀𝑋#𝐴.∀𝑌#𝑋.𝐷, because an ordinary type variable 𝑋 has no syntactically determined Oper(𝑋). Worse, its induced relation is not transitive in general. For example, with 𝐴=𝜇𝑋.{𝑝:𝑋→𝖭𝖺𝗍,𝑞:𝖭𝖺𝗍},𝐵=𝜇𝑋.{𝑝:𝑋→𝖭𝖺𝗍},𝐷=𝜇𝑋.{𝑝:𝐵→𝖭𝖺𝗍}, use the following abbreviations for the one-step body and matching test: F𝑄(𝑍)=𝑅𝑄(𝑍)when𝑄=𝜇𝑋.𝑅𝑄(𝑋),𝑃#eq𝑄⟺𝑃<:F𝑄(𝑃). This is meta-level substitution inside 𝖥eq, not the matching translation Oper(−) of definition 16.13. The three calculations are 𝐴#eq𝐵⟺𝐴<:{𝑝:𝐴→𝖭𝖺𝗍},𝐵#eq𝐷⟺𝐵<:{𝑝:𝐵→𝖭𝖺𝗍},𝐴#eq𝐷⟺𝐴<:{𝑝:𝐵→𝖭𝖺𝗍}. The first holds after unfolding 𝐴 and dropping 𝑞; the second holds after unfolding 𝐵. The third would require 𝐴→𝖭𝖺𝗍<:𝐵→𝖭𝖺𝗍, hence 𝐵<:𝐴, but unfolded 𝐵 lacks 𝑞. It therefore fails. More sharply, equi-recursive conversion gives 𝐷={𝑝:𝐵→𝖭𝖺𝗍}=𝐵. Thus #eq is not even well defined on equi-recursive types: replacing 𝐵 by the definitionally equal 𝐷 changes the answer. On fixed presentations the preceding calculations also exhibit the attempted transitivity failure. Neither defect is a failure of ordinary subtype transitivity.
The higher-order reading instead translates ∀𝑋#𝐴.𝐷(𝑋)to∀Φ𝑋⪯Oper(𝐴).𝐷(𝜇Φ𝑋). It retains the protocol as an operator, so a second bound may compare a new operator with Φ𝑋. Reflexivity and transitivity are then inherited from pointwise operator subtyping. The price is explicit higher-kinded abstraction and explicit fold/unfold at terms. The source paper discusses a broader interpretation, but theorem 16.15 proves only the displayed restricted fragment; no end-to-end theorem is imported.
Finer boundary: mutation needs a store theorem
Theorem 16.9, Theorem 16.10 quantify over the heap-free 𝖲𝖾𝗅𝖿+ dynamics, so it has no alias invariant. To state the mutation boundary, extend 𝖲𝖾𝗅𝖿+ with 𝖱𝖾𝖿𝐴, location values ℓ, and terms 𝗋𝖾𝖿𝑎, !𝑎, and 𝑎:=𝑏. Reference types are invariant: the only subtyping between 𝖱𝖾𝖿𝐴 and 𝖱𝖾𝖿𝐵 comes from 𝐴=𝐵. Extend the polarity grammar by declaring 𝖱𝖾𝖿𝐴 positive or negative in 𝑋 only when 𝑋∉𝖥𝖵(𝐴). Correspondingly, extend the value grammar by 𝑣::=⋯∣ℓ. The typing rules are
Δ;Σ;Γ⊢𝑎:𝐴
Δ;Σ;Γ⊢𝗋𝖾𝖿𝑎:𝖱𝖾𝖿𝐴
T-Ref
Δ;Σ;Γ⊢𝑎:𝖱𝖾𝖿𝐴
Δ;Σ;Γ⊢!𝑎:𝐴
T-Deref
Δ;Σ;Γ⊢𝑎:𝖱𝖾𝖿𝐴Δ;Σ;Γ⊢𝑏:𝐴
Δ;Σ;Γ⊢𝑎:=𝑏:𝖴𝗇𝗂𝗍
T-Assign
Σ(ℓ)=𝐴
Δ;Σ;Γ⊢ℓ:𝖱𝖾𝖿𝐴
T-Loc
The uniform judgment is Δ;Σ;Γ⊢𝑎:𝐴: Δ contains type-variable bounds, Σ assigns closed types to locations, and Γ assigns types to term variables. Every functional rule is lifted by carrying the same Σ through its premises.
A store 𝜎 maps locations to closed values. Its invariant is Σ⊧𝜎⟺dom(Σ)=dom(𝜎)and⋅;Σ;⋅⊢𝜎(ℓ):Σ(ℓ)foreveryℓ. Later the chapter also writes 𝜎⊧𝑛𝑊 for semantic heap satisfaction and 𝛾⊧𝑛𝜃,𝑊Γ for semantic environment satisfaction. The three source macros ⊧, ⊧, and ⊧ deliberately print the same relation glyph, but their arguments identify the judgment: store typing has Σ on the left and 𝜎 on the right; heap satisfaction has 𝜎 on the left and carries an index; environment satisfaction has 𝛾 on the left and carries both closing data and an index. Configuration reduction adds the roots ⟨𝜎,𝗋𝖾𝖿𝑣⟩𝑎𝑙𝑙𝑜𝑐𝑎𝑡𝑖𝑜𝑛⟼⟨𝜎[ℓ↦𝑣],ℓ⟩(ℓ∉dom(𝜎)),⟨𝜎,!ℓ⟩⟼⟨𝜎,𝜎(ℓ)⟩,⟨𝜎,ℓ:=𝑣⟩⟼⟨𝜎[ℓ↦𝑣],𝗎𝗇𝗂𝗍⟩, Besides the contexts of definition 16.5, configuration reduction uses 𝐸::=⋯∣𝗋𝖾𝖿𝐸∣!𝐸∣𝐸:=𝑎∣ℓ:=𝐸. Thus the location and then the assigned value are evaluated before assignment contracts.
Proof. The typing statement is induction on the derivation. Rule T-Loc uses preservation of old bindings; every other rule restores its conclusion after applying the induction hypotheses. For the store statement, the new domains agree, the fresh cell has the assumed type, and the old cells retain their types by the typing statement. ◻
Proof of Theorem 21.17 — Configuration preservation
Proof. Induct on the configuration reduction. For allocation, inversion gives 𝑣:𝐴0. Choose fresh ℓ, set Σ′=Σ,ℓ:𝐴0, and use T-Loc for the result. The new store clause and all old clauses follow from lemma 27.19.
For dereference, typing and reference canonical forms give Σ(ℓ)=𝐴0. The store invariant gives ⋅;Σ;⋅⊢𝜎(ℓ):𝐴0, which is the type of the reduct. For assignment, inversion gives 𝑣:𝐴0 at the same invariant cell type Σ(ℓ)=𝐴0. Replacing only 𝜎(ℓ) therefore preserves every clause of equation 16.3; the result is unit.
In a context step, the induction hypothesis gives Σ′⊇Σ. Lemma 27.19 retypes the inactive subterms and the context’s typing rule is rebuilt. This covers 𝗋𝖾𝖿𝐸, !𝐸, 𝐸:=𝑎, ℓ:=𝐸, and every functional context in definition 16.5.
The functional roots leave the store fixed. Beta and recursion use term substitution. Projection and ground computation use typing inversion. For a generalized Self-open root, write the runtime annotation as 𝑆0=𝖲𝖾𝗅𝖿𝑋.𝑅0(𝑋) and the expected annotation as 𝑆=𝖲𝖾𝗅𝖿𝑋.𝑅(𝑋). Inversion gives 𝐶<:𝑆0<:𝑆,𝑣:𝑅0(𝐶),𝑋<:𝑆,𝑥:𝑅(𝑋)⊢𝑏:𝐷. Self-subtyping inversion and type substitution give 𝑅0(𝐶)<:𝑅(𝐶); subsumption gives 𝑣:𝑅(𝐶). Substituting 𝐶 for the escaping-free 𝑋, then 𝑣 for 𝑥, types 𝑏[𝐶/𝑋][𝑣/𝑥]:𝐷. Thus the store theorem contains its own Self-open case rather than importing the functional conclusion. ◻
Proof. Induct on typing after stripping final subsumption. The functional cases follow the same canonical-form analysis as theorem 16.10: a function value is a lambda, a record value has the projected field, a Self value is a package, and a fixpoint always unfolds. These facts are reproved under Σ by induction on value typing; locations add no inhabitant of an arrow, record, or Self type.
For 𝗋𝖾𝖿𝑎, either 𝑎 steps in the allocation context or it is a value and the fresh-location root applies. For !𝑎, either 𝑎 steps or reference canonical forms give a location ℓ. Its typing says ℓ∈dom(Σ), and the store invariant equates the domains, so the dereference root applies. Assignment first steps its left term, then its right term; when both are values, the left is a location in the store and the assignment root applies. These cases exhaust the extended grammar. ◻
If Σ⊧𝜎 and ⋅;Σ;⋅⊢𝑎:𝐴, every finite reduction from ⟨𝜎,𝑎⟩ preserves type 𝐴, satisfies an extending store typing, and cannot end in a stuck configuration.
For a small aliasing calculation, put 𝐾=𝖲𝖾𝗅𝖿𝑋.{contents:𝖱𝖾𝖿𝖭𝖺𝗍,set:𝖭𝖺𝗍→𝑋}. After allocating 𝑟=𝗋𝖾𝖿0, define 𝑘𝑟=𝖿𝗂𝗑𝑘:𝐾.𝗉𝖺𝖼𝗄𝖲𝖾𝗅𝖿𝐾𝗐𝗂𝗍𝗁{contents=𝑟,set=𝜆𝑛:𝖭𝖺𝗍.(𝜆𝑢:𝖴𝗇𝗂𝗍.𝑘)(𝑟:=𝑛)}𝖺𝗌𝐾. The family is positive in 𝑋, and 𝖱𝖾𝖿𝖭𝖺𝗍 is independent of 𝑋. The following trace is a concrete instance of the preservation and progress theorems. Allocation gives ⟨⋅,𝗋𝖾𝖿0⟩⟼⟨{ℓ↦0},ℓ⟩,Σ1={ℓ:𝖭𝖺𝗍},Σ1⊧{ℓ↦0}. Write 𝑘ℓ for the displayed package with 𝑟=ℓ. We write that same package twice, 𝑎1:=𝑘ℓ and 𝑎2:=𝑘ℓ, only to mark its two use sites; both aliases contain the same location ℓ. The term 𝐵2:=𝜆𝑢:𝐾.!(𝑎2⋅contents):𝐾→𝖭𝖺𝗍,𝑒12:=𝐵2((𝑎1⋅set)7):𝖭𝖺𝗍. has the configuration trace ⟨{ℓ↦0},𝑒12⟩𝑜𝑝𝑒𝑛𝑆𝑒𝑙𝑓𝑎𝑛𝑑𝑝𝑟𝑜𝑗𝑒𝑐𝑡𝑠𝑒𝑡⟼∗⟨{ℓ↦0},𝐵2((𝜆𝑢:𝖴𝗇𝗂𝗍.𝑘ℓ)(ℓ:=7))⟩⟼⟨{ℓ↦7},𝐵2((𝜆𝑢:𝖴𝗇𝗂𝗍.𝑘ℓ)𝗎𝗇𝗂𝗍)⟩𝛽𝑎𝑛𝑑𝑈𝑠𝑒𝑆𝑒𝑙𝑓⟼∗⟨{ℓ↦7},!ℓ⟩𝑑𝑒𝑟𝑒𝑓𝑒𝑟𝑒𝑛𝑐𝑒⟼⟨{ℓ↦7},7⟩. The first multi-step opens 𝑎1 and selects set. The first displayed root is assignment; then beta returns the exact receiver. The outer beta deliberately discards its parameter 𝑢; opening 𝑎2 selects the same location, and dereference reads 7. Both stores satisfy Σ1 because their sole contents have type 𝖭𝖺𝗍. An attempted update ℓ:=𝗍𝗋𝗎𝖾 is rejected by T-Assign before reduction.
A field 𝖱𝖾𝖿𝑋 would be invariant in 𝑋, not positive, and is therefore outside S-Self. The fragment therefore models objects that share cells of receiver-independent data, such as counters, flags, and handles. It cannot directly model a mutable linked structure whose cell stores another value of the exact receiver type; that requires a richer invariant or guarded treatment of 𝖱𝖾𝖿𝑋.
A step-indexed model for Self with references
The unindexed semantic-world attempt is circular. If a world stores the semantic promise at each location, 𝑊(ℓ)=V[[𝐴]]𝜃(𝑊), then defining the value relation already quantifies over worlds whose entries are instances of that same, not-yet-defined relation. There is no smaller type or world on the recursive call. Two repairs break the cycle: worlds store closed syntactic types rather than predicates, and interpreting a stored type may appeal only at a strictly smaller natural-number index.
The syntactic theorem tracks a type at each location. The semantic model tracks the behavior promised by that type at every smaller number of future steps. This second proof is independent of the functional proof and of the equi-recursive comparison calculus.
A step index𝑛 is a natural-number budget: a claim at 𝑛 may appeal recursively only to claims at smaller budgets. A world records the closed type promised by every allocated location, and a later world may add locations without changing old promises. A logical relation interprets each type as the values and expressions that honor those promises; heap satisfaction says that the current store realizes its world’s promises. The strict decrease in 𝑛 breaks the circularity among recursive Self values, references, and heaps. The earlier syntactic theorem already proves no-stuck safety for closed programs. This second theorem is not needed to repeat that conclusion; it additionally validates the open-term substitution principle and the recursive semantic interpretation used for aliasing.
A closing type substitution 𝜃 respects a context Δ when it is built from left to right and, for each declaration 𝑋<:𝐴, chooses a closed type 𝐶=𝜃(𝑋) satisfying ⋅⊢𝐶<:𝐴[𝜃]. A world 𝑊 is a finite map from locations to closed, well-formed syntactic types. Write 𝑊′⪰𝑊 when dom(𝑊)⊆dom(𝑊′) and 𝑊′(ℓ)=𝑊(ℓ) at every old location. Thus worlds contain no semantic types and their construction is noncircular. The printed order marks for ⪰ and the earlier operator bound ⪯ are not converses: world extension compares finite maps, whereas operator bounding compares type operators. Their source macros and operand sorts remain distinct.
For a type 𝐴 whose variables are closed by 𝜃, let V[[𝐴]]𝜃(𝑊,𝑛) be its set of related closed values. Equivalently, interpret the closed syntactic type 𝐴[𝜃]. The ground and top clauses are V[[𝖭𝖺𝗍]]𝜃(𝑊,𝑛)={0,1,2,…},V[[𝖡𝗈𝗈𝗅]]𝜃(𝑊,𝑛)={𝗍𝗋𝗎𝖾,𝖿𝖺𝗅𝗌𝖾},V[[𝖴𝗇𝗂𝗍]]𝜃(𝑊,𝑛)={𝗎𝗇𝗂𝗍},V[[𝖳𝗈𝗉]]𝜃(𝑊,𝑛)={𝑣∣𝑣isaclosedvalue}. Records contain exactly the values with every required field related at index 𝑛: V[[{ℓ𝑖:𝐴𝑖}𝑖∈𝐼]]𝜃(𝑊,𝑛)={{ℓ𝑗=𝑣𝑗}𝑗∈𝐽∣𝐼⊆𝐽,𝑣𝑖∈V[[𝐴𝑖]]𝜃(𝑊,𝑛)for𝑖∈𝐼}. The arrow and reference clauses are V[[𝐴→𝐵]]𝜃(𝑊,𝑛)={𝜆𝑥:𝐶.𝑎∣forall𝑗<𝑛,𝑊′⪰𝑊,𝑣∈V[[𝐴]]𝜃(𝑊′,𝑗)⟹𝑎[𝑣/𝑥]∈E[[𝐵]]𝜃(𝑊′,𝑗)},V[[𝖱𝖾𝖿𝐴]]𝜃(𝑊,𝑛)={ℓ∣ℓ∈dom(𝑊),𝑊(ℓ)=𝐴𝜃}. The equality in equation 21.5 is equality of closed syntactic types, not equality of semantic predicates.
For 𝑆=𝖲𝖾𝗅𝖿𝑋.𝑅(𝑋), define V[[𝑆]]𝜃(𝑊,𝑛)={𝗉𝖺𝖼𝗄𝖲𝖾𝗅𝖿𝐶𝗐𝗂𝗍𝗁𝑣𝖺𝗌𝑆0∣⋅⊢𝑆0<:𝑆𝜃,⋅⊢𝐶<:𝑆0,𝑣∈V[[𝑅0(𝐶)]]⋅(𝑊,𝑗)forevery𝑗<𝑛}. Here 𝐶,𝑆0, and the family 𝑅0 displayed by 𝑆0 are closed. The value and expression interpretations are defined simultaneously by the lexicographic measure (𝑛,|𝐴|,𝜌),𝖵<𝖤, where 𝜌 records the value or expression phase. A record component decreases |𝐴| at the same index. Arrow bodies and Self payloads decrease the index. The expression clause below may call the value clause at the same index when 𝑘=0, but then it decreases the phase from 𝖤 to 𝖵. Reference and ground clauses do not recurse. Thus every semantic call decreases the displayed measure.
Heap satisfaction now reads the closed type stored in the world: 𝜎⊧𝑛𝑊⟺{dom(𝜎)=dom(𝑊),𝜎(ℓ)∈V[[𝑊(ℓ)]]⋅(𝑊,𝑗)(ℓ∈dom(𝑊),𝑗<𝑛). The strict index again guards a cell whose closed syntactic type may contain Self or references.
A closed expression belongs to E[[𝐴]]𝜃(𝑊,𝑛) when, for every 𝑊′⪰𝑊, 𝑗≤𝑛, 𝑘<𝑗, and 𝜎⊧𝑗𝑊′, ⟨𝜎,𝑎⟩⟼𝑘⟨𝜎′,𝑎′⟩with𝑎′irreducible implies that some 𝑊″⪰𝑊′ satisfies 𝜎′⊧𝑗−𝑘𝑊″,𝑎′∈V[[𝐴]]𝜃(𝑊″,𝑗−𝑘).(𝑇𝑒𝑟𝑚) In particular, a related irreducible expression is a value.
Write 𝑊⊩Σ𝜃 when dom(Σ)⊆dom(𝑊),𝑊(ℓ)=Σ(ℓ)𝜃(ℓ∈dom(Σ)). For a closed store typing, 𝑊⊩Σ abbreviates the empty closing substitution. Thus 𝑊′⪰𝑊 and 𝑊⊩Σ𝜃 imply 𝑊′⊩Σ𝜃. This realization judgment permits extra allocated locations; heap satisfaction in equation 21.7 still requires exact agreement among the domains of the heap and its world. An expression substitution 𝛾 satisfies Γ at (𝜃,𝑊,𝑛), written 𝛾⊧𝑛𝜃,𝑊Γ, when it maps each 𝑥:𝐴 to a closed expression 𝛾(𝑥)∈E[[𝐴]]𝜃(𝑊,𝑛). The images need not already be values. This choice is essential for the recursive term case below: extending the environment for a fixpoint maps its variable to the reducible fix term itself, whose first unfolding is consumed at a smaller index.
The value and expression relations are downward closed in the index and monotone under syntactic-world extension. If Δ⊢𝐴<:𝐵 and 𝜃 respects Δ, then ⋅⊢𝐴𝜃<:𝐵𝜃,V[[𝐴]]𝜃(𝑊,𝑛)⊆V[[𝐵]]𝜃(𝑊,𝑛). The same inclusion holds for E.
Proof of Lemma 21.22 — Closing substitution and semantic subtyping
Proof. The first judgment is simultaneous closing substitution on formation and subtyping. In the distinguished bound case, it is exactly the premise ⋅⊢𝜃(𝑋)<:𝐴𝜃 in the definition of a respecting substitution. Arrow, record, and Self rules apply the induction hypotheses; binders are alpha-renamed before substitution.
For the semantic inclusion, induct on subtyping. The ground cases are reflexive and 𝖳𝗈𝗉 contains every closed value. Records discard fields. Arrows reverse the domain inclusion and preserve the codomain inclusion. References have no nonreflexive structural subtyping. In the Self case, a package admitted on the left has a closed annotation 𝑆0<:𝑆1𝜃; closing the rule premise gives 𝑆1𝜃<:𝑆2𝜃. Transitivity gives 𝑆0<:𝑆2𝜃, so the same witness and smaller-index payload satisfy equation 21.6 on the right. The expression inclusion replaces the last value membership in equation Term. Downward closure is induction in the lexicographic measure (𝑛,|𝐴|,𝜌) of definition 21.21; record clauses use the smaller type, arrow and Self clauses use the smaller index, and the expression clause uses the smaller phase when its residual index is unchanged. World monotonicity is proved in the same induction and uses exact agreement on old syntactic bindings, especially in equation 21.5. ◻
Proof. Take a test at 𝑗≤𝑛+1. The reducible term 𝑎 cannot satisfy the irreducibility premise in zero steps. Every terminating test therefore first takes the displayed root and has at most 𝑗−1≤𝑛 steps left. Downward closure places 𝑎′ at index 𝑗−1; applying its expression clause to the residual trace yields heap satisfaction and value membership at exactly the required residual index. ◻
Proof of Lemma 27.27 — Compatibility of the reference forms
Proof. Fix a future-world and heap test. For allocation, the premise runs the initializer to a related value 𝑣. Extend the world and heap by a fresh ℓ↦𝐴𝜃 and ℓ↦𝑣. Downward closure supplies the cell invariant at every smaller residual index, and equation 21.5 relates the returned location.
For dereference, the premise runs to a location ℓ. Its reference clause gives 𝑊(ℓ)=𝐴𝜃, and heap satisfaction supplies the stored value at every smaller index consumed by the dereference root. For assignment, run the left expression to such an ℓ, then the right expression to a related value. Replacing the cell preserves every other heap clause and the exact type at ℓ; the root returns 𝗎𝗇𝗂𝗍. In each case the sum of the premise steps and the one root step is the tested budget, so the residual index in equation Term is unchanged. ◻
Suppose Δ;Σ;Γ⊢𝑎:𝐴 is derivable using the 𝖲𝖾𝗅𝖿+, reference, and recursion rules of this section. For every index 𝑛, syntactic world 𝑊, closing substitution 𝜃, and expression substitution 𝛾, if 𝜃respectsΔ,𝑊⊩Σ𝜃,𝛾⊧𝑛𝜃,𝑊Γ, then 𝑎𝜃𝛾∈E[[𝐴]]𝜃(𝑊,𝑛).
Proof of Theorem 21.23 — Fundamental theorem for the imperative Self fragment
Proof.Base forms. Use outer induction on 𝑛, and inside it induction on the typing derivation. At index zero the expression relation has no 𝑘<𝑗≤0 test. Variables use the expression-related 𝛾. Records, projection, conditionals, and ground operations use their displayed value clauses. Subsumption uses lemma 21.22.
Functions. For abstraction, take 𝑗<𝑛, a future world 𝑊′⪰𝑊, and an argument 𝑣∈V[[𝐴]]𝜃(𝑊′,𝑗). Downward closure and world monotonicity give 𝛾⊧𝑗𝜃,𝑊′Γ; a related value is also a related expression, so extending by 𝑥↦𝑣 satisfies Γ,𝑥:𝐴 there. Moreover, future-world stability gives 𝑊′⊩Σ𝜃. Apply the outer index hypothesis at 𝑗 to the body derivation. This is not the inner derivation hypothesis at index 𝑛. Its conclusion is the arrow-clause obligation. Application composes the arrow and expression clauses.
Recursion. The recursion case is the reason for the order of induction. Let 𝑓=𝖿𝗂𝗑𝑥:𝐴𝜃.𝑎𝜃𝛾. To prove 𝑓∈E[[𝐴]]𝜃(𝑊,𝑛), consider a test at 𝑗≤𝑛. The term 𝑓 is reducible, and its first step is 𝑓⟼(𝑎𝜃𝛾)[𝑓/𝑥]. At the smaller index 𝑗−1<𝑛, the outer induction hypothesis applied to the T-Fix derivation gives 𝑓∈E[[𝐴]]𝜃(𝑊′,𝑗−1). Hence 𝛾[𝑥↦𝑓] satisfies the body context at that index. Apply the outer hypothesis again, now to the body derivation Γ,𝑥:𝐴⊢𝑎:𝐴. Its conclusion relates the displayed reduct, and lemma 27.26 absorbs the initial step. This proves fix compatibility without assuming the result at the same index.
Self packages. For T-PackSelf, closing substitution first gives ⋅⊢𝐶𝜃<:𝑆𝜃. The inner induction hypothesis places the payload expression in E[[𝑅(𝐶)]]𝜃(𝑊,𝑛), where 𝑅(𝐶)𝜃=𝑅𝜃(𝐶𝜃). Consider any irreducible trace of the whole package. The evaluation context 𝗉𝖺𝖼𝗄𝖲𝖾𝗅𝖿𝐶𝜃𝗐𝗂𝗍𝗁𝐸𝖺𝗌𝑆𝜃 runs the payload to a value 𝑣; a package with a reducible payload is not irreducible. The payload expression clause supplies 𝑣∈V[[𝑅𝜃(𝐶𝜃)]]⋅(𝑊′,𝑞) at the residual index 𝑞. Downward closure supplies the same membership at every 𝑖<𝑞. Hence the resulting package value, annotated by the closed type 𝑆𝜃, satisfies equation 21.6 by reflexivity and the closed witness premise. This proves expression membership for the package; it does not treat a reducible payload as a value-related one.
Self opening. For T-UseSelf, fix a test at index 𝑗 and run the related scrutinee for 𝑟 steps until it produces 𝗉𝖺𝖼𝗄𝖲𝖾𝗅𝖿𝐶𝗐𝗂𝗍𝗁𝑣𝖺𝗌𝑆0. The Self value clause gives ⋅⊢𝐶<:𝑆0<:𝑆𝜃 and 𝑣∈V[[𝑅0(𝐶)]]⋅ at every remaining smaller index. Self-subtyping inversion, with binders alpha-renamed to agree, gives 𝑋<:𝖳𝗈𝗉⊢𝑅0(𝑋)<:𝑅𝜃(𝑋). Closing this judgment by [𝐶/𝑋] gives ⋅⊢𝑅0(𝐶)<:𝑅𝜃(𝐶), so semantic subtyping relates the actual payload at the family expected by the body. Extend the closing substitution by 𝑋↦𝐶; it respects 𝑋<:𝑆 because 𝐶<:𝑆0<:𝑆𝜃. After the Self-open root the body has budget 𝑞=𝑗−𝑟−1. If its residual trace has 𝑠 steps, the original test has 𝑘=𝑟+1+𝑠<𝑗,𝑠<𝑞,𝑞−𝑠=𝑗−𝑘. The Self value clause supplies the payload at 𝑞<𝑗−𝑟. Extend 𝛾 by 𝑥↦𝑣, apply the outer index hypothesis at 𝑞 to the body, and use 𝑋∉𝖥𝖵(𝐷) to remove the extension from the result type. This is the closing type substitution performed by the operational Self-open root.
References and worlds. The allocation, dereference, and assignment cases apply the three clauses of lemma 27.27 to their induction hypotheses. The construction in that lemma extends 𝑊 only for allocation, so it also preserves 𝑊⊩Σ𝜃.
Representative compatible contexts. For application, split a terminating trace into 𝑟1 steps evaluating the function to a related lambda, 𝑟2 steps evaluating the argument to a related value, one beta step, and 𝑟3 body steps. If the test starts at 𝑗, put 𝑞=𝑗−𝑟1 and 𝑠=𝑞−𝑟2. From 𝑟1+𝑟2+1+𝑟3<𝑗 the displayed inequality and the definitions of 𝑞,𝑠 give 𝑠=𝑗−𝑟1−𝑟2>1+𝑟3. The arrow value clause may therefore be instantiated at 𝑠−1 in the current future world; its expression conclusion handles the 𝑟3-step body trace and returns index 𝑗−(𝑟1+𝑟2+1+𝑟3).
For projection, split 𝑟 receiver steps from the one projection root. The record value clause relates the selected field at index 𝑗−𝑟; downward closure places it at 𝑗−𝑟−1, the index left by the root. For record construction, induct on the ordered field list. If the active field consumes 𝑟𝑖 steps, subtract 𝑟𝑖 from the current budget, use its expression hypothesis at that residual index, and use downward closure for every already evaluated field; the list induction preserves the invariant that the sum of the consumed field budgets plus the remaining budget is 𝑗. For a conditional, split 𝑟 guard steps from its one branch-selection root. Canonical forms makes the guard either 𝗍𝗋𝗎𝖾 or 𝖿𝖺𝗅𝗌𝖾; choose exactly the corresponding branch hypothesis at index 𝑗−𝑟−1, leaving the unchosen branch unused. Self-package and Self-open contexts use the explicit arguments above. The reference contexts are precisely lemma 27.27. These are all evaluation contexts in the grammar, so the future-world quantifier composes the induction hypotheses without an unexamined context case. ◻
Proof. Apply theorem 21.23 with empty substitutions at index 𝑘+1, and use equation Term with the given heap. It produces an extending world 𝑊′ for which 𝑎′∈V[[𝐴]]⋅(𝑊′,1). Every defining clause of V[[𝐴]]⋅ contains only syntactic values: ground constants, lambdas, record values, locations, or Self packages with value payloads. Hence 𝑎′ is a value. ◻
★★☆ Start from the empty store, allocate the cell used by 𝑘𝑟, and reduce (𝜆𝑢:𝐾.!(𝑎2⋅contents))((𝑘𝑟⋅set)7), through every compatible-context and root step. Display the store after allocation and assignment, and check equation 16.3 at both points. Explain why assigning a Boolean is rejected before reduction.
OO 𝖲𝖾𝗅𝖿 in this chapter is the hidden representation binder of equation 16.1. It is not the term receiver passed to a method, the recursive variable of an ordinary 𝜇-type, or a match-bound protocol variable. Likewise, 𝐴#𝐵 says that 𝐴’s protocol extends 𝐵’s; it is not a subtyping judgment. In particular, no typing rule derives Γ⊢𝑎:𝐵 from Γ⊢𝑎:𝐴 and 𝐴#𝐵. The primitive Self core uses pack/open iso-recursion; 𝖥eq uses equi-recursive type conversion; and 𝖧𝜇 uses explicit term fold/unfold. An equation or reduction from one of these three calculi is never silently transferred to another.
The expansion 𝖲𝖾𝗅𝖿𝑋.𝐵=𝜇𝑌.∃𝑋<:𝑌.𝐵, its pack/use operations, the covariance derivation, the covariant-method-family condition, and the moving point and binary-method boundary are in Abadi and Cardelli, A Theory of Primitive Objects: Second-Order Systems, Sections 3.4 and 4.1–4.2, author-preprint PDF pp. 9–16, especially the rules on printed pp. 10–14. Its semantics is functional; the recoup invariant and the limit on overriding Self-returning methods are on printed pp. 17–19 [AC95]. The Point/ColorPoint argument-specialization failure and the distinction between binary-method typing and privileged representation access are developed in Bruce et al., On Binary Methods, file-PDF pp. 4–7. Its matching treatment is at file-PDF pp. 10–13; the archive cover precedes the article [BCC^+95].
The definition of matching, the statement that it grants no subsumption, and the 𝖬𝖺𝗑/𝖬𝗂𝗇𝖬𝖺𝗑 derivation occur in Abadi and Cardelli, On Subtyping and Matching, printed pp. 6–10. F-bounded quantification and its post-fixpoint interpretation are on printed pp. 12–13. The F-bounded failures of cascading bounds, reflexivity, and transitivity are on printed pp. 16–18. The higher-order translation, its reflexivity and transitivity, and its fold/unfold field derivation are on printed pp. 18–21. That source promises a rigorous full translation but gives no end-to-end proof [AC96a]; theorem 16.15 is restricted to the displayed clauses. Definition 21.20, Definition 21.21 instead give a local step-indexed model and safety proof for this reference-and-Self fragment.
★☆☆ For each occurrence of 𝑋 in {clone:𝑋,map:(𝖭𝖺𝗍→𝖡𝗈𝗈𝗅)→𝑋,equal:𝑋→𝖡𝗈𝗈𝗅,choose:(𝑋→𝖡𝗈𝗈𝗅)→𝑋}, compute its polarity from the outside inward. Determine the largest 𝖲𝖾𝗅𝖿+ subrecord and give the failed monotonicity premise for each removed field.
★★☆ Define a positive Self type with natural and Boolean fields and toggle:𝖴𝗇𝗂𝗍→𝑋. Type a closed recursive package and one toggle reduction; then omit the natural field by width and repeat the generalized (UseSelf) preservation calculation.
★★★ Let 𝖮𝗋𝖽𝖾𝗋𝖾𝖽(𝑋)={le:𝑋→𝖡𝗈𝗈𝗅},𝖭𝖺𝗆𝖾𝖽𝖮𝗋𝖽𝖾𝗋𝖾𝖽(𝑋)={name:𝖭𝖺𝗍,le:𝑋→𝖡𝗈𝗈𝗅}. Prove that the recursive types match. Give the explicit higher-order fold/unfold typing of a match-polymorphic homogeneous comparison and its F-bound analogue. Then state the subsumption judgment that would be required to use a named ordered object where an ordered object is expected, and show by arrow-domain and record-width inversion which premise prevents its derivation.
★★☆ Reconstruct the single generalized (UseSelf) preservation case when the runtime package annotation is a subtype of the expected public Self type. State exactly where Self-subtyping inversion, hidden-witness type substitution, payload subsumption, and payload substitution are used. Then give the corresponding progress argument when the scrutinee is already a closed package value.
★★★ Extend the cell with bump:𝖴𝗇𝗂𝗍→𝑋, which increments the shared reference and returns the exact receiver. Type its package, including the annotated lambda and 𝗌𝗎𝖼𝖼(!𝑟). With two aliases, fully type the trace bump unit through the first, read through the second, recording the store typing before and after allocation, assignment, and dereference. Replace the field by 𝖱𝖾𝖿𝑋; identify the failed positivity and subtyping rules.
★★★Practical project.matching-package-checker Implement four finite checks for the types in this chapter: positivity, protocol matching, package introduction, and package opening. Preserve two invariants: references containing Self are invariant rather than positive, and (UseSelf) substitutes the same hidden witness into both payload and result. The seven cases must include 𝖭𝖺𝗆𝖾𝖽𝖮𝗋𝖽𝖾𝗋𝖾𝖽 matching 𝖮𝗋𝖽𝖾𝗋𝖾𝖽, rejection of 𝖱𝖾𝖿𝑋, and the absence of matching-based subsumption. The audit is empty, and the run ends with 𝙰𝚕𝚕𝟽𝚜𝚎𝚕𝚏/𝚖𝚊𝚝𝚌𝚑𝚒𝚗𝚐𝚌𝚘𝚛𝚙𝚞𝚜𝚌𝚊𝚜𝚎𝚜𝚙𝚊𝚜𝚜𝚎𝚍. Construct three deliberately incorrect checkers by reversing arrow polarity, treating references as covariant, and substituting a different witness in the result. Each variant must remain executable and fail at least one named case. These are finite boundary checks, not a proof of the step-indexed fundamental theorem.