Few questions regarding structure matching in scala
Question 1) In the following piece of code, am I am able to pass Bird
and Plane
to takeOff
because Bird
and Plane
structurally match the object r
required by take off?
import scala.language.reflectiveCalls
case class Bird (val name: String) extends Object {
def fly(height: Int):Unit = {println("bird fly")}
}
case class Plane (val callsign: String) extends Object {
def fly(height: Int):Unit = {println("plane fly")}
}
def takeoff(
runway: Int,
r: { val callsign: String; def fly(height: Int):Unit }) = {
println(r.callsign + " requests take-off on runway " + runway)
println(r.callsign + " is clear for take-off")
r.fly(1000)
}
val bird = new Bird("Polly the parrot"){ val callsign = name }
val a380 = new Plane("TZ-987")
takeoff(42, bird)
takeoff(89, a380)
Question 2) What is reflectiveCalls? I had to import scala.language.reflectiveCalls
otherwise I get the warning reflective access of structural type member value callsign should be enabled by making the implicit value scala.language.reflectiveCalls visible.
Question 3) How can I create Bird
as follows: val bird = new Bird("Polly the parrot"){ val callsign = name }
. Shouldn't it only be val bird = new Bird("Polly the parrot")
. How come this compiles.
Question 3.1). Is bird
still of type Bird
or is it some other type now because I have passed additional {...}
4) What is the type of r
in takeOff
.
Yes (see #4)
Structural typing use reflection in background, so it's slow. reflectiveCalls
import is used to warn user about this problem.
When you add refinement { val callsign = name }
you extend you type Bird
with extra field callsign
, so now its type matches r
as it has both callsign
and fly
3.1 The type of bird
is both Bird
and structural
val bird: Bird = new Bird("Polly the parrot"){ val callsign = name }
val birdRefined: Bird{ val callsign:String } = new Bird("Polly the parrot"){ val callsign = name }
val structuralBird: { val callsign: String; def fly(height: Int): Unit } = birdRefined
Its called Duck typing
or structural type in scala.
You may also be interested in this subtyping relations
implicitly[Bird <:< { def fly(height: Int):Unit }]
//implicitly[Bird <:< { val callsign: String; def fly(height: Int):Unit }] -- fails. Not sybtype.
implicitly[Plane <:< { val callsign: String; def fly(height: Int):Unit }]
implicitly[Bird {val callsign:String} <:< { val callsign: String; def fly(height: Int):Unit }]