March 1999 Draft
JavaScript 2.0
Machine Types Library
previousupnext

Tuesday, March 23, 1999

Purpose

The machine types library is an optional library that provides additional low-level types for use in JavaScript 2.0 programs. On implementations that support this library, these types provide faster, Java-style integer operations that are useful for communicating between JavaScript 2.0 and other programming languages and for performance-critical code. These types are not intended to replace number and integer for general-purpose scripting.

Contents

When the machine types library is imported via an import of "machine-types" version 1, the following types become available:

Type

Values

byte Machine integers between -128 and 127 inclusive
ubyte Machine integers between 0 and 255 inclusive
short Machine integers between -32768 and 32767 inclusive
ushort Machine integers between 0 and 65535 inclusive
int Machine integers between -2147483648 and 2147483647 inclusive
uint Machine integers between 0 and 4294967295 inclusive
long Machine integers between -9223372036854775808 and 9223372036854775807 inclusive
ulong Machine integers between 0 and 18446744073709551615 inclusive

Values belonging to the eight machine integer types above are distinct from each other and from values of type integer. Thus, byte(7) is distinct from int(7), which in turn is distinct from the plain integer 7. However, the coercions listed below usually hide these distinctions.

No subtype relations hold between the machine types.

The above type names are not reserved words.

Coercions

The following coercions take place:

Operations

Machine integers support the arithmetic operators +, -, *, /, %, comparisons ==, !=, <, >, <=, =>, and bitwise logical operations ~, &, |, ^, <<, >>. If supplied two operands of different machine integer types M1 and M2, all of these binary operators except << and >> first coerce both operands to the same type M. If M1 appears before M2 in the list byte, ubyte, short, ushort, int, uint, long, ulong, then M is M2; otherwise M is M1. Then these operators perform the operation and finally return the result as a value of type M. If the result is not within range of the target type M, it is treated modulo |M|.

If one of the operands is a machine integer of type M and the other is an integer value v, then v is first coerced to type M.

The result type of a shift expression (<< or >>) is the same as the type of its first operand. The second operand's type does not affect the type of the result. Right shifts are signed if the first operand has type byte, short, int, or long, and unsigned if it has type ubyte, ushort, uint, or ulong.

Discussion

These rules are designed to permit machine integer operations to be implemented as single instructions on most processor architectures yet give predictable results. Overflows wrap around instead of signaling errors because such behavior is useful for many bit-manipulation algorithms and permits much better optimization of performance-critical code. Code that is concerned about overflows should be using regular integer instead of the machine integer types.

Disjointness of Machine Types

Why are values of the eight machine integer types distinct? This was done because of a desire to allow arithmetic operators to only support 32 bits when operating on int values. Let's take a look at the alternative:

Suppose we unify the values of all eight machine types so that int(2000000000) is indistinguishable from long(2000000000). To what precision should an operator like + calculate its results? Clearly, if we're adding two long values and the result is within the range of long values, then we'd expect to get the right result. In particular, long(2000000000) + long(2000000000) should yield long(4000000000). However, long(2000000000) is indistinguishable from int(2000000000), so int(2000000000) + int(2000000000) should also yield long(4000000000), which is not representable as an int value. Thus, even if both operands are known to be int values, the + operator has to use 64-bit arithmetic.

If a has type int and we compute a+1, then we have to use 64-bit arithmetic because the result could be 2147483648. However, if we compute var int r = a+1 instead, then a smart compiler could make do with 32-bit arithmetic because the result is treated modulo 232. However, this trick would not work with an expression such as var boolean b = a+1 > 0.

The alternative is viable but it leads to more demand for 64-bit arithmetic. It does have the advantage that one does not need to worry about intermediate overflows as long as the values don't approach 264.

Single-Precision Floating-Point Type

Do we want to support a float type for holding single-precision IEEE floating-point numbers? This type may be useful for:

One difficulty with supporting float is deciding what the coercion rules should be. If we invoke + with one number operand and one float operand, should the result be a float or a number? One might expect number, but this makes adding constants to floats using single-precision arithmetic awkward since every constant is a number. If s is a float, the expression s+1 would yield a number instead of a float because 1 is a number. One would have to write s+float(1) instead.


Waldemar Horwat
Last modified Tuesday, March 23, 1999
previousupnext