The following is a simplified version of my original code to make things simpler (sorry it's still a bit complicated):
trait BuilderBase
trait MessageBase {
type Builder <: BuilderBase
}
class SomeMessage extends MessageBase {
type Builder = SomeMessage.Builder
}
object SomeMessage {
class Builder extends BuilderBase
}
class Covariant[+T]
class NonCovariant[T]
def func[T <: MessageBase](value: Covariant[T]): Covariant[T#Builder] = null
val message: Covariant[SomeMessage] = null
val result: Covariant[SomeMessage.Builder] = func(message)
And the last line fails to compile with an error at func(→ message ← here):
type mismatch; found : Covariant[SomeMessage] required: Covariant[SomeMessage.type]
Definitely func takes parameter of Covariant of T that is subclass of MessageBase, what's required there is Covariant[SomeMessage] not Covariant[SomeMessage.type], because SomeMessage.type (type of the companion object SomeMessage) does not conform to MessageBase.
Strangely, the error goes away without the type annotation, say, val result = func(message), and the type of result is exactly the same as what's meant: Covariant[SomeMessage.Builder]. So it just fails with the correct type annotation. Is this a bug?
One more clue is that this doesn't happen with all Covariant replaced with NonConvariant. So it might somehow be related to covariance. Any suggestion or help will be appreciated.
I know that some little tweaks can be a walkaround for this specific problem here e.g. simply omitting the type annotation might be one of them. But it would be really helpful if I can get more clues on what's really going on in compiler for example by giving some command line options to it.
I don't know the reason why also, but to give a slight alternative to #AssafMendelson 's answer, the following works too:
trait BuilderBase
trait MessageBase {
type Builder <: BuilderBase
}
class SomeMessage extends MessageBase {
type Builder = BuilderBase {}
}
class Covariant[+T]
class NonCovariant[T]
def func[T <: MessageBase](value: Covariant[T]): Covariant[T#Builder] = null
val message: Covariant[SomeMessage] = null
val result: Covariant[SomeMessage#Builder] = func(message)
So basically instead of the class definition in the companion object, simply define it in the class
I believe the issue is that the compiler gets confused by the type parameter Builder and the class Builder
Basically SomeMessage.Builder can reference both the type inherited and the object, however, it first tries the instance and only then the object.
I tried a simple change: I changed the class builder to builder2 (and the relevant references to it) and it seems to work.
Related
Here is a strange situation:
If I comment out the call to feed_usingExplicitTypeClassInstance below, then I get a compiler error.
Very puzzling. Any explanation ?
I mean, I comment out a function call (which returns no value) and then the code does not compile anymore ?
Should this be even possible at all in theory ? In any programming language ?
I mean I comment out something like println("hello") and then the code does not compile anymore ?
Of course it would be understandable if I would comment out a declaration or something, but a call to a function that does not return anything ?
object AnimalFeeder extends App {
def feed_usingExplicitTypeClassInstance[AnimalInstance]
(animalTypeClass: AnimalTypeClass[AnimalInstance])
(food: animalTypeClass.FoodThatAnimalLikes) =
{
animalTypeClass.feed(food)
}
def feed_usingImplicitTypeClassInstance[AnimalInstance, Food]
(food: Food)
(implicit animalTypeClass: AnimalTypeClass.Aux[Food,AnimalInstance]) =
{
animalTypeClass.feed(food)
}
// If I comment out this line, THEN !, I get an error !!!! How ???
feed_usingExplicitTypeClassInstance(AnimalTypeClass.CatInstance)(new CatFood())
feed_usingImplicitTypeClassInstance(new CatFood)
}
trait Food {
def eat(): Unit
}
trait AnimalTypeClass[AnimalInstance] {
type FoodThatAnimalLikes <: Food
def feed(f: FoodThatAnimalLikes) = f.eat()
}
object AnimalTypeClass {
type Aux[Food, Animal] = AnimalTypeClass[Animal] {
type FoodThatAnimalLikes = Food
}
implicit object CatInstance extends AnimalTypeClass[Cat] {
override type FoodThatAnimalLikes = CatFood
}
}
trait Cat
class CatFood extends Food {
override def eat(): Unit = println("meow")
}
This is the error:
Error:(23, 38) could not find implicit value for parameter animalTypeClass: AnimalTypeClass.Aux[CatFood,AnimalInstance]
feed_usingImplicitTypeClassInstance(new CatFood)
Error:(23, 38) not enough arguments for method feed_usingImplicitTypeClassInstance: (implicit animalTypeClass: AnimalTypeClass.Aux[CatFood,AnimalInstance])Unit.
Unspecified value parameter animalTypeClass.
feed_usingImplicitTypeClassInstance(new CatFood)
EDIT:
If I insert the line:
AnimalTypeClass.CatInstance
before:
feed_usingImplicitTypeClassInstance(new CatFood)
then the code compiles again, even if the line
feed_usingExplicitTypeClassInstance(AnimalTypeClass.CatInstance)(new CatFood())
is commented out.
This is a pretty well known issue, where implicits which appear after their usage in the same file and without an explicit type annotation are not found. For that reason it is strongly advised (and this will eventually be enforced) to give all non-local implicits an explicit type annotation. Unfortunately implicit objects are a bit tricky here, because they always act like implicit definitions without type annotation, and it is impossible to give them an explicit type... However last I checked this seemed to be fixed in Dotty for implicit objects.
See also, among others https://github.com/scala/bug/issues/8697
The reason that it does work when you uncomment a call to AnimalTypeClass.CatInstance in your code is that that reference will force the implicit object to be type checked earlier, so its type will be known before its implicit usage.
You have the definition of the implicit value in the same file after the usage of this value. It is not initialized when the compiler looks for an implicit value when you call feed_usingImplicitTypeClassInstance. Calling feed_usingExplicitTypeClassInstance with an explicit reference to this implicit value forces the implicit to initialize, and the compiler can use it in the implicit call.
Possible solutions:
Move the definition of the implicit value to another file.
If the implicit value is in the same file, move its definition above the place where you use it implicitly.
I'm trying to mock a method that returns an instance of a value class (extends AnyVal)
I'm getting some weird error message, which I understand (because of value class erasure) but I'm surprised Mockito doesn't cope with that.
My class:
case class MyValueClass(value: String) extends AnyVal
The function I want to mock:
trait ToMock {
def something(someParams: String): MyValueClass
}
And the mock:
val theMock = mock[ToMock]
val returned = MyValueClass("test")
when(theMock.something("test")).thenReturn(returned)
This code generates the following error:
MyValueClass cannot be returned by something()
something() should return String
But of course, if I make it return a String, it doesn't compile anymore...
If I remove extends AnyVal, of course it works fine.
OK, I found an answer that works.
I need to use the older mockito style of doReturn
doReturn(returned.value).when(theMock).something("test")
Because it's not type-safe, it works.
Not fully satisfactory though, as I give up type safety.
Why wouldn't the scala compiler dig this:
class Clazz
class Foo[C <: Clazz] {
val foo = new C
}
class type required but C found
[error] val a = new C
[error] ^
Related question - How to get rid of : class type required but T found
This is a classic generic problem that also happens in Java - you cannot create an instance of a generic type variable. What you can do in Scala to fix this, however, is to introduce a type evidence to your type parameter that captures the runtime type:
class Foo[C <: Clazz](implicit ct: ClassTag[C]) {
val foo = ct.runtimeClass.newInstance
}
Note that this only works if the class has a constructor without any arguments. Since the parameter is implicit, you don't need to pass it when calling the Foo constructor:
Foo[Clazz]()
I came up with this scheme, couldn't simplify it through a companion object thought.
class Clazz
class ClazzFactory {
def apply = new Clazz
}
class Foo(factory: ClazzFactory) {
val foo: Clazz = factory.apply
}
It's very annoying that ClazzFactory can't be an object rather than a class though. A simplified version:
class Clazz {
def apply() = new Clazz
}
class Foo(factory: Clazz) {
val foo: Clazz = factory.apply
}
This requires the caller to use the new keyword in order to provide the factory argument, which is already a minor enough annoyance relative to the initial problem. But, scala could have made this scenario all more elegant; I had to fallback here to passing a parameter of the type I wish to instantiate, plus the new keyword. Maybe there's a better way.
(motivation was to instantiate that type many times within the real Foo, that's why this is at all a solution; otherwise my pattern above is just redundantly meaningless).
I'm a newbie to Scala and I'm facing an issue I can't understand and solve. I have written a generic trait which is this one:
trait DistanceMeasure[P<:DbScanPoint] {
def distance(p1:P, p2:P):Double
}
where DbScanPoint is simply:
trait DbScanPoint extends Serializable {}
Then I have the following two classes extending them:
class Point2d (id:Int, x:Double, y:Double) extends DbScanPoint {
def getId() = id
def getX() = x
def getY() = y
}
class EuclideanDistance extends DistanceMeasure[Point2d] with Serializable {
override def distance(p1:Point2d,p2:Point2d) = {
(p1.getX()-p2.getX())*(p1.getX()-p2.getX()) + (p1.getY()-p2.getY()) * (p1.getY()-p2.getY())
}
}
And at the end I have this class:
class DBScanSettings {
var distanceMeasure:DistanceMeasure[_<:DbScanPoint] = new EuclideanDistance
//...
}
My problem is that if that when I write in my test main this:
val dbScanSettings = new DBScanSettings()
dbScanSettings.distanceMeasure.distance(new Point2d(1,1,1), new Point2d(2,2,2))
I get the following compiling error:
type mismatch;
[error] found : it.polito.dbdmg.ontic.point.Point2d
[error] required: _$1 where type _$1 <: it.polito.dbdmg.ontic.point.DbScanPoint
I can't understand which is the problem. I have done a very similar thing with other classes and I got no error, so the reason of this error is quite obscure to me.
May somebody help me?
Thanks.
UPDATE
I managed to do what I needed by changing the code to:
trait DistanceMeasure {
def distance(p1:DbScanPoint, p2:DbScanPoint):Double
}
And obviously making all the related changes.
The heart of your problem is that you are defining your distanceMeasure var with an existential type, so to the compiler that type is not completely known. Then, you are calling distance which is to take two instances of type P <: DbScanPoint passing in two Point2d instances. Now, these are the correct types for the concrete class behind distanceMeasure (a new EuclideanDistance), but the way you defined distanceMeasure (with an existential), the compiler cannot enforce that Point2d instances are the right type that the concrete underlying DistanceMeasure takes.
Say for arguments sake that instead of a new EuclideanDistance, you instead instantiated a completely different impl of DistanceMeasure that did not take Point2d instances and then tried to call distance he way you have it here. If the compiler can't enforce that the underlying class accepts the arguments supplied, it's going to complain like this.
There are a bunch of ways to fix this, and the solution ultimately depends on the flexibility you need in your class structure. One possible way is like so:
trait DBScanSettings[P <: DbScanPoint] {
val distanceMeasure:DistanceMeasure[P]
//...
}
class Point2dScanSettings extends DBScanSettings[Point2d]{
val distanceMeasure = new EuclideanDistance
}
And then to test:
val dbScanSettings = new Point2dScanSettings()
dbScanSettings.distanceMeasure.distance(new Point2d(1,1,1), new Point2d(2,2,2))
But without me really understanding you requirements for what levels of abstraction you need, it's going to be up to you to define the restructure.
I am trying to create a trait that implements a tree with bidrectional links such that when a node adds a parent, that node is added to the parent's children. The error I get below is:
type mismatch; found :PolyTree.this.type (with underlying type PolyTree[T]) required: T
Any idea why this code is getting an error and what is needed in order to make this code work:
trait PolyTree[T <: PolyTree[T]] {
private val _parents: ListBuffer[T] = ListBuffer()
private val _children: ListBuffer[T] = ListBuffer()
def addParent(parent: T): PolyTree[T] = {
if (parent == this)
throw new IllegalArgumentException();
_parents += parent
parent._children += this // Error
this
}
}
The error occurs because the type of 'parent._children' is 'T', while the type of 'this' is 'PolyTree[T]', which are different types in Scala.
You can fix the error by inserting the the following self-type annotation at the top of the trait:
self: T =>
This is necessary because without it, the following would be valid code:
class TreeOne extends PolyTree[TreeOne]
class TreeTwo extends PolyTree[TreeOne]
TreeTwo is allowed to use TreeOne as the type parameter, because TreeOne satisfies the condition that T <: PolyTree[T]. However, once you add the self-type annotation, Scala essentially tries to cast self/'this' in TreeTwo to 'T' (TreeOne) at compile-time, finds that this isn't type-safe, and rejects the declaration of TreeTwo with the error:
error: illegal inheritance
self-type TreeB does not conform to PolyTree[TreeA]'s selftype TreeA'
I'm not the best at understanding or explaining this stuff, but you can garner a bit more knowledge from Chapter 12. The Scala Type System in O'Reilly's 'Programming Scala'.