1

How can i solve this simple problem. Class Conversion has a typed method from wich takes two type parameters A and B and returns a B from an A. I have defined some implicits in the companion object to provide default beahviour.

My Problem is when i try to forward the call to the Conversion class within another typed method which has the same signature it does not work. Here in my example i try to forward the call from function myFun to my Conversion class.

I got following error

  • not enough arguments for method from: (implicit f: A => B)

I am wondering why this makes any problems. Can someone explain me why and how to overcome this problem ?

Here is the code

  object MyConversions {

     implicit val IntToStr = (f:Int) => f.toString()

     implicit val DoubleToStr = (f:Double) => f.toString()

     implicit val BooleanToStr = (f:Boolean) => f.toString()

  }

  class Conversions{
     def from[A,B](a:A)(implicit f:(A) => B) = {
       f(a)
     }
  }

  import MyConversions._;

  def myFun[A,B](a:A){
    // Error
    new Conversions().from[A, B](a)
  }

  // Working
  println( new Conversions().from[Int, String](3) )
Jay
  • 1,035
  • 2
  • 11
  • 22

1 Answers1

3

The problem is that the Scala compiler cannot find an implicit value for the parameter f: (A) => B in the scope of myFun. What you have to do is to tell the compiler that myFun can only be called, when there is such a value available.

The following code should do the trick

object App {
  trait Convertible[A, B] {
    def convert(a: A): B
  }

  object Convertible {
    implicit val int2String = new Convertible[Int, String] {
      override def convert(a: Int): String = a.toString
    }

    implicit val float2String = new Convertible[Float, String] {
      override def convert(a: Float): String = a.toString
    }
  }

  def myFun[A ,B](a:A)(implicit converter: Convertible[A, B]): B = {
    converter.convert(a)
  }

  def main(args: Array[String]): Unit = {
    println(myFun(3))
  }
}
Till Rohrmann
  • 13,148
  • 1
  • 25
  • 51
  • I thought the implicits will be looked up in the source type which would be Conversions in that case. – Jay Sep 21 '15 at 11:48
  • 2
    No, in your case the implicits will only be looked up in the current scope and the companion objects of `A` and `B`. – Till Rohrmann Sep 21 '15 at 12:01
  • One question still unclear to me. How can i make object Convertible extendiable to other users which may provide their own implicits without passing a concrete Convertible object to myFun. Lets say we want another method that converts Boolean to String ? – Jay Sep 21 '15 at 12:06
  • 1
    For the standard types, like from `Boolean` to `String` you would have to add it to the `Convertible` companion object. If a user defines a new type, let's say `Foo`, and wants to define a conversion from `Foo` to `String`, then he can define the implicit `Convertible[Foo, String]` in the companion object of `Foo` and it will be found. – Till Rohrmann Sep 21 '15 at 12:13
  • May i ask u another question ? – Jay Sep 21 '15 at 13:51
  • Sure. You can also always post a new SO question. – Till Rohrmann Sep 21 '15 at 14:13
  • I have made this fiddle [Sample](http://scalafiddle.net/console/4d4933024367d04b052b3c62fc56f32). There is still an issue when used with inheritance and information hiding. I made a simple client sample which has different transport possibilities. I want the user to call the client without worring about the underlying transport and the conversions. – Jay Sep 21 '15 at 14:52
  • This won't work, because you don't tell the compiler where to find a `Convertible[RawResult, T]`. – Till Rohrmann Sep 21 '15 at 14:54
  • I know because i want that the caller can say i want a List[String] back. In that case `List[String]` is `T`. The underlying transport should then look if there is a conversion `Convertible[RawResult, List[String]` and return the List. – Jay Sep 21 '15 at 15:07
  • The compiler can only fill in the implicit values if it knows the concrete types. In cases where the type is not known, you have to add a context bound or an implicit parameter which will contain the missing value. Whenever someone calls the method then, he also has to make sure that he provides the implicit values. That's how it works. – Till Rohrmann Sep 21 '15 at 20:31