Search code examples
scalaimplicit

How to use an implicit class as a function result type


For a long time I have tried to avoid implicit classes but recently I fell into it. For the moment I can not figure out why the return type of my function aFunc2 can not be converted to its implicit form as it does for the parameter in aFunc1.

object SO extends App {
  implicit class Experiment[K, V](tpl: (K, V))(implicit o: Ordering[K], f: Fractional[V]) {
    def foo(): String = "Bar"
  }

  // Works
  println((12, 23.1).foo())

  // Works
  def aFunc1[K, V](e: Experiment[K, V]): String = e.toString
  println(aFunc1((12, 23.1)))

  // does not - why ?
  def aFunc2[K, V](e: Experiment[K, V]): Experiment[K, V] = (12, 23.1)

}

EDIT 1: In fact this has to do with the types, so let me extend the example a little bit:

object SO extends App {
  implicit class Experiment[K, V](tpl: (K, V))(implicit o: Ordering[K], f: Fractional[V]) {
    def foo(): (K, V) = (tpl._1, tpl._2)
  }

  // Works
  println((12, 23.1).foo())

  // Works
  def aFunc1[K, V](e: Experiment[K, V]): String = e.toString
  println(aFunc1((12, 23.1)))

  // still does not  but K and V should actually match - i guess
  def aFunc2[K, V](e: Experiment[K, V]): Experiment[K, V] = e.foo()

}

Error:

Error:(19, 66) type mismatch;
 found   : (K, V)
 required: scratch.SO.Experiment[K,V]
  def aFunc2[K, V](e: Experiment[K, V]): Experiment[K, V] = e.foo()

Solution

  • It is a bit hard to guess the problem without the actual error that you're getting. You should update the question with the error message.

    Looking at the code, I'm guessing the problem is not the "implicit class" but the fact that your types don't match.

    The line:

    def aFunc2[K, V](e: Experiment[K, V]): Experiment[K, V] = (12, 23.1)
    

    expects a return value of type Experiment[K,V] were both K and V are specified by the caller of your method. What you're returning is a tuple of type (Int, Double) so the compiler will complain.

    If you want to return an Experiment[Int, Double] then you should modify the function definition to:

    def aFunc2[K, V](e: Experiment[K, V]): Experiment[Int, Double] = (12, 23.1)
    

    UPDATE: Can you try adding the implicit constraints for K and V to the definition of aFunc2? It should look similar to this:

    def aFunc2[K: Ordering, V: Fractional](e: Experiment[K, V]): Experiment[K, V] = e.foo()
    

    You have to remember that in order to convert a tuple (K,V) to a Experiment[K, V] you need to have two implicit values in scope (an ordering for K, and a fractional for V).