1

I try to make implicit conversions chain that from Symbol -> A -> Option[A]. But fail to make it working with generic Option conversion, for example:

implicit def toInt(n: Symbol): Int = n.toString.length
implicit def symbolToString(n: Symbol): String = n.toString
implicit def toOptStr[T](b: T)(implicit fn: T ⇒ String): Option[String] = Option(b)
implicit def toOptInt[T](b: T)(implicit fn: T ⇒ Int): Option[Int] = Option(b)

And it works fine:

val c: Option[Int] = 'a25768xffff // returns Some(12)
val d: Option[String] = 'a2699 // returns Some('a2699) 

But I have to explicitly define toOptStr[T](b: T): Option[String] and toOptInt[T](b: T)(implicit fn: T ⇒ Int): Option[Int]

What I want to achieve instead is to have only one generic toOptT conversion, which can convert to Option[T] provided there is implicit conversion from T=>V, something like following:

implicit def toInt(n: Symbol): Int = n.toString.length
implicit def symbolToString(n: Symbol): String = n.toString
implicit def toOptT[T,V](b: T)(implicit fn: T ⇒ V): Option[V] = Option(fn(b))

val c: Option[Int] = 'a25768xffff 
val d: Option[String] = 'a2699 

Unfortunately, 2 last lines give compilation error:

Error:(34, 93) type mismatch;
   found   : Symbol
   required: Option[Int]
Error:(35, 96) type mismatch;
   found   : Symbol
   required: Option[String]

Any help is very much appreciated.

Tried it on Scala 12.2.5. There is somewhat related question: Chain implicit conversion of collection, chaining implicits details FAQ: https://docs.scala-lang.org/tutorials/FAQ/chaining-implicits.html

D. Kuzniatsou
  • 23
  • 1
  • 4
  • V should another implicit in scope and the return type of fn should match with V. so if we can see whats that V implicit is and what fn function is then we can provide you with stabilized answer ;) – Ramesh Maharjan Apr 25 '18 at 13:43
  • @RameshMaharjan I have updated a question to make it a bit more clearer. Essentially, there are 2 implicit conversions in scope: Symbol -> Int and Symbol -> String. And we want 3 to make chain Symbol -> T -> Option[T] where T can be any T which have conversion from Symbol to T in scope (like Int and String in the example). So that we should be able to do: val c: Option[Int] = 'anysymbol – D. Kuzniatsou Apr 25 '18 at 13:57

1 Answers1

0

Couldn't make it work on 2.12.5.

Here is one possible workaround:

implicit val toInt: Symbol => Int = _.toString.length
implicit val symbolToString: Symbol => String = _.toString
implicit class ToOptOps[S](s: S) {
  def toOpt[T](implicit c: S => T): Option[T] = Option(c(s))
}

val c = 'a25768xffff.toOpt[Int]
val d = 'a2699.toOpt[String]

I'd advice you to use only typeclasses in combination with implicit classes to "pimp-the-interface" (adding new methods, as toOpt in this case). Here, one should actually replace the implicit c: S => T by a proper typeclass, to avoid unwanted collisions. The combination of type classes with "pimping" has proven to be robust. In contrast to that, implicit conversions seem just evil.

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
  • thanks for you answer. I agree it is more safe approach and nicer solution in general. Just wondering is there a way to make such conversion working if needed and if no why it does not work. – D. Kuzniatsou Apr 26 '18 at 08:22