I'm trying to do some implicit magic in my code but the issue is very simple and I have extracted it out here. It seems a bit strange since from what I've read the following should work.
implicit class Foo(value: Double) {
def twice = 2*value
}
2.0.twice
implicit def strToDouble(x: String) = Try(x.toDouble) match {
case Success(d) => d
case Failure(_) => 0.0
}
strToDouble("2.0").twice
val a: Double = "2.0"
val b: Double = "equals 0.0"
"2.0".twice
I get a compile error
value twice is not a member of String
[error] "2.0".twice
I get you compiler, twice is defined for Doubles, not Strings. But I did tell you how to go from Strings to Doubles, and there is no ambiguity here (as far as I can tell), so shouldn't you be able to note that "2.0".twice can be done by doing strToDouble("2.0").twice?
Am I missing something here? Or is this an optimisation so that the compiler doesn't try out all the possible permutations of implicits (which would grow super-exponentially, I think as a factorial). I suppose I'm looking for a confirmation or rejection of this really.
Thanks
If you want extension method to be applicable even after implicit conversion, you can fix the definition of implicit class
implicit class Foo[A](value: A)(implicit ev: A => Double) {
def twice: Double = 2 * value
}
implicit def strToDouble(x: String): Double = ???
2.0.twice //compiles
"2.0".twice //compiles
I get you compiler, twice is defined for Doubles, not Strings. But I
did tell you how to go from Strings to Doubles, and there is no
ambiguity here (as far as I can tell), so shouldn't you be able to
note that "2.0".twice can be done by doing strToDouble("2.0").twice?
According to specification implicit conversions are applicable in three cases only
Why can't the compiler select the correct String.contains method when using this lambda shorthand?
https://scala-lang.org/files/archive/spec/2.13/07-implicits.html#views
The conversion of 2.0.twice to Foo(2.0).twice is the 2nd case and the conversion of "2.0" to strToDouble("2.0") is the 1st case. As you can see there is no item that they can be applied together. So if you want them to be applicable together you should specify that explicitly like I showed above.
Similarly if you defined conversions from A to B and from B to C this doesn't mean you have a conversion from A to C
case class A(i: Int)
case class B(i: Int)
case class C(i: Int)
implicit def aToB(a: A): B = B(a.i)
implicit def bToC(b: B): C = C(b.i)
A(1): B // compiles
B(1): C // compiles
// A(1): C //doesn't compile
Related
I want to understand how to go about implementing the following use-case using typeclasses in Scala (or find out if it is even possible).
Given a sealed trait and a couple of concrete cases:
sealed trait Base
case class Impl1() extends Base
case class Impl2() extends Base
Given a typeclass operating on Base and an instance for each of the corresponding base implementations:
trait Processor[B <: Base]:
def process(b: B): String
given Processor[Impl1] with:
def process(b: Impl1): String = ??? // not important
given Processor[Impl2] with:
def process(b: Impl2): String = ??? // not important
Given a list of base objects:
val objects: List[Base] = ??? // whatever
Is it possible to implement a method that goes something like this?
val processed = objects.map(obj => process(obj))
def process[B <: Base](b: B)(using proc: Processor[B]) = proc.process(b)
When I try to naively implement the above as-such, the compiler complains that it can't find an implicit for Processor[Base], which I guess it makes sense, since in the context of the method call for process(obj), the obj val has the Base type.
What I would like to do is to let the compiler figure out the concrete type of obj, fetch the corresponding given instance for the concrete type and inject it into the process method. Is it even possible to do such a thing? Does it even make sense?
(Note - I've written my code in scala 3, but I'll gladly accept an answer in scala 2 syntax).
With a list of base objects you won't be able to do it, the list doesn't contain the real type at compile time and the compiler won't be able to find their respective type classes.
In scala 3 the typed list is the tuple, so you can use a tuple to have a typed list and obtain what you are expecting. The method you need is and adaptation of the one you can find with the same name in the scala 3 documentation and is simple as:
inline def summonAll[T <: Tuple](tup: T): List[String] =
inline tup match
case _: EmptyTuple => Nil
case tupl: (t *: ts) => summonInline[Processor[t]].process(tupl.head) :: summonAll[ts](tupl.tail)
and you can use it only passing the list of elements you want to obtain in a tuple in the expected type:
summonAll[(A, B)]
Here you can see the following full code running:
import scala.compiletime.{erasedValue, summonInline}
trait Processor[A]:
def process(t: A): String
object Processor:
def apply[T: Processor]: Processor[T] = summon[Processor[T]]
given Processor[String] with
def process(t: String): String = "im String: " + t
given Processor[Int] with
def process(t: Int): String = "im Int: " + t
inline def summonAll[T <: Tuple](tup: T): List[String] =
inline tup match
case _: EmptyTuple => Nil
case tupl: (t *: ts) => summonInline[Processor[t]].process(tupl.head) :: summonAll[ts](tupl.tail)
val t1 = ("hi", "bye", 44 )
val t2 = summonAll(t1)
println(t2) //List(im String: hi, im String: bye, im Int: 44)
With this particular typeclass you can easily create the Processor[Base] which the compiler asks for:
given Processor[Base] with:
def process(b: Base): String = b match
case b: Impl1 => process(b)
case b: Impl2 => process(b)
Using type class derivation you can also generate it automatically, but I am afraid it's going to be far more code! And if you enable warnings (which you should), the compiler should warn you about a non-exhaustive match if a new subclass is added anyway. So I'd use this manual version unless you have quite a lot of subclasses to handle in your actual case or they change often.
Note "this particular typeclass" it wouldn't work e.g. if process took more than 1 B parameter, or some parameters with more complex types containing B.
There is a difference in the way the scala 2.13.3 compiler determines which overloaded function to call compared to which overloaded implicit to pick.
object Thing {
trait A;
trait B extends A;
trait C extends A;
def f(a: A): String = "A"
def f(b: B): String = "B"
def f(c: C): String = "C"
implicit val a: A = new A {};
implicit val b: B = new B {};
implicit val c: C = new C {};
}
import Thing._
scala> f(new B{})
val res1: String = B
scala> implicitly[B]
val res2: Thing.B = Thing$$anon$2#2f64f99f
scala> f(new A{})
val res3: String = A
scala> implicitly[A]
^
error: ambiguous implicit values:
both value b in object Thing of type Thing.B
and value c in object Thing of type Thing.C
match expected type Thing.A
As we can see, the overload resolution worked for the function call but not for the implicit pick. Why isn't the implicit offered by val a be chosen as occurs with function calls? If the callers ask for an instance of A why the compilers considers instances of B and C when an instance of A is in scope. There would be no ambiguity if the resolution logic were the same as for function calls.
Edit 2:
The Edit 1 was removed because the assertion I wrote there was wrong.
In response to the comments I added another test to see what happens when the implicit val c: C is removed. In that case the compiler don't complains and picks implicit val b: B despite the caller asked for an instance of A.
object Thing {
trait A { def name = 'A' };
trait B extends A { def name = 'B' };
trait C extends A { def name = 'C' };
def f(a: A): String = "A"
def f(b: B): String = "B"
implicit val a: A = new A {};
implicit val b: B = new B {};
}
import Thing._
scala> f(new A{})
val res0: String = A
scala> implicitly[A].name
val res3: Char = B
So, the overloading resolution of implicit differs from function calls more than I expected.
Anyway, I still don't find a reason why the designers of scala decided to apply a different resolution logic for function and implicit overloading. (Edit: Later noticed why).
Let's see what happens in a real world example.
Suppose we are doing a Json parser that converts a Json string directly to scala Abstract data types, and we want it to support many standard collections.
The snippet in charge of parsing the iterable collections would be something like this:
trait Parser[+A] {
def parse(input: Input): ParseResult;
///// many combinators here
}
implicit def summonParser[T](implicit parserT: Parser[T]) = parserT;
/** #tparam IC iterator type constructor
* #tparam E element's type */
implicit def iterableParser[IC[E] <: Iterable[E], E](
implicit
parserE: Parser[E],
factory: IterableFactory[IC]
): Parser[IC[E]] = '[' ~> skipSpaces ~> (parserE <~ skipSpaces).repSepGen(coma <~ skipSpaces, factory.newBuilder[E]) <~ skipSpaces <~ ']';
Which requires a Parser[E] for the elements and a IterableFactory[IC] to construct the collection specified by the type parameters.
So, we have to put in implicit scope an instance of IterableFactory for every collection type we want to support.
implicit val iterableFactory: IterableFactory[Iterable] = Iterable
implicit val setFactory: IterableFactory[Set] = Set
implicit val listFactory: IterableFactory[List] = List
With the current implicit resolution logic implemented by the scala compiler, this snippet works fine for Set and List, but not for Iterable.
scala> def parserInt: Parser[Int] = ???
def parserInt: read.Parser[Int]
scala> Parser[List[Int]]
val res0: read.Parser[List[Int]] = read.Parser$$anonfun$pursue$3#3958db82
scala> Parser[Vector[Int]]
val res1: read.Parser[Vector[Int]] = read.Parser$$anonfun$pursue$3#648f48d3
scala> Parser[Iterable[Int]]
^
error: could not find implicit value for parameter parserT: read.Parser[Iterable[Int]]
And the reason is:
scala> implicitly[IterableFactory[Iterable]]
^
error: ambiguous implicit values:
both value listFactory in object IterableParser of type scala.collection.IterableFactory[List]
and value vectorFactory in object IterableParser of type scala.collection.IterableFactory[Vector]
match expected type scala.collection.IterableFactory[Iterable]
On the contrary, if the overloading resolution logic of implicits was like the one for function calls, this would work fine.
Edit 3: After many many coffees I noticed that, contrary to what I said above, there is no difference between the way the compiler decides which overloaded functions to call and which overloaded implicit to pick.
In the case of function call: from all the functions overloads such that the type of the argument is asignable to the type of the parameter, the compiler chooses the one such that the function's parameter type is assignable to all the others. If no function satisfies that, a compilation error is thrown.
In the case of implicit pick up: from all the implicit in scope such that the type of the implicit is asignable to the asked type, the compiler chooses the one such that the declared type is asignable to all the others. If no implicit satisfies that, an compilation error is thrown.
My mistake was that I didn't notice the inversion of the assignability.
Anyway, the resolution logic I proposed above (give me what I asked for) is not entirely wrong. It's solves the particular case I mentioned. But for most uses cases the logic implemented by the scala compiler (and, I suppose, all the other languages that support type classes) is better.
As explained in the Edit 3 section of the question, there are similitudes between the way the compiler decides which overloaded functions to call and which overloaded implicit to pick. In both cases the compiler does two steps:
Filters out all the alternatives that are not asignable.
From the remaining alternatives choses the most specific or complains if there is more than one.
In the case of the function call, the most specific alternative is the function with the most specific parameter type; and in the case of implicit pick is the instance with the most specific declared type.
But, if the logic in both cases were exactly the same, then why did the example of the question give different results? Because there is a difference: the assignability requirement that determines which alternatives pass the first step are oposite.
In the case of the function call, after the first step remain the functions whose parameter type is more generic than the argument type; and in the case of implicit pick, remain the instances whose declared type is more specific than the asked type.
The above words are enough to answers the question itself but don't give a solution to the problem that motivated it, which is: How to force the compiler to pick the implicit instance whose declared type is exactly the same than the summoned type? And the answer is: wrapping the implicit instances inside a non variant wrapper.
I am working on a system of chained implicit functions, which is similar to the simplified example below. The test c1.payload == c2.payload represents a test I need to do that is not in "type-space"; I had expected that I would drop into a macro for the definition of witnessEvidence, however Scala apparently does not allow macro definitions with implicit arguments of arbitrary type (WeakTypeTag values only!), and so I am a bit stumped about how to proceed with this. The code below shows logically what I'd like to happen, however an implicit function can't conditionally produce or not produce evidence (unless it is inside a macro implementation).
case class Capsule[T](payload: Int)
trait A
trait B
trait C
implicit val capa = Capsule[A](3)
implicit val capb = Capsule[B](3)
implicit val capc = Capsule[C](7)
case class Evidence[T1, T2](e: Int)
implicit def witnessEvidence[T1, T2](implicit c1: Capsule[T1], c2: Capsule[T2]): Evidence[T1, T2] = {
if (c1.payload == c2.payload)
Evidence[T1, T2](c1.payload)
else
// Do not produce the evidence
}
def foo[T1, T2](implicit ev: Evidence[T1, T2]) = ev.e
val f1 = foo[A, B] // this should compile
val f2 = foo[A, C] // this should fail with missing implicit!
This would not be possible as-is, since the implicit resolution is done at compilation, while testing for value equivalence is done at runtime.
To make this work, you need to make the compiler understand values as types, so that you can ask for the type equality of the two 3s and use that to infer that capa =:= capb. To do that you can use singleton types: https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#singleton-typed-literals
If you need to do arithmetic beyond plain equality comparison, you will need to use Nat:https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/nat.scala
I've been experimenting with implicit conversions, and I have a decent understanding of the 'enrich-my-libray' pattern that uses these. I tried to combine my understanding of basic implicits with the use of implicit evidence... But I'm misunderstanding something crucial, as shown by the method below:
import scala.language.implicitConversions
object Moo extends App {
case class FooInt(i: Int)
implicit def cvtInt(i: Int) : FooInt = FooInt(i)
implicit def cvtFoo(f: FooInt) : Int = f.i
class Pair[T, S](var first: T, var second: S) {
def swap(implicit ev: T =:= S, ev2: S =:= T) {
val temp = first
first = second
second = temp
}
def dump() = {
println("first is " + first)
println("second is " + second)
}
}
val x = new Pair(FooInt(200), 100)
x.dump
x.swap
x.dump
}
When I run the above method I get this error:
Error:(31, 5) Cannot prove that nodescala.Moo.FooInt =:= Int.
x.swap
^
I am puzzled because I would have thought that my in-scope implict conversion would be sufficient 'evidence' that Int's can be converted to FooInt's and vice versa. Thanks in advance for setting me straight on this !
UPDATE:
After being unconfused by Peter's excellent answer, below, the light bulb went on for me one good reason you would want to use implicit evidence in your API. I detail that in my own answer to this question (also below).
=:= checks if the two types are equal and FooInt and Int are definitely not equal, although there exist implicit conversion for values of these two types.
I would create a CanConvert type class which can convert an A into a B :
trait CanConvert[A, B] {
def convert(a: A): B
}
We can create type class instances to transform Int into FooInt and vise versa :
implicit val Int2FooInt = new CanConvert[Int, FooInt] {
def convert(i: Int) = FooInt(i)
}
implicit val FooInt2Int = new CanConvert[FooInt, Int] {
def convert(f: FooInt) = f.i
}
Now we can use CanConvert in our Pair.swap function :
class Pair[A, B](var a: A, var b: B) {
def swap(implicit a2b: CanConvert[A, B], b2a: CanConvert[B, A]) {
val temp = a
a = b2a.convert(b)
b = a2b.convert(temp)
}
override def toString = s"($a, $b)"
def dump(): Unit = println(this)
}
Which we can use as :
scala> val x = new Pair(FooInt(200), 100)
x: Pair[FooInt,Int] = (FooInt(200), 100)
scala> x.swap
scala> x.dump
(FooInt(100), 200)
A =:= B is not evidence that A can be converted to B. It is evidence that A can be cast to B. And you have no implicit evidence anywhere that Int can be cast to FooInt vice versa (for good reason ;).
What you are looking for is:
def swap(implicit ev: T => S, ev2: S => T) {
After working through this excercise I think I have a better understanding of WHY you'd want to use implicit evidence serves in your API.
Implicit evidence can be very useful when:
you have a type parameterized class that provides various methods
that act on the types given by the parameters, and
when one or more of those methods only make sense when additional
constraints are placed on parameterized types.
So, in the case of the simple API given in my original question:
class Pair[T, S](var first: T, var second: S) {
def swap(implicit ev: T =:= S, ev2: S =:= T) = ???
def dump() = ???
}
We have a type Pair, which keeps two things together, and we can always call dump() to examine the two things. We can also, under certain conditions, swap the positions of the first and second items in the pair. And those conditions are given by the implicit evidence constraints.
The Programming in Scala book gives a nice example of how this technique
is used in Scala collections, specifically on the toMap method of Traversables.
The book points out that Map's constructor
wants key-value pairs, i.e., two-tuples, as arguments. If we have a
sequence [Traversable] of pairs, wouldn’t it be nice to create a Map
out of them in one step? That’s what toMap does, but we have a
dilemma. We can’t allow the user to call toMap if the sequence is not
a sequence of pairs.
So there's an example of a type [Traversable] that has a method [toMap] that can't be used in all situations... It can only be used when the compiler can 'prove' (via implicit evidence) that the items in the Traversable are pairs.
Looking at some scala-docs of my libraries, it appeared to me that there is some unwanted noise from value classes. For example:
implicit class RichInt(val i: Int) extends AnyVal {
def squared = i * i
}
This introduces an unwanted symbol i:
4.i // arghh....
That stuff appears both in the scala docs and in the IDE auto completion which is really not good.
So... any ideas of how to mitigate this problem? I mean you can use RichInt(val self: Int) but that doesn't make it any better (4.self, wth?)
EDIT:
In the following example, does the compiler erase the intermediate object, or not?
import language.implicitConversions
object Definition {
trait IntOps extends Any { def squared: Int }
implicit private class IntOpsImpl(val i: Int) extends AnyVal with IntOps {
def squared = i * i
}
implicit def IntOps(i: Int): IntOps = new IntOpsImpl(i) // optimised or not?
}
object Application {
import Definition._
// 4.i -- forbidden
4.squared
}
In Scala 2.11 you can make the val private, which fixes this issue:
implicit class RichInt(private val i: Int) extends AnyVal {
def squared = i * i
}
It does introduce noise (note: in 2.10, in 2.11 and beyond you just declare the val private). You don't always want to. But that's the way it is for now.
You can't get around the problem by following the private-value-class pattern because the compiler can't actually see that it's a value class at the end of it, so it goes through the generic route. Here's the bytecode:
12: invokevirtual #24;
//Method Definition$.IntOps:(I)LDefinition$IntOps;
15: invokeinterface #30, 1;
//InterfaceMethod Definition$IntOps.squared:()I
See how the first one returns a copy of the class Definition$IntOps? It's boxed.
But these two patterns work, sort of:
(1) Common name pattern.
implicit class RichInt(val repr: Int) extends AnyVal { ... }
implicit class RichInt(val underlying: Int) extends AnyVal { ... }
Use one of these. Adding i as a method is annoying. Adding underlying when there is nothing underlying is not nearly so bad--you'll only hit it if you're trying to get the underlying value anyway. And if you keep using the same name over and over:
implicit class RicherInt(val repr: Int) extends AnyVal { def sq = repr * repr }
implicit class RichestInt(val repr: Int) extends AnyVal { def cu = repr * repr * repr }
scala> scala> 3.cu
res5: Int = 27
scala> 3.repr
<console>:10: error: type mismatch;
found : Int(3)
required: ?{def repr: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method RicherInt of type (repr: Int)RicherInt
and method RichestInt of type (repr: Int)RichestInt
the name collision sorta takes care of your problem anyway. If you really want to, you can create an empty value class that exists only to collide with repr.
(2) Explicit implicit pattern
Sometimes you internally want your value to be named something shorter or more mnemonic than repr or underlying without making it available on the original type. One option is to create a forwarding implicit like so:
class IntWithPowers(val i: Int) extends AnyVal {
def sq = i*i
def cu = i*i*i
}
implicit class EnableIntPowers(val repr: Int) extends AnyVal {
def pow = new IntWithPowers(repr)
}
Now you have to call 3.pow.sq instead of 3.sq--which may be a good way to carve up your namespace!--and you don't have to worry about the namespace pollution beyond the original repr.
Perhaps the problem is the heterogeneous scenarios for which value classes were plotted. From the SIP:
• Inlined implicit wrappers. Methods on those wrappers would be translated to extension methods.
• New numeric classes, such as unsigned ints. There would no longer need to be a boxing overhead for such classes. So this is similar to value classes in .NET.
• Classes representing units of measure. Again, no boxing overhead would be incurred for these classes.
I think there is a difference between the first and the last two. In the first case, the value class itself should be transparent. You wouldn't expect anywhere a type RichInt, but you only really operate on Int. In the second case, e.g. 4.meters, I understand that getting the actual "value" makes sense, hence requiring a val is ok.
This split is again reflected in the definition of a value class:
1. C must have exactly one parameter, which is marked with val and which has public accessibility.
...
7. C must be ephemeral.
The latter meaning it has no other fields etc., contradicting No. 1.
With
class C(val u: U) extends AnyVal
the only ever place in the SIP where u is used, is in example implementations (e.g. def extension$plus($this: Meter, other: Meter) = new Meter($this.underlying + other.underlying)); and then in intermediate representations, only to be erased again finally:
new C(e).u ⇒ e
The intermediate representation being accessible for synthetic methods IMO is something that could also be done by the compiler, but should not be visible in the user written code. (I.e., you can use a val if you want to access the peer, but don't have to).
A possibility is to use a name that is shadowed:
implicit class IntOps(val toInt: Int) extends AnyVal {
def squared = toInt * toInt
}
Or
implicit class IntOps(val toInt: Int) extends AnyVal { ops =>
import ops.{toInt => value}
def squared = value * value
}
This would still end up in the scala-docs, but at least calling 4.toInt is neither confusing, no actually triggering IntOps.
I'm not sure it's "unwanted noise" as I think you will almost always need to access the underlying values when using your RichInt.
Consider this:
// writing ${r} we use a RichInt where an Int is required
scala> def squareMe(r: RichInt) = s"${r} squared is ${r.squared}"
squareMe: (r: RichInt)String
// results are not what we hoped, we wanted "2", not "RichInt#2"
scala> squareMe(2)
res1: String = RichInt#2 squared is 4
// we actually need to access the underlying i
scala> def squareMeRight(r: RichInt) = s"${r.i} squared is ${r.squared}"
squareMe: (r: RichInt)String
Also, if you had a method that adds two RichInt you would need again to access the underlying value:
scala> implicit class ImplRichInt(val i: Int) extends AnyVal {
| def Add(that: ImplRichInt) = new ImplRichInt(i + that) // nope...
| }
<console>:12: error: overloaded method value + with alternatives:
(x: Int)Int <and>
(x: Char)Int <and>
(x: Short)Int <and>
(x: Byte)Int
cannot be applied to (ImplRichInt)
def Add(that: ImplRichInt) = new ImplRichInt(i + that)
^
scala> implicit class ImplRichInt(val i: Int) extends AnyVal {
| def Add(that: ImplRichInt) = new ImplRichInt(i + that.i)
| }
defined class ImplRichInt
scala> 2.Add(4)
res7: ImplRichInt = ImplRichInt#6