On Tuesday, June 11, 2013 12:33:32 AM UTC+2, Paul Phillips wrote:
On Mon, Jun 10, 2013 at 6:21 PM, Paolo G. Giarrusso
<p.gia...@gmail.com> wrote:
res11: String = something primitive: look at >>>>>class java.lang.Integer<<<<<<
Well, that's why I didn't call getClass.
Yeah, calling it was a bad way of making my point.
The information being sought is encoded in which method was called. If the T <: AnyVal method is called, then it was primitive. The actual thing you're holding will of course be boxed, but that's okay, because you know what the unboxed form of anything boxed is, and you know the static type is unboxed.
Ah, so you propose to figure out whether something is AnyVal and then just unbox it, even though at the call site it maybe was already unboxed? OK, that would work, but that's not how I hoped to do it.
If you really didn't believe it, I can flesh out that method until you get the thingy you want. The key is that discriminating via variant implicit conversions collects the information at the call site.
I suspect I was mislead by your `(5: Integer).whatAmI` example, and by some details. I'm also not sure whether I guesstimated the ABI correctly.
If the T <: AnyVal method is called, maybe the call-site type was AnyVal and at the caller-site was still boxed. Right?
I think I'm after something more like the following (shown only for Int):
implicit def imp1[T](x: T) = new { def whatAmI = "something boxed" }
implicit def impInt(x: Int) = new { def whatAmI = "something primitive" }
// Other N variants of impInt for all base types
// It would maybe be cool if I could instead write:
// implicit def imp2[@specialized T](x: T) = new { def whatAmI = "something primitive" }
// and get what I want, but of course specialization tries to not alter the semantics, exactly the opposite of what I'd want here. So I guess I'd need some advanced macros for that.
// Three example call-sites, to call on argument 5.
def f1[T](t: T) = t.whatAmI //t is boxed here
def f2[T <: AnyVal](t: T) = t.whatAmI // also boxed
def f3(t: Int) = t.whatAmI //here it's primitive
The output matches the comments, but I am not yet sure whether erasure actually works like that. That's just my guess.
Now, what I was going after is something horribly complicated like:
def unboxClassTag(x: ClassTag[_]): ClassTag[_] = //omitted
def boxClassTag(x: ClassTag[_]): ClassTag[_] = //omitted
implicit def imp1[T](x: T): Matcher[T] = new Matcher[T] {
def matchMe[U](ct: ClassTag[U]) = {
println("imp1")
(boxClassTag(ct) unapply x: Option[_]).asInstanceOf[Option[T]]
}
}
implicit def impInt(x: Int): Matcher[Int] = new Matcher[Int] {
def matchMe[U](ct: ClassTag[U]) = {
println("impInt")
(unboxClassTag(ct) unapply x: Option[_]).asInstanceOf[Option[Int]]
}
}
//All matches succeed
println(1 matchMe classTag[Int])
println(1 matchMe classTag[Integer])
def foo[T](x: T) = {
println(x matchMe classTag[Int])
println(x matchMe classTag[Integer])
}
foo(1)
Now the idea is that matchMe could be a macro method, so that you decide statically how to convert the macro tag. If the matching is done in a loop and this conversion is lifted outside the loop, that's might be actually faster, isn't it?
But for the non-loop case, I fear I'm optimizing the wrong direction — isn't it faster to simply unbox or box the value, rather than comparing class tags? Well, I don't know, but when the class tag is either unboxed or boxed and you don't know, you need to normalize the class tag, so it doesn't get much better. Or you just call `ct.unapply(box(t)) orElse ct.unapply(unbox(t))` (or the result of aggressive inlining in that fragment) and maybe that's even faster.