Difference between conversion with implicit function and implicit class in Scala - scala

For implicit conversion in Scala, I can use either implicit conversion function
implicit def intToX(i:Int):X = new X(i)
1.myMethod // -1
or implicit class
implicit class X(i: Int) {
def myMethod = - i
}
1.myMethod // -1
Is there any difference between the two? When should I prefer one over the other?
There is a related question about implicit conversion vs. type class but it only compares implicit functions and type classes. What I am interested is the difference from implicit classes.

Implicit class is a syntax sugar for implicit method and a class:
http://docs.scala-lang.org/sips/completed/implicit-classes.html:
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)
Implicit classes were added in scala 2.10 because it is was very common to define new class with defining implicit method conversion to it.
But if you do not need to define a new class but defining implicit conversion to existing class you should better use an implicit method

It's been a while sice you asked a question and it seems that things have changed since. Actually, you should always choose implicit classes over implicit conversions now.
Implicit conversions have been marked as an advanced language feature by scala and the compiler discourages use of them (at least in Scala 2.12). And you need to add an extra flag (-language:implicitConversions) to the compile options to turn it off. See scala-lang docs
Also, Scala community (or at least LightBend/Typesafe people) are even planning of getting rid of imlicit conversions in general. This was mention in a conference talk in 2017 Nov presenting Scala 2.13, you can find it here.

Related

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() = ???
...

Explanation for "illegal cyclic reference" involving implicits

In my project, I have a type A, used for arguments in a few places, where I want a bunch of types automatically converted to that type. I've implemented this using a few implicit classes in the companion object of A. I've removed everything not necessary to trigger the problem:
trait A
object A {
implicit class SeqA[T](v: Seq[T])(implicit x: T => A) extends A
implicit class IntA(v: Int) extends A
implicit class TupleA(v: (Int, Int)) extends SeqA(Seq(v._1, v._2))
}
But scalac rejects this code because of an illegal cyclic reference:
$ scalac -version
Scala compiler version 2.12.8 -- Copyright 2002-2018, LAMP/EPFL and Lightbend, Inc.
$ scalac A.scala
A.scala:5: error: illegal cyclic reference involving class TupleA
implicit class TupleA(v: (Int, Int)) extends SeqA(Seq(v._1, v._2))
^
one error found
What exactly is the problem here? What is the compiler tying to do/infer/resolve that involves an illegal cylce?
Bonus points for a valid way to implement these implicit classes.
You're running into SI-9553, a three-and-a-half-year-old compiler bug.
The reason the bug hasn't been fixed is probably in part because there's an extremely simple workaround—just put an explicit type parameter on the generic class you're extending:
trait A
object A {
implicit class SeqA[T](v: Seq[T])(implicit x: T => A) extends A
implicit class IntA(v: Int) extends A
implicit class TupleA(v: (Int, Int)) extends SeqA[Int](Seq(v._1, v._2))
}
This is probably a good idea anyway, since you're asking for trouble any time you let type parameters get inferred where implicit definitions are involved.
As a side note, you can investigate issues like this with a compiler option like -Xprint:typer. In this case it shows the following in a REPL:
// ...
implicit class TupleA extends $line6.$read.$iw.$iw.A.SeqA[Int] {
<paramaccessor> private[this] val v: (Int, Int) = _;
def <init>(v: (Int, Int)): $line6.$read.$iw.$iw.A.TupleA = {
TupleA.super.<init>(scala.collection.Seq.apply[Int](v._1, v._2))({
((v: Int) => A.this.IntA(v))
});
()
}
};
implicit <synthetic> def <TupleA: error>(v: (Int, Int)): <error> = new TupleA(v)
Which in this case isn't terribly helpful, but it at least indicates that the problem is happening in the definition of the synthetic conversion method for the TupleA implicit class, and not at some point before that.

Scala Type Classes Best Practices

I'm reading through and working my way through using type classes and I came across this way of defining type classes from the Shapeless guide:
So here goes the example:
object CsvEncoder {
// "Summoner" method
def apply[A](implicit enc: CsvEncoder[A]): CsvEncoder[A] =
enc
// "Constructor" method
def instance[A](func: A => List[String]): CsvEncoder[A] =
new CsvEncoder[A] {
def encode(value: A): List[String] =
func(value)
}
// Globally visible type class instances
}
What I do not understand is the need for the apply method? What is it doing in this context above?
Later on, the guide describes how I could create a type class instance:
implicit val booleanEncoder: CsvEncoder[Boolean] =
new CsvEncoder[Boolean] {
def encode(b: Boolean): List[String] =
if(b) List("yes") else List("no")
}
is actually shortened to:
implicit val booleanEncoder: CsvEncoder[Boolean] =
instance(b => if(b) List("yes") else List("no"))
So my question now is, how does this work? What I do not get is the need for the apply method?
EDIT: I came across a blog post that describes the steps in creating type classes as below:
Define typeclass contract trait Foo.
Define a companion object Foo with a helper method apply that acts like implicitly, and a way of defining Foo instances typically from a function.
Define FooOps class that defines unary or binary operators.
Define FooSyntax trait that implicitly provides FooOps from a Foo instance.
So what is the deal with point number 2, 3 and 4?
Most of those practices came from Haskell (basically an intention to mimic Haskell's type-classes is a reason for so much boilerplate), some of it is just for convenience. So,
2) As #Alexey Romanov mentioned, companion object with apply is just for convenience, so instead of implicitly[CsvEncoder[IceCream]] you could write just CsvEncoder[IceCream] (aka CsvEncoder.apply[IceCream]()), which will return you a required type-class instance.
3) FooOps provides convenience methods for DSLs. For instance you could have something like:
trait Semigroup[A] {
...
def append(a: A, b: A)
}
import implicits._ //you should import actual instances for `Semigroup[Int]` etc.
implicitly[Semigroup[Int]].append(2,2)
But sometimes it's inconvenient to call append(2,2) method, so it's a good practice to provide a symbolic alias:
trait Ops[A] {
def typeClassInstance: Semigroup[A]
def self: A
def |+|(y: A): A = typeClassInstance.append(self, y)
}
trait ToSemigroupOps {
implicit def toSemigroupOps[A](target: A)(implicit tc: Semigroup[A]): Ops[A] = new Ops[A] {
val self = target
val typeClassInstance = tc
}
}
object SemiSyntax extends ToSemigroupOps
4) You can use it as follows:
import SemiSyntax._
import implicits._ //you should also import actual instances for `Semigroup[Int]` etc.
2 |+| 2
If you wonder why so much boilerplate, and why scala's implicit class syntax doesn't provide this functionality from scratch - the answer is that implicit class actually provides a way to create DSL's - it's just less powerful - it's (subjectively) harder to provide operation aliases, deal with more complex dispatching (when required) etc.
However, there is a macro solution that generates boilerplate automatically for you: https://github.com/mpilquist/simulacrum.
One another important point about your CsvEncoder example is that instance is convenience method for creating type-class instances, but apply is a shortcut for "summoning" (requiring) those instances. So, first one is for library extender (a way to implement interface), another one is for a user (a way to call a particular operation provided for that interface).
Another thing to note is that in shapeless the apply method is not only for cuter syntax.
Take for instance this simplified version of shapeless' Generic and some case class Foo.
trait Generic[T] {
type Repr
}
object Generic {
def apply[T](implicit gen: Generic[T]): Generic[T] { type Repr = gen.Repr } = gen
/* lots of macros to generate implicit instances omitted */
}
case class Foo(a: Int, b: String)
Now when I call Generic[Foo] I will get an instance that is typed as Generic[Foo] { type Repr = Int :: String :: HNil }. But if I call implicitly[Generic[Foo]] all the compiler knows about the result is that it's a Generic[Foo]. In other words: the concrete type of Repr is lost and I can't do anything useful with it. The reason is that implicitly is implemented as follows:
def implicitly[T](implicit e: T): T = e
That method declaration basically says: if you ask for a T I promise to give you a T, if I find one, and nothing more. So that means you'd have to ask implicitly[Generic[Foo] { type Repr = Int :: String :: HNil }] and that defeats the purpose of having automatic derivation.
Quoting the guide immediately after the object CsvEncoder definition:
The apply method ... allows us to summon a type class instance given a target type:
CsvEncoder[IceCream]
// res9: CsvEncoder[IceCream] = ...

Implicit class vs Implicit conversion to trait

I'm trying to add new functions to existing types (so I can have the IDE auto suggest relevant functions for types I don't have control over, eg Future[Option[A]]). I've explored both implicit classes and implicit conversions to accomplish this and they both seem to offer the same behavior.
Is there any effective difference between using an implicit class:
case class Foo(a: Int)
implicit class EnrichedFoo(foo: Foo) {
def beep = "boop"
}
Foo(1).beep // "boop"
And using an implicit conversion:
case class Foo(a: Int)
trait Enriched {
def beep: String
}
implicit def fooToEnriched(foo: Foo) = new Enriched {
def beep = "boop"
}
Foo(1).beep // "boop"
I suppose one difference here might be that the first example creates a one-off class instead of a trait, but I could easily adapt the implicit class to extend an abstract trait, eg:
case class Foo(a: Int)
trait Enriched {
def beep: String
}
implicit class EnrichedFoo(foo: Foo) extends Enriched {
def beep = "boop"
}
Foo(1).beep // "boop"
As far as I'd know, they're pretty much exactly the same. The scoping rules also equally apply to both.
In my opinion, I'd use the implicit classes for your kind of situation. They were probably created exactly for something like that.
Implicit conversions, to me, are more appropriate when you already actually have two different kind of classes and want to convert between the two.
You can check out the initial proposal for implicit classes right here.
There it says:
A new language construct is proposed to simplify the creation of classes which provide extension methods to another type.
You can even see how it desugars implicit classes. The following:
implicit class RichInt(n: Int) extends Ordered[Int] {
def min(m: Int): Int = if (n <= m) n else m
...
}
will desugar into:
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)
Well to me its a matter of preference. Actually the implicit classes came into being to ease the creation of classes which provide extension methods to another type.
Implicit classes add a lot of value to value classes though.
To add on Luka Jacobowitz answer: Implicit classes are basically extensions. Implicit conversion is used to tell the compiler that it may be treated as something with extension.
Sounds nearly the same. Two things of interest from implicit conversion to have some difference:
First: You may need to activate the language feature for disabling warnings when using implicit conversion.
Second: The term of "converting" the type may be confusing:
Implicit conversions are applied in two situations:
If an expression e is of type S, and S does not conform to the expression’s expected type T.
[Or:] In a selection e.m with e of type S, if the selector m does not denote a member of S.
case class Foo(a: Int)
trait Enriched {
def beep: String
}
implicit def fooToEnriched(foo: Foo) = new Enriched {
def beep = "boop"
}
Foo(1) match {
case _:Enriched => println("is an Enriched")
case _:Foo => println("no, was a Foo")
}
// no, was a Foo
but it may be treated as an Enriched...
val enriched: Enriched = Foo(2)
enriched match {
case _:Enriched => println("is an Enriched")
case _:Foo => println("no, was a Foo")
}
// is an Enriched
// plus unreachable code warning: case _:Foo => println("no, was a Foo")

Universal/generic boxing from Any to AnyRef

Is it possible to force runtime boxing in scala dynamically? I would like a function:
def box(value :Any) :AnyRef
or
def box[T](value :T) :AnyRef
I have a generic class which may be parameterized with AnyVals but need to pass them to legacy java methods accepting collections of objects. Of course, I could implement it myself with pattern matching, but it's a bit annoying to have to do it time and time again, and it wouldn't work for user value classes.
Edit
The answer turned out as simple as surprising. Now, can I do it through reflection? Assume
class Box[T :TypeTag](private var value :T) {
def get :T = value
def set(o :Any) {
...
}
}
I would like to do a safe set, checking in the runtime if o is a subclass of T like this:
runtimeMirror(getClass.getClassLoader).classSymbol(o.getClass).toType <:< typeOf[T]
Unfortunately, typeOf[T] for Box[Long] will be a primitive, and the following check will fail on java.lang.Long, which is the runtime type of elements of Seq[Long] for example. Bottom line, when using generics with AnyVals, the compiler sometimes boxes them making runtime class checks unpredictible.
Just cast to AnyRef with asInstanceOf and Scala will turn it into an AnyRef:
scala> val x = 13
x: Int = 13
scala> val xBoxed = x.asInstanceOf[AnyRef]
xBoxed: AnyRef = 13
scala> xBoxed.getClass()
res0: Class[_ <: AnyRef] = class java.lang.Integer
For value classes, this will box it in an instance of the value class, instead of the Java class. You could use a generic trait to be able to get the Java boxed versions from your value classes, without using reflection. For example:
trait ValueClass[T] extends Any {
def value: T
def javaBoxed: AnyRef = value.asInstanceOf[AnyRef]
}
case class MyInt(value: Int) extends AnyVal with ValueClass[Int]
case class MyReal(asDouble: Double) extends AnyVal with ValueClass[Double] {
def value = asDouble
}
However, this requires you mix your trait into all your value classes. For value classes that extend Product, like all case classes do, there's a quicker way using productElement:
def javaBox(x: Product): AnyRef = {
if (x.productArity == 1) x.productElement(0).asInstanceOf[AnyRef]
else x.asInstanceOf[AnyRef] // or throw an exception if you prefer
}
Unfortunately, it looks to me like both methods (mix-in trait and Product) cause Scala to do its boxing, meaning when called on an unboxed value, the value goes from unboxed → Scala boxed → unboxed → Java boxed, instead of straight to the Java boxed value.