July 2000 Draft
JavaScript 2.0
Libraries
Types
|
Wednesday, February 16, 2000
The following types are predefined in JavaScript 2.0:
Type | Set of Values | Coercions |
---|---|---|
none |
No values | None |
void |
undefined |
Any value undefined |
Null |
null |
undefined null |
Boolean |
true and false |
undefined false |
Integer |
Double-precision IEEE floating-point numbers that are mathematical integers, including positive and negative zeroes, infinities, and NaN | undefined NaN |
Number |
Double-precision IEEE floating-point numbers, including positive and negative zeroes, infinities, and NaN | undefined NaN |
Character |
Single 16-bit unicode characters | None |
String |
Immutable strings of unicode characters | undefined "" |
Function |
All functions | None |
Array |
All arrays | undefined [] |
Type |
All types | undefined any |
any |
All values | None |
Unlike in JavaScript 1.5, there is no distinction between objects and primitive values. All values can have methods. Some values can be sealed, which disallows addition of ad-hoc properties. User-defined classes can be made to behave like primitives.
The above type names are not reserved words. They are considered to be defined in a scope that encloses a package's global scope, so a package could use these type names as identifiers. However, defining these identifiers for other uses might be confusing because it would shadow the corresponding type names (the types themselves would continue to exist, but they could not be accessed by name).
any
is the supertype of all types. none
is the subtype of all types. none
is useful
to describe the return type of a function that cannot return normally because it either falls into an infinite loop or always
throws an exception. void
is useful to describe the return type of a function that can return but that does not
produce a useful value.
A literal number is a member of the type Number
; if that literal has an integral value, then it is also a
member of type Integer
. A literal string is a member of the type String
; if that literal has exactly
one 16-bit unicode character, then it is also a member of type Character
.
We can use the following operators to construct more complex types. t is a type expression and u is a value expression in the table below.
Type | Values | Coercions |
---|---|---|
+ t |
null or any value belonging to type t |
null null ; undefined
null (if undefined is not a
member of t); any other coercions already defined for t |
~ t |
undefined or any value belonging to type t |
undefined undefined ;
any other coercions already defined for t |
singleton( u) |
Only the value u | None |
The language cannot syntactically distinguish type expressions from value expressions, so a type expression can also use
any other value operators such as !
, |
, and .
(member access). Except for parentheses,
most of them are not very useful, though. See also the type
expression syntax rationale for other possible type constructors.
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. null
is not an instance of a user-defined class.
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 x:Integer;
restricts the values that can be held in variable x
to be integers.
Type declarations use the Pascal-style colon syntax. See the type declaration syntax rationale for an alternative.
A type declaration does not affect 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 x:MyType = 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 Z:Type = Integer; function abs_val(i:Z):Z { return i<0 ? -i : i; }
is equivalent to:
function abs_val(i:Integer):Integer { return i<0 ? -i : i; }
As another example, the following method takes a type and returns an instance of that type:
method QueryInterface(T:Type):T {
... }
Coercions can take place in the following situations:
@
t operator.In any of these cases, if v t, then v is passed unchanged. If v t, then if t defines a mapping for value v then that mapped v is used; otherwise an error occurs.
@
OperatorOne can explicitly request a coercion in an expression by using the @
operator. This operator has the same
precedence as .
and coerces its left operand to the right operand, which must be a type. ... v@
t ...
can be used in an expression and has the same effect as:
function coerce_to_
t(a:
t):
t {return a} //
Declared at the top level
... coerce_to_
t(
v)
...
assuming that coerce_to_
t is an identifier not used anywhere else. The @
operator is useful as a type assertion as in w@Window
. It's a postfix operator to simplify cascading expressions:
w@Window.child@Window.pos
is equivalent to:
(((w@Window).child)@Window).pos
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, Integer(258.1)
returns the integer 258
, and String(2+2==4)
returns
the string "true"
.
If value is already a member of type, the type cast returns value unchanged. If value can be coerced to type, the type cast returns the result of the coercion. Otherwise, the effect of a type cast depends on type.
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 16, 2000 |