2

Say I have a trait like this

trait X {
  def foo(param: String): Int
}

and I want to override it with a function value, I have to do this:

class XImpl extends X {
  private val fooF: String => Int = ???
  override def foo(param: String): Int = fooF(param)
}

because the following does not work

class XImpl extends X {
  override val foo: String => Int = ???
}
/*
       error: class XImpl needs to be abstract. Missing implementation for:
         def foo(param: String): Int // inherited from trait X
                                            ^
       error: value foo overrides nothing.
       Note: the super classes of class XImpl contain the following, non final members named foo:
       def foo(param: String): Int
*/

Is it possible to directly implement/override the trait method with the function value in some way and avoid the forwarder?

dtech
  • 13,741
  • 11
  • 48
  • 73

1 Answers1

5

The simple answer is that you cannot override a method with a function value because they are not the same type.

A method must be called on a particular instance of a class (even if the method itself does not use any fields in that class).

A function value stands alone and can be called without any additional information.

A method can be converted a function value using eta expansion x.foo _. This creates a function value which has the class value embedded within it.

val x: X = ???
val etaFoo: String => Int = x.foo _

In this case Scala will actually do the eta expansion for you so the _ is optional, but it is required in more complex uses and is good practice to keep it there so show that eta expansion is happening.

To convert a function value to a method you need to define a method as shown in the question.


Eta expansion works with methods with multiple parameters:

trait X2 {
  def foo2(p1: String, p2: Int): String
}

val x2: X2 = ???
val etaFoo2: (String, Int) => String = x2.foo2 _
Tim
  • 26,753
  • 2
  • 16
  • 29
  • 1
    Thanks, unfortunately the eta expansion only works if the trait has 1 method (SAM), so for 2+ method traits the forwarder is the only option. – dtech May 14 '20 at 12:27
  • @dtech You can use an eta expansion for methods with multiple arguments. I have updated the answer to show this. – Tim May 14 '20 at 12:37