Skip to content

Instantly share code, notes, and snippets.

@tixxit
Last active August 29, 2015 14:13
Show Gist options
  • Save tixxit/2bba6c7d27a3eed0f779 to your computer and use it in GitHub Desktop.
Save tixxit/2bba6c7d27a3eed0f779 to your computer and use it in GitHub Desktop.
object MiniboxingReflection {
...
def mbCast[A]: MbCast[A, _]
}
sealed trait MbCast[A, @mb B] {
def from(a: A): B
def to(b: B): A
def fromTC[F[_]](fa: F[A]): F[B]
def toTC[F[_]](fb: F[B]): F[A]
}
class IntMbCast[T] extends MbCast[T, Int]
class LongMbCast[T] extends MbCast[T, Long]
class FloatMbCast[T] extends MbCast[T, Float]
class DoubleMbCast[T] extends MbCast[T, Double]
...
sealed trait Point2[@mb A] {
def x: A
def y: A
...
}
case class IntPoint2(x: Int, y: Int) extends Point2[Int]
case class DoublePoint2(x: Double, y: Double) extends Point2[Double]
case class GenPoint2[A](x: A, y: A) extends Point2[A]
object Point2 {
def apply[@mb A](x: A, y: A): Point2[A] = MiniboxingReflection.mbCast[A] match {
case (cast: IntMbCast) => cast.toTC(IntPoint2(cast.from(x), cast.from(y)))
case (cast: DoubleMbCast) => cast.toTC(DoublePoint2(cast.from(x), cast.from(y)))
case _ => GenPoint2(x, y)
}
}
@VladUreche
Copy link

@tixxit, with the proposed reflection, you would have to do:

object Point2 {
  def apply[@mb A](x: A, y: A): Point2[A] = (reifiedType[A] match {
    case SimpleType.Int => IntPoint2(x.asInstanceOf[Int], y.asInstanceOf[Int])
    case SimpleType.Double => DoublePoint2(x.asInstanceOf[Double], y.asInstanceOf[Double])
    case _ => GenPoint2(x, y)
  }).asInstanceOf[Point2[A]]
} 

I would argue the last .asInstanceOf[Point2[A]] is not that ugly. The really ugly part is casting the components. So what if the SimpleTypes would have a ConvertType counterpart:

object Point2 {
  def apply[@mb A](x: A, y: A): Point2[A] = (reifiedType[A] match {
    case ConvertType.Int(conv) => IntPoint2(conv(x), conv(y))
    case ConvertType.Double(conv) => DoublePoint2(conv(x), conv(y))
    case _ => GenPoint2(x, y)
  }).asInstanceOf[Point2[A]]
} 

That could be implemented in a pretty simple way, with a separate extractor. WDYT about this?

@VladUreche
Copy link

In general, I'd be afraid to have the higher-order convertors:

def fromTC[F[_]](fa: F[A]): F[B]
def toTC[F[_]](fb: F[B]): F[A] 

Since they only scale to one type parameter, not more :(

@tixxit
Copy link
Author

tixxit commented Jan 21, 2015

@VladUreche yeah, the casts are what I would've done otherwise, and aren't too bad (which is why I love what you have already). I fear the 2nd example would require some allocations and I was mostly hoping to get rid of the casts without any extra allocations (just *Point2)! But just being able to pattern match on the specialized type without a ClassTag solves this problem, so I'm happy anyway :)

@tixxit
Copy link
Author

tixxit commented Jan 21, 2015

The more I think about it, the more I'm happy with just reifiedType[A]. Being able to pattern match on the type solves all my problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment