Search code examples
scalastructural-typing

What is structure match in scala


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.


Solution

    1. Yes (see #4)

    2. Structural typing use reflection in background, so it's slow. reflectiveCalls import is used to warn user about this problem.

    3. 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
      
    4. 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 }]