o Satisfies a Type T?T describes a set of values that behave in a certain way.S => T is a contract between caller and callee:S.T.Say we have a function of type T => U
val foo : T => U = x => ...
and an object of type S.
val o : S = { ... }
o to foo ?foo(o)
S is a subtype of T !When can S-typed values can be substituted for T-typed values?
e has type S, andS is a subtype of T (written S <: T)e can be used in any context that requires a T.S <: T ?ticker Type From Last Time
type t = { def next(): Any
; def hasNext: Boolean }
s <: t?type s = { def hasNext: Boolean
; def next(): Any }
type t = { def next(): Any
; def hasNext: Boolean }
s <: t?type s = { def next(): Any
; def hasNext: Boolean }
type t = { def hasNext: Boolean
; def next(): Any;
; def foreach(f: Any => Unit): Unit }
s does not guarantee foreach method, which t requires.s <: t?type s = { def hasNext: String
; def next(): Any;
; def foreach(f: Any => Unit): Unit }
type t = { def next(): Any
; def hasNext: Boolean }
A: Yes B: No
s <: t?type s = { def hasNext: String
; def next(): Any;
; def foreach(f: Any => Unit): Unit }
type t = { def next(): Any
; def hasNext: Boolean }
s provides an extra members which t doesn't need. That's okay...s has hasNext, but it's String, not Boolean.When structural type S has more attributes than T
S = { def f1: S1; ... ; def fn: Sn; def f0:S0 }T = { def f1: S1; ... ; def fn: Sn }S <: Ts <: t?type s = { def next(): Int;
; def hasNext: Boolean
; def foreach(f: Any => Unit): Unit }
type t = { def next(): Any
; def hasNext: Boolean }
A: Yes B: No
s <: t?type s = { def next(): Int;
; def hasNext: Boolean
; def foreach(f: Any => Unit): Unit }
type t = { def next(): Any
; def hasNext: Boolean }
next method in s returns Int rather than Any...When S fields are subtypes of T fields
S = { def f1: S1; ... ; def fn: Sn }T = { def f1: T1; ... ; def fn: Tn }S1 <: T1 and ... and Sn <: TnS <: TSo far, three subtyping rules:
Permutation : order of members doesn't matter
Width : extra members are okay
Depth : member types can be "more specific" than required
The subtyping (or "is-a") relation is reflexive
TT <: TThe subtyping (or "is-a") relation is transitive
S <: TT <: US <: UHow can we ask Scala if an expression e has a certain type T?
How can we ask Scala if an expression e has a certain type T?
scala> val blah: T = e
e will be analyzed and (possibly) assigned some type S.S <: T.scala> val blah: Int = 1
blah: Int = 1
scala> val blah: Boolean = 1
<console>:7: error: type mismatch;
found : Int(1)
required: Boolean
val blah: Boolean = 1
^
scala> val blah: Any = 1
blah: Any = 1
T <: Any for all T.Can make these "subtyping queries" more directly:
scala> (1:Int, 1:Any)
res20: (Int, Any) = (1, 1)
scala> 1:Boolean
... error ...
e:T declares an expected type for e.val/var/def Declarations?type t1 = { val i : Int } ; type t3 = { def i : Int }
type t2 = { var i : Int } ; type t4 = { def i() : Int }
type t1 = { val i : Int } ; type t3 = { def i : Int }
type t2 = { var i : Int } ; type t4 = { def i() : Int }
object o1 { val i = 0 } ; object o3 { def i = 0 }
object o2 { var i = 0 } ; object o4 { def i() = 0 }
o1:t1 is well-typedo2:t2 is well-typedo3:t3 is well-typedo4:t4 is well-typedtype t1 = { val i : Int } ; type t3 = { def i : Int }
type t2 = { var i : Int } ; type t4 = { def i() : Int }
object o1 { val i = 0 } ; object o3 { def i = 0 }
object o2 { var i = 0 } ; object o4 { def i() = 0 }
scala> o1:t2 // Is this expression well-typed?
A: Yes B: No
var means that the "context" (caller) may assign to i...val means immutable. So NO!type t1 = { val i : Int } ; type t3 = { def i : Int }
type t2 = { var i : Int } ; type t4 = { def i() : Int }
object o1 { val i = 0 } ; object o3 { def i = 0 }
object o2 { var i = 0 } ; object o4 { def i() = 0 }
scala> o1:t3 // Is this expression well-typed?
A: Yes B: No
def with no parameter list must be called with no parens.type t1 = { val i : Int } ; type t3 = { def i : Int }
type t2 = { var i : Int } ; type t4 = { def i() : Int }
object o1 { val i = 0 } ; object o3 { def i = 0 }
object o2 { var i = 0 } ; object o4 { def i() = 0 }
scala> o1:t4 // Is this expression well-typed?
A: Yes B: No
def with empty parameter list may be called with no parens.type t1 = { val i : Int } ; type t3 = { def i : Int }
type t2 = { var i : Int } ; type t4 = { def i() : Int }
object o1 { val i = 0 } ; object o3 { def i = 0 }
object o2 { var i = 0 } ; object o4 { def i() = 0 }
scala> o2:t1 // Is this expression well-typed?
val is required, so the "context" (caller) will only read...var should be okay.val cannot be provided where var requiredvar cannot be provided where val requiredval can be provided where def requiredvar can be provided where def requiredval cannot be provided where def(...) required (not surprising)var cannot be provided where def(...) required (not surprising)Two structurally identically classes:
class C1 { var i:Int = 0 } ; class C2 { var i:Int = 0 }
val x1 = new C1 ; val x2 = new C2
x1:C1 and x2:C2.x1:C2 ?Two structurally identically classes:
class C1 { val i:Int = 0 } ; class C2 { val i:Int = 0 }
val x1 = new C1 ; val x2 = new C2
Of course, x1:C1 and x2:C2.
What about x1:C2 ?
scala> x1:C2
<console>:11: error: type mismatch;
found : C1
required: C2
new C1 has type C1When one class instance is an instance of another class
C is a descendant of D in the class hierarchyC <: Dclass C1 { val i:Int = 0 } ; class C2 { val i:Int = 0 }
C1 and C2 and have the same structure, but...C1 <: C2 does not holdC2 <: C1 does not holdAny ideas?
???
???
???
C, just refer to the name C!abstract class IntList
{ val data: Int; val next: Option[IntList] }
trait inti { val i : Int }
class D1 extends inti { val i = 0 }
class D2 extends inti { val i = 0 }
val y1 = new D1 ; val y2 = new D2
y1:D1 and y1:inti and y2:D2 and y1:intiy1:D2 and y2:D1class C1 { val i = 0 } ; class C2 { val i = 0 }
trait inti { val i : Int }
val z1 = new C1 with inti ; val z2 = new C2 with inti
// z1 : C1 with inti // z2 : C2 with inti
Note: the types of z1 and z2 mention with.
z1:C1 and z1:inti and z2:C2 and z1:intiz1:C2 and z2:C1class C1 { val i:Int = 0 }
val x1 = new C1
scala> x1:{val i:Int}
res60: AnyRef{val i: Int} = C1@13c59de
scala> x1:{}
res61: AnyRef{} = C1@1b95cf5
def applyFunc(f: Double => Double) = 3.14 + (f (3.14))
def addOne(i: Int) = 1 + i
val res = applyFunc(addOne)
A: Type Error (in applyFunc)
B: Type Error (in call to applyFunc)
C: res: Int = 7
D: res: Double = 7.28
E: Run-Time Exception
def applyFunc(f: Double => Double) = 3.14 + (f (3.14))
def addOne(i: Int) = 1 + i
val res = applyFunc(addOne)
addOne must be subtype of f.(Int => Int) <: (Double => Double) ?When is (S => T1) <: (S => T2) ?
T2.T1.T1 <: T2.When is (S1 => T) <: (S2 => T) ?
S2.S1.S2 <: S1. Whoa, weird!When is (In1 => Out1) <: (In2 => Out2) ?
In2 <: In1Out1 <: Out2(In1 => Out1) <: (In2 => Out2)Courtesy: Ranjit Jhala
Courtesy: Ranjit Jhala
Courtesy: Ranjit Jhala
Courtesy: Ranjit Jhala
def applyFunc(f: Double => Double) = 3.14 + (f (3.14))
def addOne(i: Int) = 1 + i
val res = applyFunc(addOne)
For call to succeed, type of addOne must be subtype of f.
So, is (Int => Int) <: (Double => Double) ?
Int is a subtype of Double).Double is not a subtype of Int).applyFunc)class Parent { def foo(p:Parent) = () }
class Child extends Parent
{ override def foo(p:Parent) = () }
Child class definition to be allowed,foo method must be a subtype of Parent's.(Parent => Unit) <: (Parent => Unit) to be true.class Parent { def foo(p:Parent) = () }
class ProblemChild extends Parent
{ override def foo(c:ProblemChild) = () }
ProblemChild class definition to be allowed,foo method must be a subtype of Parent's.(ProblemChild => Unit) <: (Parent => Unit) to be true.Parent <: ProblemChild) by contravariance...ProblemChild is not a well-typed subclass.