Auto-boxing is done via a coercion function in the Object class:
/** Implicitly convert non-object values to Boxed types. */
static def coerce[%T] (value:T) -> Object { return ValueRef[T](value); }
static def coerce(value:Object) -> Object { return value; }
If the input argument derives from Object then it is returned unchanged, otherwise if it's a value type, such an int, it's wrapped in a ValueRef. This happens automatically whenever you attempt to pass a primitive type to a function that takes an Object as an argument.
The ValueRef class itself is fairly simple:
/** A reference type used to contain a value type. */
class ValueRef[%T] : Ref {
let value:T;
def construct(value:T) {
self.value = value;
}
/** Return a string representation of the contained value. */
def toString() -> String {
return self.value.toString();
}
}
To unbox a boxed value, use the static "valueOf" method in class "Ref". It requires an explicit type parameter:
var v = Ref.valueOf[int](obj);
The 'valueOf' method is defined for each different primitive type and uses the 'classify' statement to downcast to the correct wrapper type. Here's the entire 'Ref' class:
/** Abstract class used to represent a reference to some value. */
abstract class Ref {
private static {
/// Convert signed integers to their unsigned equivalents. Supresses conversion warnings.
def asUnsigned(v:int8) -> uint8 { return uint8(v); }
def asUnsigned(v:int16) -> uint16 { return uint16(v); }
def asUnsigned(v:int32) -> uint32 { return uint32(v); }
def asUnsigned(v:int64) -> uint64 { return uint64(v); }
/// Convenience functions to check whether the given input is within the numeric range
/// of the type specified by the type parameter.
def rangeCheck[%T](value:int32) {
if value < T.minVal or value > T.maxVal {
throw TypecastException();
}
}
def rangeCheck[%T](value:int64) {
if value < T.minVal or value > T.maxVal {
throw TypecastException();
}
}
def rangeCheck[%T](value:uint32) {
if value > asUnsigned(T.maxVal) {
throw TypecastException();
}
}
def rangeCheck[%T](value:uint64) {
if value > asUnsigned(T.maxVal) {
throw TypecastException();
}
}
def rangeCheck[%T](value:char) {
if uint32(value) > asUnsigned(T.maxVal) {
throw TypecastException();
}
}
def check(value:bool) {
if not value {
throw TypecastException();
}
}
/// Check to insure that the input value is not negative.
def signCheck(value:int32) {
if value < 0 {
throw TypecastException();
}
}
def signCheck(value:int64) {
if value < 0 {
throw TypecastException();
}
}
}
/// Convert an object containing a number to the requested number type.
static def valueOf[bool](ref:Object) -> bool {
classify ref {
as v:ValueRef[bool] { return v.value; }
else {
throw TypecastException();
}
}
}
static def valueOf[char](ref:Object) -> char {
classify ref {
as v:ValueRef[int8] { signCheck(v.value); return char(v.value); }
as v:ValueRef[int16] { signCheck(v.value); return char(v.value); }
as v:ValueRef[int32] {
check(v.value >= 0 and uint32(v.value) <= uint32(char.maxVal));
return char(v.value);
}
as v:ValueRef[int64] {
check(v.value >= 0 and uint64(v.value) <= uint64(char.maxVal));
return char(v.value);
}
as v:ValueRef[uint8] { return char(v.value); }
as v:ValueRef[uint16] { return char(v.value); }
as v:ValueRef[uint32] { check(v.value <= uint32(char.maxVal)); return char(v.value); }
as v:ValueRef[uint64] { check(v.value <= uint64(char.maxVal)); return char(v.value); }
as v:ValueRef[char] { return v.value; }
else {
throw TypecastException();
}
}
}
static def valueOf[int8](ref:Object) -> int8 {
classify ref {
as v:ValueRef[int8] { return v.value; }
as v:ValueRef[int16] { rangeCheck[int8](v.value); return int8(v.value); }
as v:ValueRef[int32] { rangeCheck[int8](v.value); return int8(v.value); }
as v:ValueRef[int64] { rangeCheck[int8](v.value); return int8(v.value); }
as v:ValueRef[uint8] { rangeCheck[int8](v.value); return int8(v.value); }
as v:ValueRef[uint16] { rangeCheck[int8](v.value); return int8(v.value); }
as v:ValueRef[uint32] { rangeCheck[int8](v.value); return int8(v.value); }
as v:ValueRef[uint64] { rangeCheck[int8](v.value); return int8(v.value); }
as v:ValueRef[char] { rangeCheck[int8](v.value); return int8(v.value); }
else {
throw TypecastException();
}
}
}
static def valueOf[int16](ref:Object) -> int16 {
classify ref {
as v:ValueRef[int8] { return int16(v.value); }
as v:ValueRef[int16] { return v.value; }
as v:ValueRef[int32] { rangeCheck[int16](v.value); return int16(v.value); }
as v:ValueRef[int64] { rangeCheck[int16](v.value); return int16(v.value); }
as v:ValueRef[uint8] { return int16(v.value); }
as v:ValueRef[uint16] { rangeCheck[int16](v.value); return int16(v.value); }
as v:ValueRef[uint32] { rangeCheck[int16](v.value); return int16(v.value); }
as v:ValueRef[uint64] { rangeCheck[int16](v.value); return int16(v.value); }
as v:ValueRef[char] { rangeCheck[int16](v.value); return int16(v.value); }
else {
throw TypecastException();
}
}
}
static def valueOf[int32](ref:Object) -> int32 {
classify ref {
as v:ValueRef[int8] { return v.value; }
as v:ValueRef[int16] { return int32(v.value); }
as v:ValueRef[int32] { return v.value; }
as v:ValueRef[int64] { rangeCheck[int32](v.value); return int32(v.value); }
as v:ValueRef[uint8] { return int32(v.value); }
as v:ValueRef[uint16] { return int32(v.value); }
as v:ValueRef[uint32] { rangeCheck[int32](v.value); return int32(v.value); }
as v:ValueRef[uint64] { rangeCheck[int32](v.value); return int32(v.value); }
as v:ValueRef[char] { rangeCheck[int32](v.value); return int32(v.value); }
else {
throw TypecastException();
}
}
}
static def valueOf[int64](ref:Object) -> int64 {
classify ref {
as v:ValueRef[int8] { return int64(v.value); }
as v:ValueRef[int16] { return int64(v.value); }
as v:ValueRef[int32] { return int64(v.value); }
as v:ValueRef[int64] { return v.value; }
as v:ValueRef[uint8] { return int64(v.value); }
as v:ValueRef[uint16] { return int64(v.value); }
as v:ValueRef[uint32] { return int64(v.value); }
as v:ValueRef[uint64] { rangeCheck[int64](v.value); return int64(v.value); }
as v:ValueRef[char] { rangeCheck[int64](v.value); return int64(v.value); }
else {
throw TypecastException();
}
}
}
static def valueOf[uint8](ref:Object) -> uint8 {
classify ref {
as v:ValueRef[int8] { signCheck(v.value); return uint8(v.value); }
as v:ValueRef[int16] {
check(v.value >= 0 and v.value <= int16(uint8.maxVal));
return uint8(v.value);
}
as v:ValueRef[int32] {
check(v.value >= 0 and v.value <= int32(uint8.maxVal));
return uint8(v.value);
}
as v:ValueRef[int64] {
check(v.value >= 0 and v.value <= int64(uint8.maxVal));
return uint8(v.value);
}
as v:ValueRef[uint8] { return v.value; }
as v:ValueRef[uint16] { rangeCheck[uint8](v.value); return uint8(v.value); }
as v:ValueRef[uint32] { rangeCheck[uint8](v.value); return uint8(v.value); }
as v:ValueRef[uint64] { rangeCheck[uint8](v.value); return uint8(v.value); }
as v:ValueRef[char] { rangeCheck[uint8](v.value); return uint8(v.value); }
else {
throw TypecastException();
}
}
}
static def valueOf[uint16](ref:Object) -> uint16 {
classify ref {
as v:ValueRef[int8] { signCheck(v.value); return uint16(v.value); }
as v:ValueRef[int16] { signCheck(v.value); return uint16(v.value); }
as v:ValueRef[int32] {
check(v.value >= 0 and v.value <= int32(uint16.maxVal));
return uint16(v.value);
}
as v:ValueRef[int64] {
check(v.value >= 0 and v.value <= int64(uint16.maxVal));
return uint16(v.value);
}
as v:ValueRef[uint8] { return v.value; }
as v:ValueRef[uint16] { return v.value; }
as v:ValueRef[uint32] { rangeCheck[uint16](v.value); return uint16(v.value); }
as v:ValueRef[uint64] { rangeCheck[uint16](v.value); return uint16(v.value); }
as v:ValueRef[char] { rangeCheck[uint16](v.value); return uint16(v.value); }
else {
throw TypecastException();
}
}
}
static def valueOf[uint32](ref:Object) -> uint32 {
classify ref {
as v:ValueRef[int8] { signCheck(v.value); return uint32(v.value); }
as v:ValueRef[int16] { signCheck(v.value); return uint32(v.value); }
as v:ValueRef[int32] { signCheck(v.value); return uint32(v.value); }
as v:ValueRef[int64] {
check(v.value >= 0 and v.value <= int64(uint32.maxVal));
return uint32(v.value);
}
as v:ValueRef[uint8] { return uint32(v.value); }
as v:ValueRef[uint16] { return uint32(v.value); }
as v:ValueRef[uint32] { return v.value; }
as v:ValueRef[uint64] { rangeCheck[uint32](v.value); return uint32(v.value); }
as v:ValueRef[char] { return uint32(v.value); }
else {
throw TypecastException();
}
}
}
static def valueOf[uint64](ref:Object) -> uint64 {
classify ref {
as v:ValueRef[int8] { signCheck(v.value); return uint64(v.value); }
as v:ValueRef[int16] { signCheck(v.value); return uint64(v.value); }
as v:ValueRef[int32] { signCheck(v.value); return uint64(v.value); }
as v:ValueRef[int64] { signCheck(v.value); return uint64(v.value); }
as v:ValueRef[uint8] { return uint64(v.value); }
as v:ValueRef[uint16] { return uint64(v.value); }
as v:ValueRef[uint32] { return uint64(v.value); }
as v:ValueRef[uint64] { return v.value; }
as v:ValueRef[char] { return uint64(v.value); }
else {
throw TypecastException();
}
}
}
static def valueOf[float](ref:Object) -> float {
classify ref {
as v:ValueRef[int8] { return float(v.value); }
as v:ValueRef[int16] { return float(v.value); }
as v:ValueRef[int32] { return float(v.value); }
as v:ValueRef[int64] { return float(v.value); }
as v:ValueRef[uint8] { return float(v.value); }
as v:ValueRef[uint16] { return float(v.value); }
as v:ValueRef[uint32] { return float(v.value); }
as v:ValueRef[uint64] { return float(v.value); }
as v:ValueRef[float] { return v.value; }
as v:ValueRef[double] { return float(v.value); }
else {
throw TypecastException();
}
}
}
static def valueOf[double](ref:Object) -> double {
classify ref {
as v:ValueRef[int8] { return double(v.value); }
as v:ValueRef[int16] { return double(v.value); }
as v:ValueRef[int32] { return double(v.value); }
as v:ValueRef[int64] { return double(v.value); }
as v:ValueRef[uint8] { return double(v.value); }
as v:ValueRef[uint16] { return double(v.value); }
as v:ValueRef[uint32] { return double(v.value); }
as v:ValueRef[uint64] { return double(v.value); }
as v:ValueRef[float] { return double(v.value); }
as v:ValueRef[double] { return v.value; }
else {
throw TypecastException();
}
}
}
}
Although this class looks complex, that's mainly because there are a lot of possible combinations of conversions. In terms of usage, it's actually quite simple. It also demonstrates a number of features of Tart, including partial specialization, conversion constructors, type objects (T.minVal) and of course 'classify'.
BTW, I went ahead with Guido's suggestions about the integer type names as you can see.
No comments:
Post a Comment