1
votes

I'm little confused about this code:

abstract class Abstract3 {   
    type TP
    protected def action(arg: TP): TP   
    def *[T <% TP](arg: T) = action(arg) 
}

class Concrete3(str: String) extends Abstract3 {   
    type TP = Concrete3 
    override protected def action(arg: TP) = new TP("") 
}

class Test3 {   
    implicit def str2Concrete(s: String)(implicit num: Int) = new Concrete3(s)   
    implicit val a = 1
    val foo = "AA" * "BB" * "CC" 
}

Scala compiler does not compile it, with an error message:

test.scala:15: error: value * is not a member of String val foo = "AA" * "BB" * "CC" ^ one error found

But if we change ''*'' to '/' or anything else, it will compile successfully:

abstract class Abstract3 {
  type TP
  protected def action(arg: TP): TP
  def /[T <% TP](arg: T) = action(arg)
}

class Concrete3(str: String) extends Abstract3 {
  type TP = Concrete3
  override protected def action(arg: TP) = new TP("")
}

class Test3 {
  implicit def str2Concrete(s: String)(implicit num: Int) = new Concrete3(s)
  implicit val a = 1 
  val foo = "AA" / "BB" / "CC"
}

BTW, if we remove 'implicit num: Int', it will also compile fine.

abstract class Abstract3 {
  type TP
  protected def action(arg: TP): TP
  def *[T <% TP](arg: T) = action(arg)
}

class Concrete3(str: String) extends Abstract3 {
  type TP = Concrete3
  override protected def action(arg: TP) = new TP("")
}

class Test3 {
  implicit def str2Concrete(s: String) = new Concrete3(s)
  val foo = "AA" * "BB" * "CC"
}

Does * has higher precedence than implicit parameters, but / has a lower precedence? Or there is other reason that * does not work in this case?

1
If Daniel C. Sobrals's comment is correct, you can consider working around by naming your operator ":*". Doesn't look quite as nice, but does the job.Madoc

1 Answers

3
votes

I'm inclined to believe the problem lies with the fact that * is overloaded into String by Predef (as in "AA" * 5), so, when you add your own * to it, you get an ambiguity in the conversion that makes Scala discard both of them.

With the conversions discarded, it's left with trying to find * on String, and it isn't there.

The problem with that idea is that "AA" * 2 still works even with the import, and the conversion you added works without the implicit parameter. But I still think the answer lies that way.