1

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?

Brian Hsu
  • 8,781
  • 3
  • 47
  • 59
  • 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 Jan 17 '13 at 12:14

1 Answers1

3

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.

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • 1
    -Yinfer-debug seems to say that the implicit int param breaks the conversion you get from the view T <% TP, which is considered after failing with the ambiguity. – som-snytt Jan 17 '13 at 23:57