Generic method overloading via implicit class
Asked Answered
S

0

7

When I try to create an extension for the class via implicit class and overload existing generic method, it fails with compilation error:

error: overloaded method value getAs with alternatives:
  (fieldName: String)String <and>
  (i: Int)String
 cannot be applied to (FooField.type)
       r.getAs[String](FooField)

While overloading normal (non-generic) method via implicit works fine. Tried on Scala 2.12.10. Link to scastie. What am I missing? The code:

trait Row {
    // Two overloads for `getAs[T]`
    def getAs[T](i: Int): T
    def getAs[T](fieldName: String): T

    // Two overloads for `get`
    def get(i: Int): String
    def get(fieldName: String): String
}

trait Field {
    def columnName: String
    def columnDescription: String
}
case object FooField extends Field {
    def columnName: String = "Foo"
  def columnDescription: String = "Foo desc"
}

object Implicits {
  implicit class RowEx(val r: Row) extends AnyVal {
    def getAs[T](field: Field): T = r.getAs[T](field.columnName)
    def get(field: Field): String = {
      println(s"RowEx.get: field")
      r.get(field.columnName)
    }
  }
}

object Main {
  import Implicits._
  // Create some instance of `Row`
  val r = new Row {
    def getAs[T](i: Int): T = i.toString.asInstanceOf[T]
    def getAs[T](fieldName: String): T = fieldName.toString.asInstanceOf[T]
    def get(i: Int): String = i.toString
    def get(fieldName: String): String = fieldName
  }

  def main(args: Array[String]): Unit = {
    // Call extension method => `RowEx.get`
    println(r.get(FooField))

    // Call extension method => `RowEx.get`
    // Won't compile with compilation error:
    /*
    overloaded method value getAs with alternatives:
      (fieldName: String)String 
      (i: Int)String
     cannot be applied to (FooField.type)
    */
    println(r.getAs[String](FooField))
  }
}

Opened a bug: https://github.com/scala/bug/issues/11810

Slumlord answered 26/11, 2019 at 10:27 Comment(8)
It's funny that if you don't specify type parameter then this compiles r.getAs(FooField).Centrifugal
Bugs should be reported here github.com/scala/bug/issuesCentrifugal
For r, which is instance of Row, the method getAs can accept either Int or String. You try to pass FooField object which has no implicit conversions to Int and String.Gazzo
@DmytroMitin hmm, that's strange thoughGazzo
@Gazzo But there is implicit conversion from Row to RowEx, which has method getAs accepting FooField.type <: Field.Centrifugal
@DmytroMitin I can create a bug, but I'm not sure that it is bug.Slumlord
@ArtavazdBalayan It's very similar to a bug :)Centrifugal
This is one of those annoying things in Scala when one doesnt know whats happeningCumber

© 2022 - 2024 — McMap. All rights reserved.