perovic
perovic

Reputation: 266

Scala implicit conversion from parent trait

The following code does not compile:

import scala.language.implicitConversions

trait Base {
  class Wrp[+T](val v: T) // wrapper / internal representation
}

trait BooleanOps extends Base {
  // implicit conversion
  implicit def lift2BooleanOpsCls(x: Boolean): BooleanOpsCls =
    new BooleanOpsCls(new Wrp[Boolean](x))
  class BooleanOpsCls(wx: Wrp[Boolean]) {
    def ||(wy: =>Wrp[Boolean]): Wrp[Boolean] = new Wrp[Boolean](wx.v || wy.v)
  }
}

trait MyExample extends BooleanOps {
  // test method
  def foo(): Wrp[Boolean] = {
    val ret: Wrp[Boolean] = false || new Wrp[Boolean](true)
    ret
  }
}

Output:

MyExample.scala:18: error: type mismatch;
 found   : MyExample.this.Wrp[Boolean]
 required: Boolean
        val ret: Wrp[Boolean] = false || new Wrp[Boolean](true)
                                         ^

But if I:

1) put the class Wrp outside of Base

or

2) move the body of BooleanOps to MyExample

everything compiles.

Why does not the original example work? If you have some insight in this behavior, help would be appreciated. Thank you.

Upvotes: 14

Views: 522

Answers (3)

Rob Starling
Rob Starling

Reputation: 3908

The problem is that there is no single class called Wrp (ignore the T for a moment) -- Base does not define Wrp but rather defines a named subclass of each and every concrete class that extends Base. The implicits are a red herring, too. The error that's the giveaway is the mention of MyExample.this.Wrp -- remember that there is no such class even as MyExample -- val x = new MyExample would have type Object with MyExample.

Upvotes: 1

cedric
cedric

Reputation: 358

One issue is the call-by-name nature of the argument in the def ||(wy: =>Wrp[Boolean])
if you rewite it to def ||(wy: Wrp[Boolean]) it works

but I agree that it is weird that it works if you move around Wrp or BooleanOpsCls! Intended or bug of implicit resolution??

Upvotes: 5

jwvh
jwvh

Reputation: 51271

The original example will work if you rename the || method. The compiler finds the false.||() method and doesn't bother to look for an implicit that might also work there.

Upvotes: 1

Related Questions