-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OptManifest not resolved #9482
Comments
We're not planning to implement support for Manifest in Dotty, because they're all but deprecated and known to have issues (I wanted to remove them from 2.13 but it didn't go through), if you want to make arrays, use a ClassTag instead, if you need something more advanced, you'll probably need macros: http://dotty.epfl.ch/docs/reference/metaprogramming/macros.html |
Ok, but can I get an |
I think that's doable without compiler support: import scala.reflect.ClassTag
case class OptClassTag[T](tag: Option[ClassTag[T]])
object OptClassTag extends OptClassTagLowPriorityImplicits {
implicit def optClassTagFound[T](implicit tag: ClassTag[T]): OptClassTag[T] = OptClassTag(Some(tag))
}
trait OptClassTagLowPriorityImplicits {
implicit def optClassTagNotFound[T]: OptClassTag[T] = OptClassTag(None)
}
object Test {
type A
implicitly[OptClassTag[A]]
implicitly[OptClassTag[String]]
} |
I see, but this is more expensive - two times wrapping instead of zero. What I don't understand is why we cannot have the same implicit |
I mean, unless IntelliJ is fooling me, I still have the 2.13.2 class library on the path when using Dotty (0.24.0-RC1)? So the only thing missing is the implicit resolution. ? |
You can reduce it to one wrapper easily by defining OptClassTagSome/OptClassTagNone or something. You should be able to reduce it done to zero wrappers using a trick similar to https://github.com/sjrd/scala-unboxed-option, but that's probably not worth it.
We could yes, but Manifest is effectively deprecated and we'd rather have people stop using it since it can be misleading (I would even prefer if people refrained from using ClassTag at all since it's so easy to misuse: zio/zio#3136)
Dotty reuses the Scala 2.13 standard library to stay binary compatibility so we can't do anything like that. |
To ease migration, I think we'd accept a PR to support Manifests in implicit search under the Scala 2 compatibiltiy mode ( |
then what is the problem with supporting I think it's a bit contradictory to say one the one hand the library is the 2.13 library, and on the other hand to say we want to deprecate things and remove implicit resolution even though those classes are still around and functional. Then I think the normal Scala path is to put |
Yeah, it's a bit awkward. I tried removing Manifest from 2.13 but that was rejected since there's some usecases which can only be replaced by TypeTag, which is Scala 2 specific and requires scala-reflect: scala/scala#6745. |
So I think the best path might be to reenable the implicit resolution in 3.0.x to stay compatible with 2.13.x, add |
Does your fallback involve casting the AnyRef array to an array of your input type? We shouldn't encourage people to do that becaue that can lead to ClassCastException: object Foo {
opaque type A = Int
def get: A = 1
def put(x: Array[A]): Unit = {}
}
object Test {
def singletonArray[T](x: T): Array[T] =
Array[AnyRef](x.asInstanceOf[AnyRef]).asInstanceOf[Array[T]]
def main(args: Array[String]): Unit = {
val arr = singletonArray(Foo.get)
Foo.put(arr) // java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [I
}
} (opaque types are an easy way to demonstrate the problem, I don't know if it can also manifest itself using only Scala 2 features). Anyway, I'll reopen this issue but I still recommend leaving anything related to Manifest under the Scala 2 compatibility mode. |
No; it simply specialises for all primitives and def make[A]()(implicit om: OptManifest[A]): Ref[A] = (om match {
case m: ClassTag[_] => m.newArray(0).asInstanceOf[AnyRef] match {
// these can be reordered, so long as Unit comes before AnyRef
case _: Array[Boolean] => apply(false)
case _: Array[Byte] => apply(0 : Byte)
case _: Array[Short] => apply(0 : Short)
case _: Array[Char] => apply(0 : Char)
case _: Array[Int] => apply(0 : Int)
case _: Array[Float] => apply(0 : Float)
case _: Array[Long] => apply(0 : Long)
case _: Array[Double] => apply(0 : Double)
case _: Array[Unit] => apply(())
case _: Array[AnyRef] => factory.newRef(null.asInstanceOf[A])(m.asInstanceOf[ClassTag[A]])
}
case _ => factory.newRef(null.asInstanceOf[Any])(implicitly[ClassTag[Any]])
}).asInstanceOf[Ref[A]] (this is from Nathan Bronson's original code). The |
We could also just drop this optimisation in Scala-STM, as |
I see a bunch of casts in this code snippet so I'd say there's a good chance it is in fact unsound, but it's hard to say without the full code. |
Scala-STM is highly optimised; it has an extensive test suite, and I can vouch that we don't run into any class cast exceptions anywhere. |
The ClassTag casting looked very suspicious to me, it appears to be OK in practice because the ClassTag is only passed to |
By the way, it should be possible to implement inline def make[A](): Ref[A] = inline erasedValue[A] match {
case _: Boolean => apply(false)
case _: Byte => apply(0 : Byte)
// ...
case _ => apply(null.asInstanceOf[A])
} See http://dotty.epfl.ch/docs/reference/metaprogramming/inline.html |
Opaque types are nothing special and can be encoded in Scala 2, so yes: trait Foo {
type A
def get: A
def put(x: Array[A]): Unit
}
object Foo extends Foo {
type A = Int
def get = 1
def put(x: Array[Int]): Unit = {}
}
object Test {
def singletonArray[T](x: T): Array[T] =
Array[AnyRef](x.asInstanceOf[AnyRef]).asInstanceOf[Array[T]]
def main(args: Array[String]): Unit = {
val arr = singletonArray(Foo.get)
Foo.put(arr) // java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [I
println("k")
}
} |
scala/scala3#9482 prepare Scala 3
Fix #9482: simplified Manifest synthesis
I'm currently adding Dotty support to ScalaSTM. Everything went smooth except that
OptManifest
implicit compiler resolution seems broken (works through Scala 2.11–13).Minimized code
We use the following API
which is needed to distinguish between primitive types and reference types, and create arrays.
This works in the cases where the type is concrete, such as
Ref.make[String]
orRef.make[Int]
, but also when it is abstract such asOutput
This no longer works in Dotty
Expectation
It should work, like it did in Scala 2.13, i.e. resolve to either
ClassManifest
orNoManifest
. E.g.:https://travis-ci.org/github/scala-stm/scala-stm/jobs/714280130
The text was updated successfully, but these errors were encountered: