How to use Scala 2.10 implicit classes - scala

I thought this would be correct usage of the new implicit classes of Scala 2.10:
implicit case class IntOps(i: Int) extends AnyVal {
def twice = i * 2
}
11.twice
Apparently not:
<console>:13: error: value twice is not a member of Int
11.twice
^
Am I missing something (Scala 2.10.0-M6)?

A clue is the desugaring of implicit classes, explained in the SIP-13:
implicit class RichInt(n: Int) extends Ordered[Int] {
def min(m: Int): Int = if (n <= m) n else m
...
}
will be transformed by the compiler as follows:
class RichInt(n: Int) extends Ordered[Int] {
def min(m: Int): Int = if (n <= m) n else m
...
}
implicit final def RichInt(n: Int): RichInt = new RichInt(n)
As you can see, the implicit function that is created has the same name as the original classes. I guess it's done like this to make implicit classes easier to import.
Thus in your case, when you create an implicit case class, there is a conflict between the method name created by the implicit keyword and the companion object created by the case keyword.

This shows there is an ambiguity:
val ops: IntOps = 11
<console>:11: error: ambiguous reference to overloaded definition,
both method IntOps of type (i: Int)IntOps
and object IntOps of type IntOps.type
match argument types (Int) and expected result type IntOps
val ops: IntOps = 11
^
Not sure what exactly happens. But when not using a case class it seems fine:
implicit class IntOps(val i: Int) extends AnyVal {
def twice = i * 2
}
11.twice // ok

Related

What exactly does 'is more specific than' mean in the context of implicits?

So, implicit precedence is based on two factors: one is about the scope of declaration itself having precedence (scope A extending scope/trait B, or scope A being a companion object of a type extended from a type with scope B as its companion object). The other simply mentions that declaration A is more specific than declaration B. Now, when reading it for the first time I had several possible interpretations in mind, especially considering potential parameters (implicit and not) of implicit method and type parameters. Experience seemed to teach me that it means that the type of the returned value by declaration A, after all type inference/tapply, is a subtype of the return type of declaration B. So, this is fine:
class A
class B extends A
implicit val A = new A
implicit val B = new B
implicitly[A]
Why this doesn't compile, then?
implicit class A(val toInt :Int) {
def ! = (1 /: (2 to toInt))(_ * _)
}
implicit class B(i :Int) extends A(i)
1.!
When this does?
class A(val toInt :Int) {
def ! = (1 /: (2 to toInt))(_ * _)
}
class B(i :Int) extends A(i)
implicit val A = { i :Int => new A(i) }
implicit val B = { i :Int => new B(i) }
1.!
Is it another case of 'the compiler works in mysterious ways'?
Based on SIP-13 - IMPLICIT CLASSES proposal your declaration:
implicit class A(val toInt :Int) {
def ! = (1 /: (2 to toInt))(_ * _)
}
Will be transformed to something like:
class A(toInt: Int) {
...
}
implicit final def A(toInt: Int): A = new A(toInt);
And your B in its turn will be transformed to something like:
class B(i: Int) extends A(i) {
...
}
implicit final def B(i: Int): B = new B(i);
So you are basically declaring 2 implicit conversion methods with the same parameters which are ambiguous. While the last one is not ambiguous due to already mentioned "most specific" rule for implicit parameters resolution.

Why can there not be any method, member or object in scope with the same name as the implicit class

There may not be any method, member or object in scope with the same
name as the implicit class.
https://docs.scala-lang.org/overviews/core/implicit-classes.html
Just wondering why this is the case? I know normal classes can have companion objects, why not implicit ones? Is it for the same reason as here
There may not be any method, member or object in scope with the same
name as the implicit class.
Just wondering why this is the case?
The short answer is: because they are methods!
The slightly longer answer is: because implicit classes are syntactic sugar for a class and a method.
Remember what we used to write before there were implicit classes:
final class IntFactorialExtension(n: Int) {
final def ! = (1 to n) reduce (_ * _)
}
implicit def intFactorialExtension(n: Int) = new IntFactorialExtension(n)
5! //=> 120: Int
Scastie link
As defined in SIP-13 – Implicit classes (which is linked from the document you quoted), an implicit class is simply syntactic sugar for a method (implicit conversion) and a class, just like we used to write by hand before implicit classes [bold emphasis mine]:
An implicit class must be defined in a scope where method definitions are allowed (not at the top level). An implicit class is desugared into a class and implicit method pairing, where the implicit method mimics the constructor of the class.
The generated implicit method will have the same name as the implicit class. This allows importing the implicit conversion using the name of the class, as one expects from other implicit definitions. For example, a definition of the form:
implicit class RichInt(n: Int) extends Ordered[Int] {
def min(m: Int): Int = if (n <= m) n else m
...
}
will be transformed by the compiler as follows:
class RichInt(n: Int) extends Ordered[Int] {
def min(m: Int): Int = if (n <= m) n else m
...
}
implicit final def RichInt(n: Int): RichInt = new RichInt(n)
So, because an implicit class desugars into both a name in the type realm (a class) and a name in the value realm (a method / implicit conversion), it must be legal and valid in both the type realm and the value realm, which for the implicit conversion specifically means that there cannot be another name in the value realm in scope.
There could be potential name clashes because
implicit class fooOps(v: TypeWeWantToAddExtensionTo) extends AnyVal {
def extensionMethod1() = ???
}
val v: TypeWeWantToAddExtensionTo = ???
v.extensionMethod1()
expands to
fooOps(v).extensionMethod1()
so if there is another fooOps definition in scope then it could cause name conflict.
Starting Scala 3 this is no longer a problem because we do not have to come up with a name for the implicit class, instead we just write
extension (v: TypeWeWantToAddExtensionTo)
def extensionMethod1() = ???
def extensionMethod2() = ???
...

Scala: implicitly to implicit class

Given:
implicit class Foo(val i: Int) {
def addValue(v: Int): Int = i + v
}
is it possible apply to it any implicitly?
I get an error here:
<console>:14: error: could not find implicit value for parameter e: Foo
implicitly[Foo]
An implicit class Foo(val i: Int) means that there is an implicit conversion from Int to Foo. So implicitly[Int => Foo] should work.
Think about it like this: if you could summon a Foo with implicitly[Foo], which Foo would you expect to get? A Foo(0)? A Foo(1)? A Foo(2)?
For further details,
implcitly key word can be explained as following
implitly[T] means return implicit value of type T in the context
Which means, to get Foo implicitly you need to create an implicit value in the scope
For example,
implicit class Foo(val i: Int) {
def addValue(v: Int): Int = i + v
}
implicit val foo:Foo = Foo(1)
val fooImplicitly = implicitly[Foo] // Foo(1)
Also, note that Foo itself is only a class,
But by putting implicit key word in front of class definition,
Compiler creates an implicit function of type Int => Foo

Scala type bounds =:=

While this compiles:
implicit class Container[T](val value:T) extends AnyVal{
def addInt(x:Int)(implicit ev:T=:=Int) = value+x
}
This complains about type mismatch, expected T, actual Int, as if it ignores the type bound.
implicit class Container[T](val value:T=>Int) extends AnyVal{
def addInt(x:Int)(implicit ev:T=:=Int) = value(x)
}
Why?
Your type constraint is backwards, actually. T =:= Int provides implicit evidence that T is Int, but not exactly that Int is T. If you look at the declaration if =:=, you'll see that it only goes one way:
sealed abstract class =:=[From, To] extends (From => To) with Serializable
Your first example works because value is a T, and the constraint is T =:= Int, which implicitly converts T to Int. But for the second example, we need to feed a T to value: T => Int, so we need the other direction.
This works:
implicit class Container[T](val value: T => Int) extends AnyVal {
def addInt(x: Int)(implicit ev: Int =:= T) = value(x)
}
The reason why your second example using Int <:< T also works is because <:< provides the implicit conversion from Int => T.
Oh probably the issue is the contra-variance of the function. This works now:
implicit class Container[T](val value:T=>Int) extends AnyVal{
def addInt(x:Int)(implicit ev:Int<:<T) = value(x)
}

passing a function with type parameter as argument

I want to create a function g that takes a function f as a parameter, where f has a type parameter. I can't get a signature for g that compiles. One attempt is like this:
scala> def mock1[A](): A = null.asInstanceOf[A] // STUB
mock1: [A]()A
scala> def mock2[A](): A = null.asInstanceOf[A] // STUB
mock2: [A]()A
scala> def g0(f: [A]() => A): Int = f[Int]()
<console>:1: error: identifier expected but '[' found.
def g0(f: [A]() => A): Int = f[Int]()
^
I can get it to work if I wrap the function that takes a type parameter in a trait, like so:
scala> trait FWrapper { def f[A](): A }
defined trait FWrapper
scala> class mock1wrapper extends FWrapper { def f[A]() = mock1[A]() }
defined class mock1wrapper
scala> class mock2wrapper extends FWrapper { def f[A]() = mock2[A]() }
defined class mock2wrapper
scala> def g(wrapper: FWrapper): Int = wrapper.f[Int]()
g: (wrapper: FWrapper)Int
scala> g(new mock1wrapper)
res8: Int = 0
Is there a way I can accomplish this without introducing the wrapper class?
Scala does (currently) not have support for polymorphic function values. You have two options:
Stick with your wrapper trait (probably easiest to understand)
Use polymorphic function values from Shapeless (fancy, but maybe a bit complicated)
How about this:
def mock[A](): A = null.asInstanceOf[A]
def g[A](f:() => A): A = f()
g(mock[Int])