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
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
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.
Related
In my project, I need to write a generic class, which in a single method handles some types with its handler in a special way (Numeric is used for clarity in the example).
class A[T](val a:T){
def doSomething(b:T):T = a match{
case a : Int => doSomethingWithIntOrDouble(b)
case a : Double => doSomethingWithIntOrDouble(b)
case _ => b
}
def doSomethingWithIntOrDouble(b:T)(implicit ev:Numeric[T]):T =
ev.plus(a,b)
}
<console>:13: error: could not find implicit value for parameter ev: Numeric[T]
case a : Int => doSomethingWithIntOrDouble(b)
^
<console>:14: error: could not find implicit value for parameter ev: Numeric[T]
case a : Double => doSomethingWithIntOrDouble(b)
I think this happens because the compiler picks up the type parameter but not the actual one. Tell me, is there any way around this?
PS Okay If we assume that the answer is correct, then it is necessary to overload the dosomething method to achieve polymorphism.
class A[T](val a:T){
def doSomething(b:T)(implicit ev:Numeric[T]):T = ev.plus(a,b)
def doSomething(b:T):T = b
}
But in this case, another problem arises.
scala> a.doSomething(2)
<console>:13: error: ambiguous reference to overloaded definition,
both method doSomething in class A of type (b: Int)Int
and method doSomething in class A of type (b: Int)(implicit ev: Numeric[Int])Int
match argument types (Int)
a.doSomething(2)
I am not completely sure this is want your want, but I hope it helps.
Basically, you need to forward the evidence that the T type is a Numeric to the outer method. But, you also have to handle the case where it is not.
For that case, you can provide a default value for the implicit parameter like this:
class A[T](val a: T) {
def doSomething(b: T)(implicit ev: Numeric[T] = null): T = Option(ev) match {
case Some(ev) => doSomethingWithNumeric(b)(ev)
case None => b
}
def doSomethingWithNumeric(b: T)(implicit ev: Numeric[T]): T =
ev.plus(a, b)
}
It seems to work.
(new A(10)).doSomething(100) // res: Int = 110
(new A("hey")).doSomething("world") // res: String = "world"
Note that, if you will have many methods, maybe a cleanest solution would be to make A a trait with two implementations, one for numeric types and other for no numeric types.
Make the constructors of both sub classes private and create a factory for A in the companion object which ask for the implicit numeric parameter, and if found it will return a new instance of the numeric subclass.
Suppose you have a trait like this:
trait Foo[A]{
def foo: A
}
I want to create a function like this:
def getFoo[A <: Foo[_]](a: A) = a.foo
The Scala Compiler deduces Any for the return type of this function.
How can I reference the anonymous parameter _ in the signature (or body) of getFoo?
In other words, how can I un-anonymize the parameter?
I want to be able to use the function like
object ConcreteFoo extends Foo[String] {
override def foo: String = "hello"
}
val x : String = getFoo(ConcreteFoo)
which fails compilation for obvious reasons, because getFoo is implicitly declared as Any.
If this is not possible with Scala (2.12 for that matter), I'd be interested in the rational or the technical reason for this limitation.
I am sure there are articles and existing questions about this, but I appear to be lacking the correct search terms.
Update: The existing answer accurately answers my question as stated, but I suppose I wasn't accurate enough regarding my actual usecase. Sorry for the confusion. I want to be able to write
def getFoo[A <: Foo[_]] = (a: A) => a.foo
val f = getFoo[ConcreteFoo.type]
//In some other, unrelated place
val x = f(ConcreteFoo)
Because I don't have a parameter of type A, the compiler can't deduce the parameters R and A if I do
def getFoo[R, A <: Foo[R]]: (A => R) = (a: A) => a.foo
like suggested. I would like to avoid manually having to supply the type parameter R (String in this case), because it feels redundant.
To answer literally your exact question:
def getFoo[R, A <: Foo[R]](a: A): R = a.foo
But since you don't make any use of the type A, you can actually omit it and the <: Foo[..] bound completely, retaining only the return type:
def getFoo[R](a: Foo[R]): R = a.foo
Update (the question has been changed quite significantly)
You could smuggle in an additional apply invocation that infers the return type from a separate implicit return type witness:
trait Foo[A] { def foo: A }
/** This is the thing that remembers the actual return type of `foo`
* for a given `A <: Foo[R]`.
*/
trait RetWitness[A, R] extends (A => R)
/** This is just syntactic sugar to hide an additional `apply[R]()`
* invocation that infers the actual return type `R`, so you don't
* have to type it in manually.
*/
class RetWitnessConstructor[A] {
def apply[R]()(implicit w: RetWitness[A, R]): A => R = w
}
def getFoo[A <: Foo[_]] = new RetWitnessConstructor[A]
Now it looks almost like what you wanted, but you have to provide the implicit, and you have to call getFoo[ConcreteFoo.type]() with additional pair of round parens:
object ConcreteFoo extends Foo[String] {
override def foo: String = "hey"
}
implicit val cfrw = new RetWitness[ConcreteFoo.type, String] {
def apply(c: ConcreteFoo.type): String = c.foo
}
val f = getFoo[ConcreteFoo.type]()
val x: String = f(ConcreteFoo)
I'm not sure whether it's really worth it, it's not necessarily the most straightforward thing to do. Type-level computations with implicits, hidden behind somewhat subtle syntactic sugar: that might be too much magic hidden behind those two parens (). Unless you expect that the return type of foo will change very often, it might be easier to just add a second generic argument to getFoo, and write out the return type explicitly.
This doesn't compile:
class MyClass[+A] {
def myMethod(a: A): A = a
}
//error: covariant type A occurs in contravariant position in type A of value a
Alright, fair enough. But this does compile:
class MyClass[+A]
implicit class MyImplicitClass[A](mc: MyClass[A]) {
def myMethod(a: A): A = a
}
Which lets us circumvent whatever problems the variance checks are giving us:
class MyClass[+A] {
def myMethod[B >: A](b: B): B = b //B >: A => B
}
implicit class MyImplicitClass[A](mc: MyClass[A]) {
def myExtensionMethod(a: A): A = mc.myMethod(a) //A => A!!
}
val foo = new MyClass[String]
//foo: MyClass[String] = MyClass#4c273e6c
foo.myExtensionMethod("Welp.")
//res0: String = Welp.
foo.myExtensionMethod(new Object())
//error: type mismatch
This feels like cheating. Should it be avoided? Or is there some legitimate reason why the compiler lets it slide?
Update:
Consider this for example:
class CovariantSet[+A] {
private def contains_[B >: A](b: B): Boolean = ???
}
object CovariantSet {
implicit class ImpCovSet[A](cs: CovariantSet[A]) {
def contains(a: A): Boolean = cs.contains_(a)
}
}
It certainly appears we've managed to achieve the impossible: a covariant "set" that still satisfies A => Boolean. But if this is impossible, shouldn't the compiler disallow it?
I don't think it's cheating any more than the version after desugaring is:
val foo: MyClass[String] = ...
new MyImplicitClass(foo).myExtensionMethod("Welp.") // compiles
new MyImplicitClass(foo).myExtensionMethod(new Object()) // doesn't
The reason is that the type parameter on MyImplicitClass constructor gets inferred before myExtensionMethod is considered.
Initially I wanted to say it doesn't let you "circumvent whatever problems the variance checks are giving us", because the extension method needs to be expressed in terms of variance-legal methods, but this is wrong: it can be defined in the companion object and use private state.
The only problem I see is that it might be confusing for people modifying the code (not even reading it, since those won't see non-compiling code). I wouldn't expect it to be a big problem, but without trying in practice it's hard to be sure.
You did not achieve the impossible. You just chose a trade-off that is different from that in the standard library.
What you lost
The signature
def contains[B >: A](b: B): Boolean
forces you to implement your covariant Set in a way that works for Any, because B is completely unconstrained. That means:
No BitSets for Ints only
No Orderings
No custom hashing functions.
This signature forces you to implement essentially a Set[Any].
What you gained
An easily circumventable facade:
val x: CovariantSet[Int] = ???
(x: CovariantSet[Any]).contains("stuff it cannot possibly contain")
compiles just fine. It means that your set x, which has been constructed as a set of integers, and can therefore contain only integers, will be forced to invoke the method contains at runtime to determine whether it contains a String or not, despite the fact that it cannot possibly contain any Strings. So again, the type system doesn't help you in any way to eliminate such nonsensical queries which will always yield a false.
Let's assume the following:
class Wrapper1 {
case class Condition(test: String)
}
object Wrapper1 extends Wrapper1
class Wrapper2 {
case class Condition[A](test: String)
}
object Wrapper2 extends Wrapper2
class Test
type T = // whatever
def test(fn: T => Wrapper1.Condition): X
def test[R](fn: T => Wrapper2.Condition[R]): X
}
The problem is that because of type erasure those methods have the exact same type after erasure. It's easy to change the signature of the second with say:
def test[R](fn: T => Wrapper2.Condition[R])(implicit ev: R =:= R): X
But that confuses the compiler and using the test method in other places is impossible. For a number of design reasons I'm trying to keep the name of this method consistent. Is there any way to successfully do this?
Seems this is NOT a duplicate of Scala double definition (2 methods have the same type erasure)
My suggestion... Just have a single method
def test[Cond: TypeTag](fn: T => Cond): X = {
if(typeOf[T] <:< typeOf[Wrapper1.Condition]) ...
else if(typeOf[T] <:< typeOf[Wrapper2.Condition[_]) ...
else ...
}
Finally able to work it out. What I was after was a way to conditionally append to an HList. Basically multiple overloads of the same method had to co-exist because they would return a different kind of HList.
To only have one method, arguments needed to dictate what the final signature of the method looked like.
So let's assume the following, the test method had to return
def test[RR](arg: Type1[RR]): Wrapper[RR :: ExistingHList]
Or respectively:
def test(arg: Type2): Wrapper[ExistingList]
The same method would have to append to an Hlist depending on whether or not the argument satisfied certain conditions. The fix was as trivial as using shapeless.ops.hlist.Prepend, which will by default returning the existing HList in the event we try to append HNil to an hlist.
Making the argument of Type2 return an HNil or implicitly convert to something that would end up being HNil was the approach that worked.
Specifically:
class Wrapper[PS <: HList] {
def test[
RR,
HL <: HList,
Out <: HList
](
condition: T => Wrapper[HL]
)(implicit prepend: Prepend.Aux[HL, PS, Out]): Wrapper[Out[
}
This approach works if the condition function will return a Wrapper[HNil] for situations where the function doesn't need to modify the end return type. Functions who do modify are simply free to build up their own HList independently.
Is it possible to write a method in Scala which returns an object of a type-parameterized class with different type paramter ? Something like this:
class A[T]
def f(switch: Boolean): A = if(switch) new A[Int] else new A[String]
Please note: The Code above is fictional to show the type of problem; The code above does not make semantically sense.
The code above will not compile because return type A is not parameterized.
You can, and you can even do it with type-safety with the aid of implicit arguments that encapsulate the pairings:
class TypeMapping[+A,B] {
def newListB = List.empty[B]
}
trait Logical
object True extends Logical
object False extends Logical
implicit val mapFalseToInt = new TypeMapping[False.type,Int]
implicit val mapTrueToString = new TypeMapping[True.type,String]
def f[A <: Logical,B](switch: A)(implicit tmap: TypeMapping[A,B]) = tmap.newListB
scala> f(True)
res2: List[String] = List()
scala> f(False)
res3: List[Int] = List()
You do have to explicitly map from boolean values to the custom True and False values.
(I have chosen List as the target class just as an example; you could pick anything or even make it generic with a little more work.)
(Edit: as oxbow_lakes points out, if you need all possible return values to be represented on the same code path, then this alone won't do it, because the superclass of List[Int] and List[String] is List[Any], which isn't much help. In that case, you should use an Either. My solution is for a single function that will be used only in the True or False contexts, and can maintain the type information there.)
One way of expressing this would be by using Either;
def f(switch: Boolean) = if (switch) Left(new A[Int]) else Right(newA[String])
This of course returns an Either[A[Int], A[String]]. You certainly cannot (at the moment) declare a method which returns some parameterized type P, with some subset of type parameters (i.e. only Int or String).
The language ceylon has union types and I understand the intention is to add these to scala in the near future, in which case, you could define a method:
def f(switch: Boolean): A[Int|String] = ...
Well, you could do something like that.
scala> class A {
| type T
| }
defined class A
scala> def f(b: Boolean): A = if(b) new A { type T = Int } else new A { type T = String }
f: (b: Boolean)A
But this is pointless. Types are a compile time information, and that information is getting lost here.
How about an absolutely minimal change to the "fictional code"? If we just add [_] after the "fictional" return type, the code will compile:
class A[T]
def f(switch: Boolean):A[_] = if(switch) new A[Int] else new A[String]
It is worth noting that A[_] is not the same as A[Any]. A[T] does not need to be defined covariant for the code to compile.
Unfortunately, information about the type gets lost.