How do I eliminated the following compiler error:
type mismatch;
found : org.public_domain.Test
required: Object
Note that Test extends Any, not AnyRef.
Such types can participate in value classes, but instances
cannot appear in singleton types or in reference comparisons.
Test(value)
Occurring on the following code:
object Test extends (Double => Test) {
def apply(value: Double): Test =
new Test(value)
}
final case class Test private(value: Double) extends AnyVal {
//@annotation.unused
private def readResolve(): Object =
Test(value)
}
val t = Test(10d)
println(s"t=$t")
Here’s the code and error on Scastie:
Changing AnyVal
to AnyRef
fixes it, but I suppose that’s not what you want.
I want it to act as an AnyVal
explicitly.
Is there a way to make the compiler happy with an AnyVal
?
Or does the deserialization logic not route through this method in Scala for primitives; i.e. AnyVal
descendants?
Ultimately, I am trying to ensure an invalid “instance” cannot be “injected/created” during deserialization. Is there another and/or better way to accomplish that than moving it to the far less performant AnyRef
?
Maybe you could Test(value).asInstanceOf[AnyRef]
to force boxing?
1 Like
Huh – does that work? I usually think of asInstanceOf
as being a runtime no-op; hadn’t occurred to me that it could be used to force a box.
In general, the whole thing makes me nervous. The Double
is a primitive at the Java level, right? Given that, and Java not knowing much about Scala AnyVals, it seems likely that ObjectInputStream
(assuming that’s what this is for – I don’t know the Java side well) is going to get pretty confused…
1 Like
I’d propose package public
for this purpose, if the empty package does not suffice.
That could result in some justified pain in java interop for example code.
1 Like
I tried to provide the actual primitive, but got this message which makes even less sense.
the result type of an implicit conversion must be more specific than Object
Here’s the code:
I decided to try Seth’s idea combined with the primitive like this:
Test(value).value.asInstanceOf[java.lang.Object]
And this appeared to work:
Dotty’s message is
-- Error: unresolved.scala:8:40 ----------------------------------------------------------------------------------------
8 | private def readResolve(): Object = DT(value)
| ^^^^^^^^^
| the result of an implicit conversion must be more specific than Object
1 Like
Huh – does that work? I usually think of asInstanceOf as being a runtime no-op; hadn’t occurred to me that it could be used to force a box.
Anything that extends AnyVal
must also have a boxed representation for use in generic contexts.
asInstanceOf[AnyRef]
works on primitive types as well:
scala 2.13.8> 3.asInstanceOf[AnyRef]
val res5: AnyRef = 3
scala 2.13.8> res5.getClass
val res6: Class[_ <: AnyRef] = class java.lang.Integer
This behavior falls out of a combination of how asInstanceOf
is defined in SLS 12.1 and the compiler’s ability to box and unbox as needed in generic contexts.
It’s a bit of a tangent, but since you said that you thought of asInstanceOf
being a runtime no-op, I’ll mention that that often isn’t the case on the JVM. For example:
scala 2.13.8> class C; class D
class C
class D
scala 2.13.8> (new C).asInstanceOf[D]
java.lang.ClassCastException: class C cannot be cast to class D
The JVM’s safety guarantees mandate this behavior. You can lie to the compiler all day about what type something is, but the JVM will not allow you to lie at runtime about what a value’s erased type is. (I don’t know what Scala.js or Scala Native do, here.)
2 Likes