scala-newtype
scala-newtype copied to clipboard
Support Array casting
@alexknvl pointed out that it's possible to encode newtypes in such a way that casting Arrays with asInstanceOf will work (which means Coercible can work too).
Here's a simple adaptation from his solution to demonstrate a failing test case.
object Example {
class Foo[A](val a: Array[A])
val foo = new Foo(Array(1, 2, 3))
def subst[F[_], T](fa: F[Int]): F[T] = fa.asInstanceOf[F[T]]
type Good = Good.Type
object Good {
type Base <: Any
trait Tag extends Any
type Type <: Base with Tag
}
def good() = println(subst[Foo, Good](foo).a.head)
@newtype case class Bad(value: Int)
def bad() = println(subst[Foo, Bad](foo).a.head)
def main(args: Array[String]): Unit = {
good()
bad()
}
}
/cc @joroKr21
The encoding of the newtype macros in v0.4.0 now allow for asInstanceOf casting by having the Base and Tag types extend Any, but of course this must be done with caution. Any time you use asInstanceOf you lose type safety, so it's important that you understand what you're doing.
scala> Array(1,2,3).asInstanceOf[Array[Foo]]
res0: Array[Foo] = Array(1, 2, 3)
scala> res0.getClass
res1: Class[_ <: Array[Foo]] = class [I
scala> res0.head
res2: Foo = 1
I have also started work on the 10-as-array branch which introduces the AsArray type class.
scala> import io.estatico.newtype.macros._, io.estatico.newtype.arrays._
scala> @newtype case class Foo(x: Int)
scala> AsArray(Foo(1), Foo(2))
res0: Array[Foo] = Array(1, 2)
scala> res0.getClass
res1: Class[_ <: Array[Foo]] = class [I
scala> res0.head
res2: Foo = 1
scala> AsArray.empty[Foo]
res3: Array[Foo] = Array()
scala> res3.getClass
res4: Class[_ <: Array[Foo]] = class [I
scala> AsArray.downcast(res0)
res8: Array[Int] = Array(1, 2)
scala> res8.head
res9: Int = 1
scala> Array(1,2,3)
res10: Array[Int] = Array(1, 2, 3)
scala> AsArray.upcast(res10): Array[Foo]
res12: Array[Foo] = Array(1, 2, 3)
scala> AsArray.upcast[Foo](res10)
res13: Array[Foo] = Array(1, 2, 3)
I think we might be able to now support .coerce for Arrays. Should probably do extensive testing to ensure the current encoding won't blow up on us. If that's the case, then we should be able to omit the upcast and downcast methods on AsArray, leaving only the need for empty and apply.