so I will mainly focus on $D_{<:}$.
There are three core features:
x.A
), T $\wedge$ U
), and Let's focus on path dependent types.
class NotEnoughBalance(amount : Long) extends RuntimeException
trait Account {
type B <: Bank
def id : Int
protected var _balance : Long
def balance : Long = _balance
def deposit(amount : Long) : Long = {
_balance += amount
balance
}
def withdraw(amount : Long) : Long = {
if (amount > balance) {
throw new NotEnoughBalance(amount)
}
_balance -= amount
balance
}
}
trait Bank { self =>
type A <: Account { type B = self.type }
def lookupAccount(id : Int) : A
def createAccount(initialBalance : Long = 0) : A
def transfer(amount : Long, from : self.A,
toBank : Bank, to : toBank.A) : Unit = {
from.withdraw(amount)
to.deposit(amount)
}
}
Note that to
has type toBank.A
which depends on a previous input.
object BankOfWaterloo extends Bank { /* ... */ }
object WaterlooBank extends Bank { /* ... */ }
val david = BankOfWaterloo.createAccount(200)
val elly = WaterlooBank.createAccount(300)
def transfer(amount : Long, from : self.A,
toBank : Bank, to : toBank.A) : Unit
BankOfWaterloo.transfer(10, david, WaterlooBank, elly)
This program transfers 10 dollars from David to Elly.
It type checks as David is with Bank of Waterloo and Elly is with Waterloo Bank.
BankOfWaterloo.transfer(10, david, BankOfWaterloo, ellyelly)
^^^^
What about this program?
Notice that Elly is with Waterloo Bank so she has type WaterlooBank.A
and
the program will be rejected.
Path depedent types are powerful and flexible, but...
$D_{<:}$ is the simplest calculus in the DOT calculi family. It has only path depedent types out of the three core features.
The idea is to show that a complete type checking algorithm is impossible, i.e. type checking is undecidable.
Consider a rejected judgment in $F_{<:}$: $\vdash (\top \to \top) <: (\forall X <: \top. \top)$.
Definition of $F_{<:}$:
Removing function types ($\to$) from $F_{<:}$ gives $F^-_{<:}$.
Let $\Gamma = x : \{ A : S .. U\}$:
This new definition of $D_{<:}$ is called $D_{<:}$ normal form.
x.A
.By reduction from $F^-_{<:}$.
We want to maintain transitivity and drop bad bounds.
But in $D_{<:}$, one cannot achieve both at the same time.
Since it is undecidable, we can only target a fragment of admissble subtyping.
In my thesis, there are 2 decidable fragments of $D_{<:}$.
The following is the definition of $D_{<:}$:
First let's remove the BB rule.
Then make the parameter type of the All rule identical.
This is the definition of kernel $D_{<:}$.
Consider
The idea is to realize that subtyping can be achieved by more than one context!
Pierce 92 explained that this rule introduces undecidability.
But his proof only works if there is only one context.
Now the premises of this rule are simply structurally smaller subproblems.
Data member types are covariant.
Intersection types are monotone.
Intersection types are greatest lower bounds.
There is also a decidable strong kernel by extending strong kernel $D_{<:}$ with a straightforward adaptation:
I have not discussed $\mu$ types.
$\mu$ types define objects in a way typical in object oriented languages.
In my thesis, I defined $\mu$-DART and jDOT, in which I constructed an incomplete algorithm for each (c.f. Chapter 6 and 7).
However, with $\mu$ it is very difficult to prove the calculus undecidable!
Strong kernels simply remove the BB rule. What is a decidable fragment of bad bounds?
As we've seen, the BB rule is equivalent to transitivity so recovering a fragment of bad bounds recovers a fragment of transitivity, which is a desirable property.
It is even unclear at this point whether the BB rule introduces undecidability!
features | name | decidable? | |||
---|---|---|---|---|---|
bad bounds | full All |
intersections | $\mu$ types | ||
yes | yes |
no | no | $D_{<:}$ | no |
no | no | no | no | (strong) kernel $D_{<:}$ | yes |
no | yes | no | no | $D_{<:}$ without Trans | no |
yes | yes | yes | no | $D_{\wedge}$ | no |
no | no | yes | no | strong kernel $D_{\wedge}$ | yes |
yes/no | yes/no | no | yes | $\mu$DART | unknown |
yes/no | yes/no | yes | yes | DOT | unknown |
yes/no | yes/no | yes | yes | jDOT | unknown |
References:
[Pierce 92] Benjamin C. Pierce. 1992. Bounded quantification is undecidable. In Proceedings of the 19th ACM SIGPLAN-SIGACT symposium on Principles of programming languages (POPL '92).
[Amin et al. 12] Nada Amin, Adriaan Moors & Martin Odersky, FOOL'12: 19th International Workshop on Foundations of Object-Oriented Languages, October 2012
[Amin et al. 16] Amin N., Grütter S., Odersky M., Rompf T., Stucki S. (2016) The Essence of Dependent Object Types.
[Rompf and Amin 16] Tiark Rompf and Nada Amin. 2016. Type soundness for dependent object types (DOT). SIGPLAN Not. 51, 10 (October 2016), 624-641.
[Rapoport et al. 17] Marianna Rapoport, Ifaz Kabir, Paul He, and Ondřej Lhoták. 2017. A simple soundness proof for dependent object types. Proc. ACM Program. Lang. 1, OOPSLA, Article 46 (October 2017), 27 pages.
[Pierce 92] Benjamin C. Pierce. 2002. Types and Programming Languages (1st ed.). The MIT Press.