- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Best way to cast Int to Byte
Fri, 2009-03-06, 21:16
hi,
i wonder what is the best (performance / compile-time erasure)
way to do something that in java would be
byte[] buf = new byte[10]
buf[0] = (byte) 0x66
... is that
buf(0) = 0x66.asInstanceOf[ Byte ]
or
buf(0) = 0x66.toByte
? looking at https://lampsvn.epfl.ch/trac/scala/browser/scala/branches/scala-detach/s... - both versions appear. and both seem to be methods... my hope is one of them gets to be a compile time cast...
thanks -sciss-
Fri, 2009-03-06, 23:27
#2
Re: Best way to cast Int to Byte
On Fri, Mar 6, 2009 at 8:16 PM, Sc iss wrote:
> hi,
>
> i wonder what is the best (performance / compile-time erasure)
>
> way to do something that in java would be
>
> byte[] buf = new byte[10]
> buf[0] = (byte) 0x66
>
> ... is that
>
> buf(0) = 0x66.asInstanceOf[ Byte ]
>
> or
>
> buf(0) = 0x66.toByte
>
> ? looking at https://lampsvn.epfl.ch/trac/scala/browser/scala/branches/scala-detach/s... - both versions appear. and both seem to be methods... my hope is one of them gets to be a compile time cast...
You should always use the toByte form. It does the right thing with
regards to bytecode emitted (it's emitted as a single opcode, not a
method call). The fact that the asInstanceOf[Byte] stuff works is, I
think, a bug. It's certainly contrary to what the SLS says should
happen (and inconsistent with regards to its behaviour with upcasts).
I'm hoping it will go away at some point (though this should not be
taken as a formal statement that it will).
Sat, 2009-03-07, 01:07
#3
Re: Best way to cast Int to Byte
[Follow-up to scala-debate, since I'm digressing a bit and proposing
something]
On Fri, Mar 06, 2009 at 09:16:18PM +0100, Sc iss wrote:
> buf(0) = 0x66.asInstanceOf[ Byte ]
>
> or
>
> buf(0) = 0x66.toByte
Blair's example already showed that constant unfolding works properly
with both, but when the value to be converted isn't known statically,
one can compile the following methods:
def f(i: Int) = i.toByte
def g(i: Int) = i.asInstanceOf[Byte]
and see what comes out:
public byte g(int);
Code:
0: iload_1
1: i2b
2: ireturn
public byte f(int);
Code:
0: iload_1
1: i2b
2: ireturn
So both are compiled optimally.
> my hope is one of them gets to be a compile time cast...
If by that you mean "a no-op at JVM level", then that can't happen,
because integer types must be converted with explicit instructions in
order for the code to be validated. Of course the JVM itself may
implement the i2b instruction as a no-op in some circumstances.
I recommend that you use the .toByte method, because asInstanceOf is
too overloaded. It is used for three distinct purposes:
* for standard conversions between built-in numeric types, as in this case
* for dynamically checked downcasts
* for unchecked casts that convert type arguments
The first can be accomplished also with the .toByte/toInt/etc methods,
while the latter two can also be done with pattern matching (using a
typed pattern, possibly with type arguments that are incompatible with
the type of the selector).
It's rather confusing that a single language form does so many so
different things, and in fact a very similar situation in C was a
motivation for having multiple different cast forms for different
purposes in C++. I think Scala should do the same:
* Use only .toByte/.toInt/etc for numeric conversions
* Use only pattern matching with typed patterns to do downcasts, and
_don't allow patterns to be incompatible with the type of the
selector_! (I.e. make "unchecked warnings" be errors in pattern matching)
* Allow .asInstanceOf casts from one type to another only when both
have the same erasure
After this the situation is much more clear: pattern matching is
always safe (and almost always incurs a run-time check), whereas
.asInstanceOf is always a no-op at run-time, but can break type
safety.
Even if it's too late to change the language in order to _enforce_
this policy, I think it would at least be a good idea to _follow_ it
nevertheless.
Lauri
Sat, 2009-03-07, 01:07
#4
Re: Best way to cast Int to Byte
[Follow-up to scala-debate, since I'm digressing a bit and proposing
something]
On Fri, Mar 06, 2009 at 09:16:18PM +0100, Sc iss wrote:
> buf(0) = 0x66.asInstanceOf[ Byte ]
>
> or
>
> buf(0) = 0x66.toByte
Blair's example already showed that constant unfolding works properly
with both, but when the value to be converted isn't known statically,
one can compile the following methods:
def f(i: Int) = i.toByte
def g(i: Int) = i.asInstanceOf[Byte]
and see what comes out:
public byte g(int);
Code:
0: iload_1
1: i2b
2: ireturn
public byte f(int);
Code:
0: iload_1
1: i2b
2: ireturn
So both are compiled optimally.
> my hope is one of them gets to be a compile time cast...
If by that you mean "a no-op at JVM level", then that can't happen,
because integer types must be converted with explicit instructions in
order for the code to be validated. Of course the JVM itself may
implement the i2b instruction as a no-op in some circumstances.
I recommend that you use the .toByte method, because asInstanceOf is
too overloaded. It is used for three distinct purposes:
* for standard conversions between built-in numeric types, as in this case
* for dynamically checked downcasts
* for unchecked casts that convert type arguments
The first can be accomplished also with the .toByte/toInt/etc methods,
while the latter two can also be done with pattern matching (using a
typed pattern, possibly with type arguments that are incompatible with
the type of the selector).
It's rather confusing that a single language form does so many so
different things, and in fact a very similar situation in C was a
motivation for having multiple different cast forms for different
purposes in C++. I think Scala should do the same:
* Use only .toByte/.toInt/etc for numeric conversions
* Use only pattern matching with typed patterns to do downcasts, and
_don't allow patterns to be incompatible with the type of the
selector_! (I.e. make "unchecked warnings" be errors in pattern matching)
* Allow .asInstanceOf casts from one type to another only when both
have the same erasure
After this the situation is much more clear: pattern matching is
always safe (and almost always incurs a run-time check), whereas
.asInstanceOf is always a no-op at run-time, but can break type
safety.
Even if it's too late to change the language in order to _enforce_
this policy, I think it would at least be a good idea to _follow_ it
nevertheless.
Lauri
Sat, 2009-03-07, 02:07
#5
Re: Re: Best way to cast Int to Byte
On Fri, Mar 6, 2009 at 11:57 PM, Lauri Alanko wrote:
> [Follow-up to scala-debate, since I'm digressing a bit and proposing
> something]
>
> On Fri, Mar 06, 2009 at 09:16:18PM +0100, Sc iss wrote:
>> buf(0) = 0x66.asInstanceOf[ Byte ]
>>
>> or
>>
>> buf(0) = 0x66.toByte
>
> Blair's example already showed that constant unfolding works properly
> with both, but when the value to be converted isn't known statically,
> one can compile the following methods:
>
> def f(i: Int) = i.toByte
> def g(i: Int) = i.asInstanceOf[Byte]
>
> and see what comes out:
>
> public byte g(int);
> Code:
> 0: iload_1
> 1: i2b
> 2: ireturn
>
> public byte f(int);
> Code:
> 0: iload_1
> 1: i2b
> 2: ireturn
>
> So both are compiled optimally.
>
>> my hope is one of them gets to be a compile time cast...
>
> If by that you mean "a no-op at JVM level", then that can't happen,
> because integer types must be converted with explicit instructions in
> order for the code to be validated. Of course the JVM itself may
> implement the i2b instruction as a no-op in some circumstances.
>
> I recommend that you use the .toByte method, because asInstanceOf is
> too overloaded. It is used for three distinct purposes:
If by "three distinct purposes" you mean "one purpose", yes.
> * for standard conversions between built-in numeric types, as in this case
Note that this behaviour is, according to the specification, wrong.
It's not supposed to work like that.
> * for dynamically checked downcasts
>
> * for unchecked casts that convert type arguments
These are the same operation. They're a forced conversion between two
different types. It just happens that when the cast is wrong the
underlying JVM implementation dictates which fail immediately and
which erroneously claim to succeed and fail mysteriously later.
> The first can be accomplished also with the .toByte/toInt/etc methods,
> while the latter two can also be done with pattern matching (using a
> typed pattern, possibly with type arguments that are incompatible with
> the type of the selector).
>
> It's rather confusing that a single language form does so many so
> different things,
Conveniently, the specification agrees. :-) That's why it decrees that
asInstanceOf does exactly one thing.
> and in fact a very similar situation in C was a
> motivation for having multiple different cast forms for different
> purposes in C++. I think Scala should do the same:
>
> * Use only .toByte/.toInt/etc for numeric conversions
Agreed.
> * Use only pattern matching with typed patterns to do downcasts, and
> _don't allow patterns to be incompatible with the type of the
> selector_! (I.e. make "unchecked warnings" be errors in pattern matching)
Requiring compatibility would not get rid of unchecked warnings.
Consider matching on an Any to get a List[String].
Further, at least ostensibly (there may be some bugs. I haven't
checked this behaviour too carefully and I'm not sure anyone else has
either), you're *already* supposed to only be able to match against a
compatible type.
> * Allow .asInstanceOf casts from one type to another only when both
> have the same erasure
No. That sounds complicated and unnecessary. asInstanceOf is defined
in terms of pattern matching, and is conceptually exactly the same
operation regardless of whether the two have the same erasure
(further, the cast is not guaranteed to succeed at runtime even if the
two have the same erasure. At the moment it happens that it does. In
2.8 it will probably be the case that it will error if the two share a
different path). The fact that some casts which should be are not
dynamically checked is merely an unfortunate necessity.
> After this the situation is much more clear: pattern matching is
> always safe (and almost always incurs a run-time check), whereas
What you suggest would not achieve this.
> .asInstanceOf is always a no-op at run-time, but can break type
> safety.
Nor would it achieve this.
> Even if it's too late to change the language in order to _enforce_
> this policy,
Even were it not too late it would still be a bad idea.
> I think it would at least be a good idea to _follow_ it
> nevertheless.
I don't.
Philosophically, the purpose of the casting operator is to say "I know
what's best, mr type system, and you're damn well going to get out of
the way and do what I tell you to". You should not be using it unless
you know you are correct, and the results of being wrong should be
considered to be undefined. Attempting to distinguish between
different modes of failure at the language level is not useful.
That being said, it's certainly unfortunate that incorrect usage of
asInstanceOf does not fail noisily in more instances than it currently
does. Maybe some of that will be fixable e.g. when the specialisation
stuff Iulian is working on comes into play.
Sat, 2009-03-07, 18:47
#6
Re: Re: Best way to cast Int to Byte
On Fri, Mar 6, 2009 at 11:57 PM, Lauri Alanko wrote:
> * Allow .asInstanceOf casts from one type to another only when both
> have the same erasure
I can't think of any good reason why the following currently legal code,
trait A
trait B
val a : A = new A with B
val b : B = a.asInstanceOf[B]
should be excluded (as it would be by your proposal).
Cheers,
Miles
Sat, 2009-03-07, 19:17
#7
Re: Best way to cast Int to Byte
On Fri, Mar 6, 2009 at 11:17 PM, David MacIver wrote:
> On Fri, Mar 6, 2009 at 8:16 PM, Sc iss wrote:
>> hi,
>>
>> i wonder what is the best (performance / compile-time erasure)
>>
>> way to do something that in java would be
>>
>> byte[] buf = new byte[10]
>> buf[0] = (byte) 0x66
>>
>> ... is that
>>
>> buf(0) = 0x66.asInstanceOf[ Byte ]
>>
>> or
>>
>> buf(0) = 0x66.toByte
>>
>> ? looking at https://lampsvn.epfl.ch/trac/scala/browser/scala/branches/scala-detach/s... - both versions appear. and both seem to be methods... my hope is one of them gets to be a compile time cast...
>
> You should always use the toByte form. It does the right thing with
> regards to bytecode emitted (it's emitted as a single opcode, not a
> method call). The fact that the asInstanceOf[Byte] stuff works is, I
> think, a bug. It's certainly contrary to what the SLS says should
> happen (and inconsistent with regards to its behaviour with upcasts).
> I'm hoping it will go away at some point (though this should not be
> taken as a formal statement that it will).
>
I don't see how asInstanceOf's behavior is a bug. Here's what the SLS says:
The test ~\lstinline@$x$.asInstanceOf[$T$]@ is treated specially if $T$ is a
numeric value type (\sref{sec:cls-value}. In this case the cast will
be translated to an application of a conversion method ~\lstinline@x.to$T$@
(\sref{cls:numeric-value}). For non-numeric values $x$ the operation
will raise a
\code{ClassCastException}.
So I think the behavior is as speced. One can argue whether it's the
right thing to do. The present behavior is as in Java, which is sort
of what we do by default if we do not particularly care for an
alternative. In my mind, asInstanceOf is
not a very nice or important part of the language. That's also why we
chose the unwieldy name, to make it look _less_ nice.
Cheers
Sat, 2009-03-07, 19:27
#8
Re: Best way to cast Int to Byte
On Sat, Mar 7, 2009 at 6:10 PM, martin odersky wrote:
>> You should always use the toByte form. It does the right thing with
>> regards to bytecode emitted (it's emitted as a single opcode, not a
>> method call). The fact that the asInstanceOf[Byte] stuff works is, I
>> think, a bug. It's certainly contrary to what the SLS says should
>> happen (and inconsistent with regards to its behaviour with upcasts).
>> I'm hoping it will go away at some point (though this should not be
>> taken as a formal statement that it will).
>>
> I don't see how asInstanceOf's behavior is a bug. Here's what the SLS says:
>
> The test ~\lstinline@$x$.asInstanceOf[$T$]@ is treated specially if $T$ is a
> numeric value type (\sref{sec:cls-value}. In this case the cast will
> be translated to an application of a conversion method ~\lstinline@x.to$T$@
> (\sref{cls:numeric-value}). For non-numeric values $x$ the operation
> will raise a
> \code{ClassCastException}.
>
> So I think the behavior is as speced.
I beg your pardon. You're quite right. I'd missed that addendum after
the normal definition of asInstanceOf.
> One can argue whether it's the
> right thing to do. The present behavior is as in Java, which is sort
> of what we do by default if we do not particularly care for an
> alternative.
I think it's pretty broken. The standard definition if asInstanceOf is
clean and fairly simple, and it does exactly one thing. Having this
additional complication when there's already a much better alternative
(use the toByte versions) seems odd.
> In my mind, asInstanceOf is
> not a very nice or important part of the language. That's also why we
> chose the unwieldy name, to make it look _less_ nice.
Agreed. But that doesn't absolve us from making it work consistently. :-)
Sc iss wrote:
> hi,
>
> i wonder what is the best (performance / compile-time erasure)
>
> way to do something that in java would be
>
> byte[] buf = new byte[10]
> buf[0] = (byte) 0x66
>
> ... is that
>
> buf(0) = 0x66.asInstanceOf[ Byte ]
>
> or
>
> buf(0) = 0x66.toByte
It looks like they do the same thing. When in doubt, write a small file,
compile it and use javap on it:
class Foo
{
def f1 = 0x66.asInstanceOf[Byte]
def f2 = 0x66.toByte
}
$ javap -c -p Foo
Compiled from "Foo.scala"
public class Foo extends java.lang.Object implements scala.ScalaObject{
...
...
public byte f1();
Code:
0: ldc #13; //int 102
2: i2b
3: ireturn
public byte f2();
Code:
0: ldc #13; //int 102
2: i2b
3: ireturn
...
...
}
Regards,
Blair