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.
Related
Define a method which accepts types: List[_ <: AnyVal]
def foo(x : List[_ <: AnyVal]) = x
Try to use an AnyRef:
foo(List(new Test))
error: type mismatch;
found : Test
required: AnyVal
Note that implicit conversions are not applicable because they are ambiguous:
both method ArrowAssoc in object Predef of type [A](self: A)ArrowAssoc[A]
and method Ensuring in object Predef of type [A](self: A)Ensuring[A]
are possible conversion functions from Test to AnyVal
Question 1: In the warning message, why does the compiler ignore the other two "generic to AnyVal" implicit conversions defined in Predef.scala?
final implicit class StringFormat[A] extends AnyVal
final implicit class any2stringadd[A] extends AnyVal
Removing the previous ambiguity and forcing compiler to use the ArrowAssoc implicit conversion:
foo(List(new Test -> 1))
error: the result type of an implicit conversion must be more specific than AnyVal
Question 2: What is this error message implying? Its confusing. The method def -> [B](y: B): Tuple2[A, B] = Tuple2(self, y) in the ArrowAssoc class returns a Tuple2 which is of AnyRef type. So, a more useful error message could have been found Tuple2 required AnyVal?
To answer your second question first. Try this:
class Temp
implicit class Arrow[T](a:T) extends Temp{
def -->[B](b:B) = (a,b)
}
def foo(x : List[_ <: Temp]) = x
scala> foo(List(1 --> 2))
res0: List[Temp] = List(Arrow#2e17a321)
This works as expected. It is not complaining because it was searching for Temp and not Tuple2.
Now introduce ambiguity:
implicit class OtherTemp[T](a:T) extends Temp{}
foo(List(1 --> 2)) //compile error
It fails complaining collisions. So to answer your question on why it didn't show AnyRef is because:
Remember ArrowAssoc is being called to get AnyVal representation. With ->, it has a Tuple2 and is trying to retrieve a AnyVal. And because it is unable to retrieve AnyVal, it marks it as error as failure on inability to convert to AnyVal. Its true identity is irrelevant.
For first question:
In my understanding, implicits go as first search basis. So once it finds two and there is ambiguity, it quits complaining. May be this is why it doesn't try with StringFormat etc. This can be confirmed on repl by re-ordering implicit order
implicit class OtherTemp2[T](a:T) extends Temp{
}
implicit class OtherTemp[T](a:T) extends Temp{
}
foo(List[Temp]("asdf"))
Compiler complains as Arrow and OtherTemp2 as collisions. If you re-order and run repl again, it complains based on which implicit was found first.
But I cant find an official source which confirms this.
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.
I am rather new to Scala programming, so still figuring out canonical ways to doing something. Lately, I wanted to write a function foo that would only accept a set of types for its only parameter. Think of something like
def foo(x: [Int, String]) = ???
But I couldn't find anything close to the syntax above (which I find most natural to me). Using type Any would loose the compile-side checking and would make it easier for problems to escape into the runtime land.
The best I was able to come up with is something like this:
sealed abstract class Base
case class TypeInt(v: Int) extends Base
case class TypeString(v: String) extends Base
implicit def toTypeInt(v: Int) = TypeInt(v)
implicit def toTypeString(v: String) = TypeString(v)
def foo(x: Base) = x match {
case TypeInt(v) => println("Int: ", v)
case TypeString(v) => println("String: ", v)
}
foo(1)
foo("hello")
(As a side note, I would like to be able to just write implicit case class ... to avoid creating manually the toType* functions but that doesn't compile.)
Is there a simpler way to write a function that accepts a parameter of a set of types in a typesafe manner?
UPDATE: It actually turns out that in my specific case I could just have used method overloading. For some reason it's not possible to use method overloading at all in Scala worksheet which made me think that Scala doesn't have overloading at all. But I was wrong - in regular Scala source it should be possible to use that. There are still some shortcomings of overload usage that are described in the article on Magnet pattern that was mentioned in comments below (e.g. there is no way to overload on type Foo[Type1] and Foo[Type2] because of type erasure in JVM generics.
The magnet pattern feels like overkill here—you can use plain old type classes:
trait Fooable[A] { def apply(a: A): Unit }
implicit object intFooable extends Fooable[Int] {
def apply(a: Int) = printf("Int: %d\n", a)
}
implicit object stringFooable extends Fooable[String] {
def apply(a: String) = printf("String: %s\n", a)
}
def foo[A: Fooable](a: A) = implicitly[Fooable[A]].apply(a)
And then:
scala> foo(1)
Int: 1
scala> foo("hello")
String: hello
Suppose you're worried about collisions after erasure. Let's try some instances for a generic type:
trait Bar[A]
implicit object barIntFooable extends Fooable[Bar[Int]] {
def apply(a: Bar[Int]) = println("A bar of ints.")
}
implicit object barStringFooable extends Fooable[Bar[String]] {
def apply(a: Bar[String]) = println("A bar of strings.")
}
And again:
scala> foo(new Bar[Int] {})
A bar of ints.
scala> foo(new Bar[String] {})
A bar of strings.
Everything works as expected.
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
I have two case classes
case class StringCaseClass(argument: String)
case class IntCaseClass(argument: Int)
I want to define a structural type which will match the companion object of both of these
type HasApply1 {
def apply[A, R](argument: A): R
}
This will compile fine, but when I try to use it like this
def method(caseClass: HasApply1) {
// whatever
}
method(StringCaseClass)
I will get a compiler error
found : StringCaseClass.type
required: WithApply1
(which expands to) AnyRef{def apply[A, R](string: A): R}
Is there any way of accomplishing this? If I redefine the structural type to have concrete types for A and R it will compile correctly, but then I lose the flexiblity
#aloiscochard's comment is almost there. What he forgot to mention is that case class companion objects already implement the appropriate FunctionN trait, so you can simply do this,
scala> case class StringCaseClass(argument: String)
defined class StringCaseClass
scala> case class IntCaseClass(argument: Int)
defined class IntCaseClass
scala> def method[A, R](caseClass: A => R, a: A) = caseClass(a)
method: [A, R](caseClass: A => R, a: A)R
scala> method(StringCaseClass, "foo")
res0: StringCaseClass = StringCaseClass(foo)
scala> method(IntCaseClass, 23)
res1: IntCaseClass = IntCaseClass(23)
In general you should avoid structural typing as it's very expensive. The call will be converted into a reflection call because of limitations in the JVM. When you start using scala 2.10 structural types will result in a warning at compile time (though you could disable that using a flag).
If you're looking into a more general way to add functionality to classes that don't share an inheritance hierarchy you could use Type Classes.
Here's a quick example:
trait CanCreateRFromA[A,R]{
def createNew(a:A): R
}
implicit object CanCreateBlahFromInt extends CanCreateRFromA[Int,Blah2]{
def createNew(i:Int):Blah2 = new Blah2(i)
}
implicit object CanCreateBlah1FromString extends CanCreateRFromA[String,Blah1]{
def createNew(s:String):Blah1 = new Blah1(s)
}
case class Blah1(something:String)
case class Blah2(something:Int)
def createRFromA[A,R](a:A)(implicit tc:CanCreateRFromA[A,R])= tc.createNew(a)
Then you can call:
createRFromA(1) // This gives a Blah2
createRFromA("1") // This gives a Blah1
Again I'm not sure what you're trying to accomplish, but it probably is possible to do what you want with a type class and it will be much faster.
You didn't pass an instance of StringCaseClass to your method. What you passed there is companion object of StringCaseClass (which is automatically generated for case classes).
Try if this works: method(StringCaseClass("dummy")).