Search code examples
scalaapplystructural-typing

Apply method used in type [Scala]


I was skimming Scala code, and find that apply method is also used in type.

Example:
type Common = {
  def apply: {val func: {} => {val a: A}; val c: C} => {val b: B}
}

What does above code mean?

As I understand, it means that Common refers to all the types that includes apply method. But, questions is what kind of apply method does it mean? What should be the inputs of apply method be?

Also,

type Common = {
  def apply({val func: {} => {val a: A}; val c: C} => {val b: B})
}

What is the difference between two Common type?


Solution

  • This is known as a structural type. It simply means that you describe a type by its structure instead of (only) by its name. The type Foo{val a: String} means "something that has type Foo but also has a val a: String". {val a: String} is the same as AnyRef{val a: String}. So {} means AnyRef{}, which basically means the same as AnyRef.

    Of course you can also use structural types in structural types, which is what Common does. Common is a subtype of AnyRef that has an apply method which takes no arguments but returns a function with some complicated structural types as type arguments. To decipher those you just have to recursively apply the rules from the first paragraph.

    How would you use this Common type? I recommend not to, but...

    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class A; class B; class C
    
    type Common = {
      def apply: {val func: {} => {val a: A}; val c: C} => {val b: B}
    }
    
    class HasA { val a = new A }
    
    class HasB { val b = new B }
    
    class HasC {
      val func = (a: AnyRef) => new HasA
      val c = new C
    }
    
    class MyCommon { def apply = (h: Any) => new HasB }
    
    // Exiting paste mode, now interpreting.
    
    
    scala> def common(c: Common) = c
    common: (c: Common)Common
    
    scala> common(new MyCommon)
    res0: Common = MyCommon@3652a0d8
    
    scala> res0.apply(new HasC)
    res1: AnyRef{val b: B} = HasB@3925c40e
    
    scala> res1.b
    res2: B = B@1ba053df
    

    Invocations of methods of structural types might also incur a runtime overhead, as they are implemented with reflection.