This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Type specialization

2 replies
alex14n
Joined: 2009-03-16,
User offline. Last seen 2 years 19 weeks ago.

Hello,

Maybe it was too early to fire bugs and I should discuss this on the mailing
list first.
https://lampsvn.epfl.ch/trac/scala/ticket/2678
https://lampsvn.epfl.ch/trac/scala/ticket/2679

What I was trying to do is implement specialized array search,
I have array with objects and array with their integer hashcodes.
When I look for an object I want first check its referential equality,
if it equals - OK, if not - first compare hashcode and only
if it equals - call Object.equals method to compare them.

There is eq operator but as far as I can understand it works only on
AnyRef/Object types.
One proposal it to make it work on any scala type just as == works in java.

Now I can write something like this:

class Test[@specialized A] (implicit val m: Manifest[A]) {
def test (x: A, y: A) = if (x.isInstanceOf[AnyRef]) x.asInstanceOf[AnyRef]
eq y.asInstanceOf[AnyRef] else x == y
}

But when I decompile resulting code specialized for Int I see:

public boolean test$mcI$sp(int x, int y)
{
return (BoxesRunTime.boxToInteger(x) instanceof Object) ?
BoxesRunTime.boxToInteger(x) == BoxesRunTime.boxToInteger(y) :
BoxesRunTime.equals(BoxesRunTime.boxToInteger(x),
BoxesRunTime.boxToInteger(y));
}

This code is just incorrect since Int is not an instance of AnyRef,
but BoxesRunTime.boxToInteger(x) - is!

Is it possible to make some king of conditional compilation for specialized
types?
Not like #ifdef, but at least so that compiler could check types and remove
some code,
so there would be no ".isInstanceOf[AnyRef]" check for Int specialization
since
compiler already know its type. It would be excellent if this will work in
match/case too, like:

class Test[@specialized A] (implicit val m: Manifest[A]) {
def test (x: A, y: A) = x match {
case r: AnyRef => r eq y.asInstanceOf[AnyRef]
case i: Int => i == y
case _ => x == y
}
}

So that when specialized to Int only "i == y" check will be done since we
know the types.
Currently this code produces just something ugly. Even simple == when
specialized
generates too much boxing and boxed checks that there's almose no point in
specialization at all.

class Test[@specialized A] (implicit val m: Manifest[A]) {
def test (x: A, y: A) = x == y
}

When specialzied to Int produces the following decompiled code:

public boolean test$mcI$sp(int x, int y)
{
return BoxesRunTime.equals(BoxesRunTime.boxToInteger(x),
BoxesRunTime.boxToInteger(y));
}

just to compare two ints! This is very inefficient.

Also it would be nice to simplify specialized arrays creation. Now it
requires manifests,
so calling new Array[A](n) always calls manifest.newArray(n) but in
specialized code
we know exact types and it is better just to have analog of "new int[n]"
java code.

Regards,
Alex

-----
Faster HashMap: http://github.com/alex14n/CompactHashMap

Iulian Dragos 2
Joined: 2009-02-10,
User offline. Last seen 42 years 45 weeks ago.
Re: Type specialization


On Mon, Nov 23, 2009 at 4:50 AM, Alex Yakovlev <alex14n@gmail.com> wrote:

Hello,
 
There is eq operator but as far as I can understand it works only on
AnyRef/Object types.

That is true, it is for reference equality.
 
One proposal it to make it work on any scala type just as == works in java.

Now I can write something like this:

class Test[@specialized A] (implicit val m: Manifest[A]) {
 def test (x: A, y: A) = if (x.isInstanceOf[AnyRef]) x.asInstanceOf[AnyRef]
eq y.asInstanceOf[AnyRef] else x == y
}

But when I decompile resulting code specialized for Int I see:

   public boolean test$mcI$sp(int x, int y)
   {
       return (BoxesRunTime.boxToInteger(x) instanceof Object) ?
BoxesRunTime.boxToInteger(x) == BoxesRunTime.boxToInteger(y) :
BoxesRunTime.equals(BoxesRunTime.boxToInteger(x),
BoxesRunTime.boxToInteger(y));
   }

This is an instance of this bug report

https://lampsvn.epfl.ch/trac/scala/ticket/1872

which says that instanceOf checks on primitive types will be disallowed. I'm not sure what that means for polymorphic types, which could be primitives.
 
Is it possible to make some king of conditional compilation for specialized
types?
Not like #ifdef, but at least so that compiler could check types and remove
some code,
so there would be no ".isInstanceOf[AnyRef]" check for Int specialization
since
compiler already know its type. It would be excellent if this will work in
match/case too, like:

class Test[@specialized A] (implicit val m: Manifest[A]) {
 def test (x: A, y: A) = x match {
   case r: AnyRef => r eq y.asInstanceOf[AnyRef]
   case i: Int => i == y
   case _ => x == y
 }
}

This makes sense, but I'm not yet sure how far this could go. The reason is that specialized code may return different results from non-specialized code. Unless the dynamic instance check on primitives can be fixed.
 

When specialzied to Int produces the following decompiled code:

   public boolean test$mcI$sp(int x, int y)
   {
       return BoxesRunTime.equals(BoxesRunTime.boxToInteger(x),
BoxesRunTime.boxToInteger(y));
   }

just to compare two ints! This is very inefficient.

This is  plainly a bug. I am not sure what happens, but it's not intended. At all.

Also it would be nice to simplify specialized arrays creation. Now it
requires manifests,
so calling new Array[A](n) always calls manifest.newArray(n) but in
specialized code
we know exact types and it is better just to have analog of "new int[n]"
java code.

Agreed. But since there's just one definition of a specialized class, how to handle the generic case? Maybe have user-defined specialized classes, or a 'specialized' version for Object, which is really the generic one.

cheers,
iulian
 

Regards,
Alex

-----
Faster HashMap: http://github.com/alex14n/CompactHashMap
--
View this message in context: http://old.nabble.com/Type-specialization-tp26472442p26472442.html
Sent from the Scala mailing list archive at Nabble.com.




--
« Je déteste la montagne, ça cache le paysage »
Alphonse Allais
alex14n
Joined: 2009-03-16,
User offline. Last seen 2 years 19 weeks ago.
Re: Type specialization

On Mon, Nov 23, 2009 at 2:10 PM, Iulian Dragos wrote:
> On Mon, Nov 23, 2009 at 4:50 AM, Alex Yakovlev wrote:

>> There is eq operator but as far as I can understand it works only on
>> AnyRef/Object types.
>
> That is true, it is for reference equality.

Is it possible to introduce a complete equivalent of java's == into Scala?
I mean, that will work on any types (including primitive ones), not just
AnyRef?

> This is an instance of this bug report
>
> https://lampsvn.epfl.ch/trac/scala/ticket/1872
>
> which says that instanceOf checks on primitive types will be disallowed.
> I'm
> not sure what that means for polymorphic types, which could be primitives.

What I'm afraid is that it will just cause errors, like for example:

class Test[@specialized A] (implicit val m: Manifest[A]) {
def test (x: A, y: A) = x match {
case i: Int => i == y
case r: AnyRef => r eq y.asInstanceOf[AnyRef]
case _ => x == y
}
}

does not compile with -Yspecialize at all, but compiles without this switch.
Is it a bug or what? Compiles says:

Test.scala:4: error: unreachable code
case r: AnyRef => r eq y.asInstanceOf[AnyRef]
^
one error found

I'm afraid it was caused by one of specialized branches,
for Int, where first "case" will always match thus making other
"cases" really unreachable. That's exactly the case where
I suppose conditional compilation is required, but that's just
a guess since I do not know the cause of this error.

I suppose we can detect such cases where we can just remove
some of the branches in if and match on specialized types.

>> Is it possible to make some king of conditional compilation for
>> specialized types? Not like #ifdef, but at least so that compiler
>> could check types and remove some code, so there would be no
>> ".isInstanceOf[AnyRef]" check for Int specialization since
>> compiler already know its type. It would be excellent if this
>> will work in match/case too, like:
>>
>> class Test[@specialized A] (implicit val m: Manifest[A]) {
>> def test (x: A, y: A) = x match {
>> case r: AnyRef => r eq y.asInstanceOf[AnyRef]
>> case i: Int => i == y
>> case _ => x == y
>> }
>> }
>
> This makes sense, but I'm not yet sure how far this could go. The reason
> is
> that specialized code may return different results from non-specialized
> code. Unless the dynamic instance check on primitives can be fixed.

Well, actually that's what I'd like to see - a possibility to intentionally
make possible to have different pieces of code for different specialized
types,
in this case user will take complete responsibility for all possible harm.

Maybe there's a sense to emit a warning, and some annotation to disable it
in case you do that on purpose.

>> Also it would be nice to simplify specialized arrays creation. Now it
>> requires manifests, so calling new Array[A](n) always calls
>> manifest.newArray(n) but in specialized code we know exact types
>> and it is better just to have analog of "new int[n]" java code.
>
> Agreed. But since there's just one definition of a specialized class, how
> to
> handle the generic case? Maybe have user-defined specialized classes, or a
> 'specialized' version for Object, which is really the generic one.

In generic case we have only 2 possibilities, either to use a manifest,
or allocate generic array of Objects and then store boxed values in it,
but since manifests were already introduces I think it should be used.
And in specialized code we can simply ignore it.

Regards,
Alex

-----
Faster HashMap: http://github.com/alex14n/CompactHashMap

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland