|
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 |
Single-precision IEEE floating-point numbers, including positive and negative zeroes and infinities and NaN |
double |
Double-precision IEEE floating-point 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 floating-point numbers. A literal number that contains a decimal point or exponent is considered to be a floating-point number; otherwise it's an integer. This distinction does not matter much to most scripts because integers and floating-point numbers coerce freely to each other, but there are subtle differences between integers and floating-point numbers in the handling of negative zero and values beyond ±253.
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 264) |
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 floating-point number w t mathematically closest to v using IEEE round-to-nearest semantics. 0 becomes +0.0. |
float |
v double |
The floating-point number w t mathematically closest to v using IEEE round-to-nearest 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 |