IntListPoint objects can we send to screenSaver?Point?Short descriptions of Objects
Maps from names to types
The actions one can perform on object
Field and Methods and their respective types
Short descriptions of Objects
Maps from names to types
Example: ticker
{ def next(): Any
def hasNext: Boolean }
Example: Int
{ def .+(other: Int) : Int // add method
def .-(other: Int) : Int // subtract method
...//etc }
Short descriptions of Objects
Maps from names to types
Example: Point
class Point {
val name : String // immutable field
var x : Int // mutable field
var y : Int // mutable field
def render(g: Graphics): Unit // method
def move(d: Dimension, del: Int) // method
}
def screenSaver(p: Point) {
// Only uses properties described in Point
}
ScreenSaver) promises to only use attributes of Pointmain) promises to only send Point valuesPoint value?Point ?What objects can we really call ScreenSaver with?
new Point(...) ?DotColorDotBoxColorBoxWhat objects can we really call ScreenSaver with?
Point attributesDotColorDotBoxColorBoxPointS <: T means type S is a subtype of type TS<:T then we can use S object in place of T objectS<:T then S object IS A T objectS <: T then we can use S object in place of T objectT objects, it can be called with S objectsIf S <: T then we can use S objects in place of T objects
Dot <: PointColorDot <: Dot <: PointBox <: Dot <: PointColorBox <: Dot <: Pointdef screen(p: Point) {
// Only uses properties described in Point
}
So screen can be called with Dot, ColorDot, Box, ColorBox
S <: TS <: TWhen every object of type S "IS A" object of type T
S has all attributes of TS <: TS <: T if S has all attributes of Tclass ColorDot {
val color : Color // Extra Field
val name : String
var x : Int
var y : Int
def render(g: Graphics): Unit
def move(d: Dimension, delta: Int)
}
is a (subtype of)
class Dot {
val name : String
var x : Int
var y : Int
def render(g: Graphics): Unit
def move(d: Dimension, delta: Int)
}
S <: TWidth Subtyping: when S has more attributes than T
S = { val f0: S0; val f1: S1; ... ; val fn: Sn }T = { val f1: S1; ... ; val fn: Sn }S <: TDot <: Point (extra field: name)ColorDot <: Dot (extra field: color)ColorDot <: Point ?S <: TTransitive Subtyping: The Is-A relation is transitive
S <: ThingThing <: TS <: TS and T, how can we know if S <: T ?We know ColorDot <: Dot. What about ColorLine and Line?
class Line {
val p1: Dot
val p2: Dot
}
and
class ColorLine {
val p1: ColorDot
val p2: ColorDot
}
S <: T ?We know ColorDot <: Dot. What about ColorLine and Line?
class Line {
val p1: Dot
val p2: Dot
}
class ColorLine {
val p1: ColorDot
val p2: ColorDot
}
For any function def foo(l: Line), is it OK to call foo with a ColorLine ?
A. Hells, Yes!
B. OMG, NO!
S and T, how can we know if S <: T ?We know ColorDot <: Dot.
What about ColorLine and Line?
For any function
def foo(l: Line)
Is it OK to call foo with a ColorLine ? Yes
foo can do is use p1 and p2 as Dot...ColorLine has those fields with properties of ColorDotColorDot is a Dotfoo with ColorLine objects.S <: TDepth Subtyping: when S fields are subtypes of T fields
S = { val f1: S1; ... ; val fn: Sn }T = { val f1: T1; ... ; val fn: Tn }S1 <: T1 and S2 <: T2 and ... Sn <: TnS <: TS and T, how can we know if S <: T ?(In => S) <: (In => T)?(S => Out) <: (T => Out)?(S1 => S2) <: (T1 => T2)?S and T, how can we know if S <: T ?(In => S) <: (In => T)?(S => Out) <: (T => Out)?(S1 => S2) <: (T1 => T2)?In=>S <: In=>T ?() => ColorDot <: () => Dot ?Suppose I have a method whose input has type () => Dot
def screenSaver(f:() => Dot): Unit
Also, suppose I have a function that returns ColorDot <: Dot
val getColorDot: () => ColorDot
screenSaver(getColorDot) ?A. Yes
B. No
In=>S <: In=>T ?() => ColorDot <: () => Dot ?Suppose I have a method whose input has type () => Dot
def screenSaver(f:() => Dot): Unit
Also, suppose I have a function that returns ColorDot <: Dot
val getColorDot: () => ColorDot
screenSaver(getColorDot) ? YESscreenSaver can do is call f to get a Dot ...Dots propertiesscreenSaver calls getColorDot it gets a ColorDot ...Dot (has all of Dots properties) ...In => S <: In => TCan substitute/use a function with another that produces fewer outputs ...
S <: TIn => S <: In => TColorDot <: Dot() => ColorDot <: () => DotS and T, how can we know if S <: T ?(In => S) <: (In => T)?S <: T(S => Out) <: (T => Out)?(S1 => S2) <: (T1 => T2)?S=>Out <: T=>Out ?ColorDot=>Graphic <: Dot=>Graphic ?If I have a function whose input must be Dot => Graphic
def plotGraphic(x: Dot => Graphic): Unit
and a function from ColorDot to Graphic
val cd2g: ColorDot => Graphic
plotGraphic(cd2g) ?A. Yes
B. No
S=>Out <: T=>Out ?ColorDot=>Graphic <: Dot=>Graphic ?def plotGraphic(f: Dot => Graphic) {
val d = new Dot(0, 0) // not ColorDot
plot(f(d))
}
def cd2g(cd: ColorDot) = {
val c = cd.color
setColor(cd.color)
fillColorOval()
}
What happens if we do ...
plotGraphic(cd2g)
?
S=>Out <: T=>Out ?ColorDot=>Graphic <: Dot=>Graphic ?def plotGraphic(f: Dot => Graphic) {
val d = new Dot(0, 0) // not ColorDot
plot(f(d)) // cd2g(d) crashes!
}
def cd2g(cd: ColorDot) = {
val c = cd.color
setColor(cd.color)
fillColorOval()
}
plotGraphic(cd2g)
f(d) in plotGraphic crashes!cd2g(new Dot(0, 0)) tries to access .color field ...Dot!S=>Out <: T=>Out ?ColorDot=>Graphic <: Dot=>Graphic ?ColorDot=>Graphic instead of Dot=>GraphicColorDot=>Graphic in place of Dot=>GraphicS=>Out <: T=>Out ?Dot=>Graphic <: ColorDot=>Graphic ?S=>Out <: T=>Out ?Dot=>Graphic <: ColorDot=>Graphic ?Suppose we have:
def plotColorGraphic(f: ColorDot => Graphic)
def d2g(d: Dot)
Would plotGraphic(cd2g) cause any problems?
plotColorGraphic will only call f with ColorDot values ...Dot values ...d2g will have no problem handling them!S=>Out <: T=>Out ?Dot=>Graphic <: ColorDot=>Graphic ?Suppose we have:
def plotColorGraphic(f: ColorDot => Graphic)
def d2g(d: Dot)
Would plotGraphic(cd2g) cause any problems?
Safe to use a function that accepts more inputs
T => Out <: T => OutCan substitute/use a function with another that accepts more inputs ...
T <: SS => Out <: T => OutAs ColorDot <: Dot
We have Dot => Graphic <: ColorDot => Graphic
S and T, how can we know if S <: T ?(In => S) <: (In => T)?S <: T(S => Out) <: (T => Out)?T <: S(In1 => Out1) <: (In2 => Out2) ?You tell me!
In1 => Out1 <: In2 => Out2
If:
A. In1 <: In2 and Out1 <: Out2
B. In2 <: In1 and Out1 <: Out2
C. In1 <: In2 and Out2 <: Out1
D. In2 <: In1 and Out2 <: Out1
You tell me!
In1 => Out1 <: In2 => Out2
We can use f1: In1 => Out1 in place of f2: In2 => Out2
If:
f1 accepts more inputs
In2 <: In1f2 produces fewer outputs
Out1 <: Out2In2 <: In1 and Out1 <: Out2S and T, how can we know if S <: T ?If
In2 <: In1Out1 <: Out2Then
In1 => Out1 <: In2 => Out2S and T, how can we know if S <: T ?If
In2 <: In1Out1 <: Out2Then
In1 => Out1 <: In2 => Out2S <: T ?We know ColorDot <: Dot. How about these two (with getter methods)
class Line {
def getP1(): Dot
def getP2(): Dot
}
and
class ColorLine {
def getP1(): ColorDot
def getP2(): ColorDot
}
Is ColorLine <: Line ? (Is it OK to call foo with a ColorLine?)
A. Yes
B. No
S and T, how can we know if S <: T ?We know ColorDot <: Dot. How about these two (with getter methods)
class Line {
def getP1(): Dot
def getP2(): Dot
}
and
class ColorLine {
def getP1(): ColorDot
def getP2(): ColorDot
}
Yes we can call foo with a ColorLine
foo can only get and use p1 and p2 as Dot...ColorLine has those fields with properties of ColorDotColorDot is a Dotfoo with ColorLine objects.S and T, how can we know if S <: T ?We know ColorDot <: Dot. How about these two (with getter methods)
class Line {
def getP1: () => Dot
def getP2: () => Dot
}
class ColorLine {
def getP1: () => ColorDot
def getP2: () => ColorDot
}
Lets use the rules to derive ColorLine <: Line ?
() => ColorDot <: () => DotColorLine.getP1 <: Line.getP1ColorLine.getP2 <: Line.getP2ColorLine <: LineS and T, how can we know if S <: T ?We know ColorDot <: Dot. How about these two (with setter methods)
class Line {
// other fields from before ...
def setP1(p: Dot): Unit
def setP2(p: Dot): Unit
}
class ColorLine {
// other fields from before ...
def setP1(p: ColorDot) : Unit
def setP2(p: ColorDot) : Unit
}
ColorLine <: Line ?For any function foo, can we call foo(new ColorLine(...)) ?
def foo(l: Line) {...}
S and T, how can we know if S <: T ?OK to call foo with a ColorLine? (for any def foo(l: Line))
class Line { def setP1(p: Dot): Unit }
class ColorLine { def setP1(p: ColorDot) : Unit }
Suppose that ColorLine <: Line ?
Consider the following foo
def foo(l: Line) { l.setP1(new Dot(0, 0)) }
Now, all hell breaks loose:
val cl = new ColorLine
foo(cl) // Typechecks
val color1 = l.getP1.color // Runtime Error!
S and T, how can we know if S <: T ?If ColorDot <: Dot then is ColorLine <: Line ?
class Line {
// from before ...
def setP1: Dot => Unit
def setP2: Dot => Unit
}
class ColorLine {
// from before ...
def setP1: ColorDot => Unit
def setP2: ColorDot => Unit
}
ColorLine.setP1 not a subtype of Line.setP1 ...Can one widget be safely substituted with another?
S <: TSays when a value of type S is a value of type T
S has more attributes than TS fields are subtypes of T fieldsS accepts more inputs, produces fewer outputsIf S <: T then we can use S objects in place of T objects
Dot <: PointColorDot <: Dot <: PointBox <: Dot <: PointColorBox <: Dot <: Pointdef screen(p: Point) {
// Only uses properties described in Point
}
So screen can be called with Dot, ColorDot, Box, ColorBox