The following code fails when the constructor parameter is declared with val
Works:
class Poso(array : Array[_ <: Any])
object Test {
new Poso(classOf[Retention].getEnumConstants())
}
Doesn't work:
class Poso(val array : Array[_ <: Any])
object Test {
new Poso(classOf[Retention].getEnumConstants())
}
The compiler gives the error:
Error in Scala compiler: type mismatch; found :java.lang.Object required: array[java.lang.Object]
Without being able to give a line number.
Looks like a bug in Scala compiler (it dies on an exception). You should probably report it to Scala developers.
Using AnyRef instead of Any fixed it for me:
class Poso(val array : Array[_ <: AnyRef])
object Test {
new Poso(classOf[java.lang.annotation.Retention].getEnumConstants())
}
Related
I have this method:
private def doSomeStringProcessing[T](input: String, typeConverter: String => T): Array[T] = {
cleanTheString(input)
.split(",").map(typeConverter)
}
which gives the error:
error: type mismatch;
[INFO] found : scala.collection.mutable.ArraySeq[T]
[INFO] required: Array[T]
Per some googling, found posts saying to use the ClassManifest. Tried that and it was deprecated. So it pointed me to ClassTag. Googled that and found this resource which I'm trying to follow: https://docs.scala-lang.org/overviews/reflection/typetags-manifests.html#via-the-methods-typetag-classtag-or-weaktypetag
So I tried doing below:
private def doSomeStringProcessing[T: TypeTag](input: String, typeConverter: String => T): Array[T] = {
cleanTheString(input)
.split(",").map(typeConverter)
}
Which gives the exact same error. I want generics to make my code cleaner/easier to read, not convoluted, so I don't want to do any of the complicated solutions. What's the quickest way to fix this?
This does work with ClassTag (I got confused because IntelliJ imported and/or code-completed it wrong, so including the correct import below):
import scala.reflect.ClassTag
private def doSomeStringProcessing[T: ClassTag](input: String, typeConverter: String => T): Array[T] = {
cleanTheString(input)
.split(",").map(typeConverter)
}
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.
This seems like a simple thing but I can't understand it...
This compiles:
object CanFoo1 {
def foo(): Unit = {
println("Yup, I can foo alright")
}
}
object CanFoo2 {
def foo(): Unit = {
println("And I can foo with the best")
}
}
trait A {
type CanFoo = { def foo(): Unit }
def fooers: Seq[CanFoo]
}
class B extends A {
def fooers = Seq(
// CanFoo1, // <- won't compile when this is uncommented
CanFoo2
)
}
But uncommenting the // CanFoo1, line gives:
error: type mismatch;
found : Seq[Object]
required: Seq[B.this.CanFoo]
(which expands to) Seq[AnyRef{def foo(): Unit}]
def fooers = Seq(
^
one error found
So it seems like the compiler understands that a collection containing just one element Seq(CanFoo2) (or Seq(CanFoo1)) is of the correct type, but when both objects are in the collection it gives up? What am I doing wrong here?
So it seems like the compiler understands that a collection containing
just one element Seq(CanFoo2) (or Seq(CanFoo1)) is of the correct
type, but when both objects are in the collection it gives up? What am
I doing wrong here?
When you pass CanFoo1 or CanFoo2 to the Seq apply, the sequence is inferred to be of type CanFoo1.type or CanFoo2.type respectively, it is not inferred to be of type CanFoo.
When you pass in both elements to the Seq, the compiler tries to look for a common type to which it can validly infer to make the code compile, and the only type it can find is Object, but fooers is said to be of type Seq[CanFoo], so the compiler yells.
You can help the compiler a little by explicitly writing the type of the collection:
class B extends A {
def fooers = Seq[CanFoo](
CanFoo1,
CanFoo2
)
}
I'm using scala's 2.10 TypeTags extensively in my code and I observe some behavior related to type inference that I do not understand.
Example code:
import scala.reflect.runtime.universe._
object BugDemo extends App {
def printType[T <: AnyRef : TypeTag]() : T = {
println(typeOf[T]);
null.asInstanceOf[T];
}
case class Foo()
var foo1 = printType[Foo]()
var foo2 : Foo = printType[Foo]()
var foo3 : Foo = printType()
}
Now I expect it to print Foo 3 times, but in reality I get (scala 2.10.3):
BugDemo.Foo
BugDemo.Foo
Nothing
What's wrong with my code? Why doesn't scala want to pass a proper type tag for my T in foo3?
Here is nothing wrong.
With type parameter not specified scala compiler takes the most concrete type. In case of printType() it's Nothing (the bottom type in scala type hierarchy).
Since Nothing is subtype of Foo your code is valid:
var foo3 : Foo = printType[Nothing]()
Funny thing is that with var foo3 : Nothing = printType[Nothing]() or even with printType[Nothing]() you'll get a NullPointerException:
scala> var foo3 : Nothing = printType[Nothing]()
Nothing
java.lang.NullPointerException
scala> printType[Nothing]()
Nothing
java.lang.NullPointerException
You can't get an instance of Nothing, but your code (var foo3 : Foo = printType[Nothing]()) works due to the type erasure. It looks like a scala bug that can't be fixed.
Nothing is the type parameter inferred by scala when one isn't explicitly provided by the caller. I hate (HATE) this default behavior because is leads to all sorts of runtime bugs Nothing is an allowed parameter to everything.
Its much better to enforce that the type parameter should be fully specified at compile-time by requiring that its not Nothing:
sealed trait NotNothing[-T]
object NotNothing {
implicit object YoureSupposedToSupplyAType extends NotNothing[Nothing]
implicit object notNothing extends NotNothing[Any]
}
and then:
def printType[T : TypeTag : NotNothing]() : T = { ... }
I have used Java for several years, however I'm new to Scala and am still trying to figure out its type system. I'm using Scala 2.10.2, Slick 1.0.1, and ScalaMock 2.10-3.0-M4 in Eclipse Scala IDE 3.0.1
I'm trying to mock out Slick in updateNameById using ScalaMock.
def updateNameById(id: Int, input: String, users: RichTable[Object]) = {
users.where(_.id === id).map{ e => e.test }.update(input)
}
abstract class RichTable[T](name: String = "blank")
extends slick.driver.MySQLDriver.simple.Table[T](name) {
def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
def test = column[String]("test")
}
(I'm actually passing in users: RichTable[User] where User has a complex inheritance hierarchy, but I've temporarily removed the uses of User to simplify the example)
users.where returns a scala.slick.lifted.Query, so I try to mock this out as follows
class ModelTest extends FlatSpec with MockFactory {
def test = {
val mockUsers = mock[RichTable[Object]]
// mockQuery definition
val mockQuery = mock[scala.slick.lifted.Query[RichTable[Object],
scala.slick.lifted.NothingContainer#TableNothing]]
(mockUsers.where _).expects(*).returns(mockQuery)
Main.updateNameById(1, "asdf", mockUsers)
}
}
The mockQuery definition gives me these cryptic type errors
type mismatch;
found : scala.slick.lifted.Query[O(in method union),
scala.slick.lifted.NothingContainer#TableNothing]
required: scala.slick.lifted.Query[(some other)O(in method union),
scala.slick.lifted.NothingContainer#TableNothing]
type mismatch;
found : scala.slick.lifted.Query[O(in method unionAll),
scala.slick.lifted.NothingContainer#TableNothing]
required: scala.slick.lifted.Query[(some other)O(in method unionAll),
scala.slick.lifted.NothingContainer#TableNothing]
I have no idea what "O(in method union[all])" vs. "(some other)O(in method union[All])" means, and Google hasn't been any help (it doesn't help matters that "some other" is an extremely generic phrase - googling "scala some other type error" produces pretty much the same results as "scala type error"). Does anybody know what this means and/or how to fix the type error?