9

I am trying to detect if an implicit conversion exists, and depending on it, to execute some code. For instance :

if (x can-be-converted-to SomeType)
  return something(conversion(x))
else
  return someotherthing(x)

For instance, x is an Int and should be converted to a RichInt. Is this possible in Scala? If yes, how?

Thanks

Alban Linard
  • 1,037
  • 9
  • 19
  • 4
    implicit conversions exist only at compile time and not at runtime. If you want to test if such a conversion exists you can write down the code and try to compile it. The compiler will tell you if it can be compiled. – kiritsuku Apr 19 '11 at 14:30

2 Answers2

12

As others already mentioned implicits are resolved at compile time so maybe you should rather use type classes to solve problems like this. That way you have the advantage that you can extend functionality to other types later on.

Also you can just require an existing implicit value but have no way of directly expressing non-existence of an implicit value except for the default arguments.

Jean-Phiippe's solution using a default argument is already quite good but the null could be eliminated if you define a singleton that can be put in place of the implicit parameter. Make it private because it is actually of no use in other code and can even be dangerous as implicit conversions can happen implicitly.

private case object NoConversion extends (Any => Nothing) {
   def apply(x: Any) = sys.error("No conversion")
}

// Just for convenience so NoConversion does not escape the scope.
private def noConversion: Any => Nothing = NoConversion

// and now some convenience methods that can be safely exposed:

def canConvert[A,B]()(implicit f: A => B = noConversion) =
  (f ne NoConversion)

def tryConvert[A,B](a: A)(implicit f: A => B = noConversion): Either[A,B] = 
  if (f eq NoConversion) Left(a) else Right(f(a))

def optConvert[A,B](a: A)(implicit f: A => B = noConversion): Option[B] =
  if (f ne NoConversion) Some(f(a)) else None
Julie
  • 6,221
  • 3
  • 31
  • 37
Moritz
  • 14,144
  • 2
  • 56
  • 55
  • Thanks for this answer. When tested for instance with "canConvert[Boolean, Ordered[Boolean]]", it returns false. I thought the conversion to RichBoolean would be used, it seems not. What is wrong? – Alban Linard Apr 21 '11 at 07:44
  • Without the code I will have to guess: probably you called it with parenthesis like this: `canConvert[Boolean,Ordered[Boolean]]()`. The compiler then fills in the default parameter - which is not what you want. Either remove the parenthesis from the call or add an empty parameter list before the implicit parameters. – Moritz Apr 21 '11 at 11:38
  • @saucisson I updated the code to include an empty parameter list - now it does not matter if you invoke the `canConvert` method with or without an empty parameter list. – Moritz Apr 21 '11 at 12:02
9

You can try to pass it to a method that needs the corresponding implicit parameter with a default of null:

def toB[A](a: A)(implicit convertFct: A => B = null) =
  if (convertFct != null)
    convertFct(a)
  else
    someOtherThing(a)

Note that it looks curious to me to check this at runtime, because the compiler knows at compile time whether such a conversion function is available.

Jean-Philippe Pellet
  • 59,296
  • 21
  • 173
  • 234