Scala version: 2.12.4.
Let's say, there's one empty trait and one class with function, which accepts trait instance as implicit parameter:
trait I
class A {
def fa()(implicit i: I): Unit = {}
}
Let's define another class, which invokes this fa() function. We'll try to import I instance from its companion object:
class B(a: A) {
import B._
def fb(): Unit = { a.fa() }
}
object B {
private implicit object II extends I
}
But we face an error then!
error: could not find implicit value for parameter i: I
def fb(): Unit = { a.fa() }
^
Let's make implicit val then in class B:
class B(a: A) {
import B._
private implicit val ii = II
def fb(): Unit = { a.fa() }
}
Suddenly, we still face an error anyway:
error: ambiguous implicit values:
both value ii in class B of type => B.II.type
and object II in object B of type B.II.type
match expected type I
def fb(): Unit = { a.fa() }
^
Compiler doesn't see implicit in the first case, but sees the same implicit in the second case. Why?
How to import this implicit object from companion object?
This is an ordering issue with type inference. There are other similar questions, I don't know if there is an exact duplicate.
The issue is that when class B is type-checked, type inference hasn't yet run on object B. Using II in the body of class B in the second example triggers this type inference and makes it visible as an implicit I.
It can be solved by either placing the companion object before the class, or by giving explicit type to II, e.g.
object B {
private implicit val II: I = new I {}
}
See e.g. Why does this explicit call of a Scala method allow it to be implicitly resolved?
Related
I searched online but didn't get a useful result. Maybe this is stupid but I'm trying to make it work.
The description of my question can be shown in the following example:
trait EnumType
class MyEnum extends EnumType
trait Coherence[S <: EnumType] {
def printS(s: S): Unit
}
class MyCoherence extends Coherence[EnumType] {
override def printS(s: EnumType): Unit = println("printS in MyCoherence")
}
case class MyCaseClass(coh: Coherence[_ <: EnumType])
object HelloWorld {
def main(args: Array[String]) {
val myCoh = new MyCoherence
val m = MyCaseClass(myCoh)
val myEnum = new MyEnum
myCoh.printS(myEnum)
m.coh.printS(myEnum) // >>> problematic line 21
println("Hello, world!")
}
}
As you can see, I have a case class MyCaseClass which takes an instance of Coherence[_ <: EnumType] as parameter.
This instance has a simple printS() which prints some message.
In the main, when I try to call printS of m.coh, the compiler gives the following error:
$scalac *.scala
HelloWorld.scala:21: error: type mismatch;
found : myEnum.type (with underlying type MyEnum)
required: _$1
m.coh.printS(myEnum)
^
one error found
It seems that the type bound of coh is erased when I do m.coh.printS (_$1 instead of _$1 <: EnumType).
I wonder whether I'm missing something for using printS in such a way? Thanks
The type bound isn't erased, just not printed in this situation. The problem is that m.coh could be a Coherence[SomeOtherEnum]:
class SomeOtherEnum extends EnumType
class OtherCoherence extends Coherence[SomeOtherEnum] {
override def printS(s: SomeOtherEnum): Unit = ???
}
val m = MyCaseClass(new OtherCoherence)
Because this m and yours have the same type, m.coh.printS(myEnum) should type-check in both cases or in neither, and it obviously can't work here: it calls OtherCoherence.printS() which only accepts SomeOtherEnum.
You can make it compile by casting m.coh:
m.coh.asInstanceOf[Coherence[EnumType]].printS(myEnum)
But it's unsafe due to the above: if m.coh is a MyCoherence, it will work; if m.coh is an OtherCoherence, it will end up trying to cast myEnum to SomeOtherEnum and throw an exception.
I am trying to express a constraint like:
in a method def run[A, B](...), B must be equal to A#SomeInner
Here is my example code:
trait Wrapper {
type Implementation
implicit val instance: Data[Implementation]
}
trait Data[A] {
def create : A
}
object DataInstances {
implicit object IntData extends Data[Int] { def create = 0}
implicit object StringData extends Data[String] { def create = "<empty>"}
implicit object FloatData extends Data[Float] { def create = 0.5F}
}
import DataInstances._
object IntWrapper extends Wrapper { type Implementation = Int; implicit val instance = IntData }
object StringWrapper extends Wrapper { type Implementation = String; implicit val instance = StringData}
object FloatWrapper extends Wrapper { type Implementation = Float; implicit val instance = FloatData}
object Test extends App {
def run[W <: Wrapper, D](wrapper: W)(implicit data: Data[D], ev: D =:= W#Implementation) : D = {
data.create
}
run(StringWrapper)
}
and here I get a compilation error:
Error:(31, 6) ambiguous implicit values:
both object IntData in object DataInstances of type DataInstances.IntData.type
and object StringData in object DataInstances of type DataInstances.StringData.type
match expected type Data[D]
run(StringWrapper)
^
Can you explain me why the compiler finds it ambiguous?
From what I can tell (and what I tried to express) is that when I pass StringWrapper then, according to type equality evidence the only possible value for D would be String and therefore the only possible value for data would be StringData.
But obviously the compiler doesn't think so :)
And what would be the way to express this constraint properly?
I don't see a reason to introduce type D in method run. Without it method signature looks simpler and successfully compiles
def run[W <: Wrapper](wrapper: W)(implicit data: Data[W#Implementation]) : W#Implementation = {
data.create
}
+++
btw, if you change order of implicits in your original method it will compile too, looks like 'ev' help to "type-bound" implicit resolution for data
def run[W <: Wrapper, D](wrapper: W)(implicit ev: D =:= W#Implementation, data: Data[D]) : D = {
data.create
}
The type class pattern in Scala involves defining a trait such as:
trait Show[T] {
def show(obj: T): String
}
Then you can define instantiations of this type class as such:
object Show {
implicit val string = new Show[String] {
def show(obj: String): String = obj
}
implicit object BooleanShow extends Show[Boolean] {
def show(obj: Boolean): String = obj.toString
}
}
The advantage of defining these instantiations for basic types in the companion object is that they are automatically in scope whenever the type class is concerned (roughly).
Functionally it would appear defining the instantiation as an implicit val or an implicit object does not change much.
Is there a difference? Is one way better than the other?
There is actually more than the type names between val and object.
You know, object in Scala is something like a singleton in Java.
Maybe you thought that both string and BooleanShow are in an object not a class so they have no difference, but that's not true.
They are val and object no matter what.
Try this in Scala REPL.
trait Show[T] {
def show(obj: T): String
}
object Show {
println("!! Show created")
implicit val string = new Show[String] {
println("!! string created")
def show(obj: String): String = obj
}
implicit object BooleanShow extends Show[Boolean] {
println("!!BooleanShow created")
def show(obj: Boolean): String = obj.toString
}
}
If only the definition is done, then no printlns are executed afterwards, since Show is a singleton in effect. It's not created yet.
Next, execute Show in Scala REPL.
scala> Show
!! Show created
!! string created
res0: Show.type = Show$#35afff3b
You see, printlns in Show and Show.string were called, but the one in Show.BooleanShow was not.
You can execute Show.BooleanShow next in Scala REPL.
scala> Show.BooleanShow
!!BooleanShow created
res1: Show.BooleanShow.type = Show$BooleanShow$#18e419c5
Show.BooleanShow was initialized at last. It is a singleton, so it is lazy.
Basically, your question is the same as val and object inside a scala class? except that your val and object are defined in an object, but the linked question tries to find differences val and object defined in a class and the method in val uses reflection (but yours uses overriding, so no reflection is involved). implicit basically does not make difference in what they are.
I think you already know the difference between class and object. Further information can be found in the linked question.
Since they say always to use explicit types for implicits, prefer val over object.
Compare Why can't Scala find my typeclass instance defined implicitly in the companion object, when the typeclass is not in a dedicated source file? where it makes a difference.
Make it lazy if necessary.
Elaboration:
scala> trait T
defined trait T
scala> object X { implicitly[T] ; object O extends T }
<console>:8: error: could not find implicit value for parameter e: T
object X { implicitly[T] ; object O extends T }
^
scala> object X { implicitly[T] ; implicit object O extends T }
<console>:8: error: could not find implicit value for parameter e: T
object X { implicitly[T] ; implicit object O extends T }
^
scala> object X { implicitly[O.type] ; implicit object O extends T }
defined object X
scala> object X { implicitly[T] ; implicit object O extends T ; implicit def y = O }
<console>:8: error: could not find implicit value for parameter e: T
object X { implicitly[T] ; implicit object O extends T ; implicit def y = O }
^
scala> object X { implicitly[T] ; implicit object O extends T ; implicit def y: T = O }
defined object X
The inferred type of O is the singleton type O.type.
With val x = new X { } you are creating an anonymous subclass of X, whereas with object x extends X you create a "proper" subclass. I would think that the overhead of an object is minimal, and as #applicius points out, it has proper name. Therefore I suggest to go for the object in this case.
I have a covariant Scala type Thing[+B]. The implementation uses an internal mutable queue:
private val queue : AsyncQueue[B]()
AsyncQueue is a custom mutable queue implementation, with special properties which I can't easily implement in an immutable version. Because it's mutable, AsyncQueue is invariant. So I can't use it in my covariant type Thing.
Since queue is private, I can guarantee the correctness of my code: e.g. I won't try to assign queue to a reference of type Queue[Any]. How can I make this work, keeping Thing covariant in B, without using casts?
(The solution with casts is to declare an AsyncQueue[Object] and cast objects on enqueue/dequeue, which is very ugly.)
ETA: I understand type covariance, and I understand why I shouldn't be able to declare an AsyncQueue of a covariant type, or make AsyncQueue itself covariant. My question is how to design this code to avoid using casts everywhere.
You can make your member immune to the variance check by making it private[this], according to the spec.
scala> trait Thing[+A] { def next(): A }
defined trait Thing
expectedly,
scala> class Thingie[+A](implicit t: ClassTag[A]) extends Thing[A] { val as = mutable.ArrayBuffer.fill[A](10)(t.runtimeClass.newInstance.asInstanceOf[A]) ; private val it = as.iterator ; def next() = it.next() }
<console>:12: error: covariant type A occurs in invariant position in type => scala.collection.mutable.ArrayBuffer[A] of value as
class Thingie[+A](implicit t: ClassTag[A]) extends Thing[A] { val as = mutable.ArrayBuffer.fill[A](10)(t.runtimeClass.newInstance.asInstanceOf[A]) ; private val it = as.iterator ; def next() = it.next() }
but
scala> class Thingie[+A](implicit t: ClassTag[A]) extends Thing[A] { private[this] val as = mutable.ArrayBuffer.fill[A](10)(t.runtimeClass.newInstance.asInstanceOf[A]) ; private val it = as.iterator ; def next() = it.next() }
defined class Thingie
and
scala> class X
defined class X
scala> val xs = new Thingie[X]
xs: Thingie[X] = Thingie#49f5c307
scala> xs.next
res1: X = X#4816c290
You need #uncheckedVariance:
import scala.annotation.unchecked.uncheckedVariance
class A[T] {}
class B[+T] {
val a: A[T #uncheckedVariance] = null
}
Even the Scala standard library makes use of #uncheckedVariance, notably in allowing the invariant mutable collections to inherit from covariant traits.
If B is covariant in Thing[+B] then you will not be able to have B in a contravariant position in Thing, i.e.
def put(b:B) {...} // will fail to compile, can't use a covariant type in this position
But it is possible to make two interfaces for Thing, one where the type is used in covariant positions and one where it is used in contravarient positions, as in the following:
trait ThingProduce[+B] {
def get: B
}
trait ThingConsume[-B] {
def put(b: B)
}
class Thing[B] extends ThingConsume[B] with ThingProduce[B] {
private val queue = new scala.collection.mutable.Queue[B]
def put(b: B) {queue.enqueue(b)}
def get: B = queue.dequeue
def both(b: B): B = ???
}
So that with the class hierarchy:
class Animal
class Mammal extends Animal
class Dog extends Mammal
The following can be done:
val mammalThing: Thing[Mammal] = new Thing[Mammal]{}
val dogConsumer: ThingConsume[Dog] = mammalThing
val animalProducer: ThingProduce[Animal] = mammalThing
But not:
val dogConsumer: ThingConsume[Dog] = animalProducer
//or
val animalProducer: ThingProduce[Animal] = dogConsumer
Thus Thing[B] can be seen to be both covarient and contravariant, but only for certain members.
I'm trying to use a code similar to
abstract class A[T] extends Ordered[A[T]] {
val att:Int
def compare(that:A[T]) =
if (this.att >= that.att)
1
else
-1
}
class B extends A[Int] {
val att = 1
}
When I try this in Scala 2.11 REPL
scala> import scala.collection.immutable.SortedSet
scala> SortedSet[B]()
I get the following error
<console>:11: error: diverging implicit expansion for type Ordering[B]
starting with method ordered in trait LowPriorityOrderingImplicits
SortedSet[B]()
How can I solve this?
You need an instance of the Ordering type class to create a SortedList. The ordered method mentioned in the error message will automatically create an Ordering[X] for any type X that's an Ordered[X].
Your B is not an Ordered[B], however—it only extends Ordered[A[Int]]. Ordered is invariant in its type argument, so Ordered[B] and Ordered[A[Int]] have essentially nothing to do with each other.
You can address this issue with F-bounded polymorphism:
abstract class A[T, S <: A[T, S]] extends Ordered[S] {
val att: Int
def compare(that: S)=
if (this.att >= that.att)
1
else
-1
}
class B extends A[Int, B] {
val att = 1
}
Now B extends Ordered[B] and you can create the sorted set.
Alternatively, you could use your original code and just create a SortedSet[A[Int]]. It's a much better idea to avoid Ordered altogether, though, and just define the Ordering type class instance directly.