Visit the official notes for a proper recap. A way to think of subtypes is with subsets.
ColoredCircle <: Circle, and instances of ColoredCircles are a subset of all instances of Circles.
Here is a step-by-step guide on how to deal with type checking.
Summary of Steps
Type checking can be split into 2 main parts -- compile time and runtime check.
Compile Time
As the name suggests, we check whether this passes compilation or throws compilation error.
1
a=(C)b;
Compiler find compile-time type of rhs b i.e. CTT(b)
Check for possibility for run-time type of b to be subtype of C i.e. RTT(b) <: C
If impossible, exit with compilation error
Find CTT of variable lhs a i.e. CTT(a)
Check if C <: CTT(a)
If no, exit with compilation error
Else, add run-time check for RTT(b) <: C
Find CTT(b)
possible for RTT(b) <: C ? continue : compilation error
Find CTT(a)
Check if C <: CTT(a) ? runtime check : compilation error
Checks if typecast [(C) b] can potentially occur
Compiler find compile-time type of b i.e. CTT(b)
Check for possibility for run-time type of b to be subtype of C i.e. RTT(b) <: C
If impossible, exit with compilation error
Checks if assignment [a = expr] satisfies subtyping relationship
Find CTT of variable a i.e. CTT(a)
Check if C <: CTT(a)
If no, exit with compilation error
Else, add run-time check for RTT(b) <: C
CTT(b) <: C
widening, always allowed
explicit type cast not needed
C <: CTT(b)
narrowing, runtime check needed
If CTT(b) = B and RTT(b) = C (or subtype of C), allowed at runtime
If CTT(b) = B and RTT(b) = B (or other subtype of B that is not C), not allowed at runtime
Due to possibility, compiler adds code to check at runtime
C is interface
Let CTT(b) = B, may have subclass B1 where B1 <: C (B1 implements C)
If RTT(b) = B1, allowed at runtime
Let CTT(b) = B, B and C unrelated i.e. B </: C and C </: B
impossible for RTT(b) <: C (subclass of B extends B, cannot also extends C)
C interface and B has final modifier
case 3 not possible, class cannot be inherited from
Runtime
Once the compile time check pass, compiler does a runtime check (added from step 4).
1
a=(C)b;
Find runtime type of rhs i.e. RTT(b)
Check if RTT(b) <: C
Step-by-step
Success
We will look at the following successful example first