February 1999 Draft
JavaScript 2.0
Types

Wednesday, February 17, 1999
The following primitive types are predefined in JavaScript 2.0:
Type 
Values 

void 
undefined 
null_t 
null 
boolean 
true and false 
byte 
Integers between 128 and 127 inclusive 
ubyte 
Integers between 0 and 255 inclusive 
short 
Integers between 32768 and 32767 inclusive 
ushort 
Integers between 0 and 65535 inclusive 
int 
Integers between 2147483648 and 2147483647 inclusive 
uint 
Integers between 0 and 4294967295 inclusive 
long 
Integers between 9223372036854775808 and 9223372036854775807 inclusive 
ulong 
Integers between 0 and 18446744073709551615 inclusive 
integer 
All integers (of arbitrary size) 
float 
Singleprecision IEEE floatingpoint numbers, including positive and negative zeroes and infinities and NaN 
double 
Doubleprecision IEEE floatingpoint numbers, including positive and negative zeroes and infinities and NaN 
real 
Any integer or double 
string 
Immutable strings of unicode characters 
funct 
Any function or method 
type 
Any type 
any 
Any value 
Integers are distinct values from floatingpoint numbers. A literal number that contains a decimal point or exponent is considered to be a floatingpoint number; otherwise it's an integer. This distinction does not matter much to most scripts because integers and floatingpoint numbers coerce freely to each other, but there are subtle differences between integers and floatingpoint numbers in the handling of negative zero and values beyond ±2^{53}.
The above type names are not reserved words. They become available at the top level once a script imports the Types
library.
Any class defined using the class
declaration is also a type that denotes the set of all of its and its descendants'
instances. These include the predefined classes, so Object
, Date
, etc. are all types. Note that
null
is not an instance of any class.
We can use the following operators to construct more complex types. t is a type expression in the expressions below.
Type  Values 

t ! 
null or any value of type t 
t ~ 
undefined or any value of type t 
t [] 
any array of values of type t 
In addition to the above, a type expression can use any value operators. Except for parentheses, most of them are not very useful, though.
We write a b to denote that a is a subtype of b. Subtyping is transitive, so if a b and b c then a c is also true. Subtyping is also reflexive: a a.
The following subtype relations hold on the basic types:
byte short
int
long integer 

ubyte ushort
uint
ulong integer 

ubyte short 

ushort int 

uint long 

integer real 

float double
real 

c Object 
for any class c 
c d  for any class c and subclass d of c 
t any 
for any type t 
t~ void 
for any type t 
t! null_t 
for any type t 
Every other subtype relation can be derived from the above by applying the transitivity and reflexivity rules.
We write v t to indicate that v is a value that is a member of type t. The following subtyping rule holds: if v t and t s, then v s holds as well. Thus any particular value v is simultaneously a member of many types.
A JavaScript 2.0 value does not have an intrinsic most specific type  one can ask whether the value v
is a member of a given type t, but this does not prevent the value v from also being a member of some
unrelated type s. For example, 3
is a member of type byte
as well as type ubyte
,
but neither byte
nor ubyte
is a subtype of the other. Thus it is meaningless to talk about the
type of a value  a value has many types.
On the other hand, a variable does have a particular type. If one declares a variable x of type byte
,
then whatever value is held in x is guaranteed to have type byte
, and one can assign any value of
type byte
to x.
Types are generally used to restrict the set of objects that can be held in a variable or passed as a function argument. For example, the declaration
var integer x;
restricts the values that can be held in variable x
to be integers.
A type declaration never affects the semantics of reading the variable or accessing one of its members. Thus,
as long as expression new MyType()
returns a value of type MyType
, the following two code snippets
are equivalent:
var MyType x = new MyType(); x.foo();
var x = new MyType(); x.foo();
This equivalence always holds, even if these snippets are inside the declaration of class MyType
and foo
is a private field of that class. As a corollary, adding true type annotations does not change the meaning of a program.
A type is also a value (whose type is type
) and can be used in expressions, assigned to variables, passed
to functions, etc. For example, the code
const type Z = integer; function abs_val(Z i) Z { return i<0 ? i : i; }
is equivalent to:
function abs_val(integer i) integer { return i<0 ? i : i; }
As another example, the following method takes a type and returns an instance of that type:
method QueryInterface(type t) t {
... }
Coercions can take place in the following situations:
In any of these cases, if v t, then v is passed unchanged. However, if v t, then v is sometimes coerced to type t. The following coercions are predefined:
t  v  Result 

byte , ubyte 
v integer 
The unique integer w t that satisfies the congruence w = v (mod 256) 
short , ushort 
v integer 
The unique integer w t that satisfies the congruence w = v (mod 65536) 
int , uint 
v integer 
The unique integer w t that satisfies the congruence w = v (mod 4294967296) 
long , ulong 
v integer 
The unique integer w t that satisfies the congruence w = v (mod 2^{64}) 
t integer 
v double 
If v has no fractional part, v is reinterpreted as an integer. ±0.0 become the integer
0. If v has a fractional part or is ± or a NaN, the coercion fails. 
float , double 
v integer 
The floatingpoint number w t mathematically closest to v using IEEE roundtonearest semantics. 0 becomes +0.0. 
float 
v double 
The floatingpoint number w t mathematically closest to v using IEEE roundtonearest semantics. 
null_t 
undefined 
null 
boolean 
undefined 
false 
t integer 
undefined 
0 
t double 
undefined 
+0.0 
string 
undefined 
"" 
If several coercions apply, the one earlier in the list is selected (this will not happen unless some language extension defines a type that multiply inherits from several predefined types).
A type cast performs more aggressive transformations than a type coercion. To cast a value to a given type, we use the type as a function, passing it the value as an argument:
type(
value)
For example, byte(258.1)
returns the byte 2
, and string(2+2==4)
returns the string
"true"
.
Need to specify the semantics of type casts. They are intended to mimic the current ToNumber, ToString, etc. methods.
Waldemar Horwat Last modified Wednesday, February 17, 1999 