need some clarification on compile-time type vs. run-time type

Brendan Eich brendan at
Fri Nov 9 17:53:52 PST 2007

On Nov 9, 2007, at 5:29 PM, Yuh-Ruey Chen wrote:

> The confusion I'm getting is that there seems to be many ways to check
> or differentiate between types. For example, consider the following  
> ES3
> function:
> function foo(x, t) {
>     if (!(x instanceof t))
>         throw some_type_error;
>     print(x);
> }
> If t were a fixed type property, then foo could be redefined as:
> function foo.<t>(x) {
>     if (!(x is t))
>        throw some_type_error;
>     print(x);
> }

Here t is the name of a type parameter to foo, so it is by definition  
fixed -- it doesn't matter how you instantiate foo.<T> for some T --  
but there again, in the foo.<T> expression, you need a fixed type  
term T.

> Or maybe the following is possible (it's currently disallowed in  
> the RI):
> function foo.<t>(x: t) {
>     print(x);
> }

I'll let Graydon reply in full, and give an update -- I heard he  
nearly has type params working.

> Which one is preferred in ES4? The ES3 version is more flexible in a
> way, since it treats types as first-class values,

A constructor function is not a type in ES1-3, it's a function  
object, which if user-defined has a completely writable prototype  
property that instanceof checks. So it is not bad (or good), but I'm  
here to say: it's not about types in the ES4 sense.

Indeed user-defined constructor functions all make Object instances,  
by definition, although you could strengthen them to make structural  
subtypes of Object in ES4:

function MyConstructor(a, b) {
     return {a: a, b: b} : {a: int, b: string};

> but the last version
> is the most efficient. Users will have to deal with this choice,  
> but it
> requires a decent understanding of the type system to make a good  
> choice.

Users can buy by the yard. The old ways work for the dynamic  
constructor/prototype world everyone knows.

Above you have made three different things. The instanceof check is  
not the same as the |is| check. The type paramter example is yet  
again different -- it's just printing x assuming x is compatible with  
t -- that is, that there's no type error on attempt to call foo.<T>,  
e.g. foo.<Date>(new RegExp).

> And it doesn't end there. I haven't even addressed the |is like|
> compound operator,

It's not a compound operator: 'like' is a type constructor or type  
unary operator if you prefer: like T is a type, you can use it  
freely. Thus because (x is T) can be tested, and T can be defined as  
like U, you can write (x is like U). Make sense?

> of which there is no counterpart in |instanceof|
> since structural types apparently can't be stored as non-fixed type
> properties (|type x={a:int};y=x;| doesn't work in the RI).

Type are types, not functions; the instanceof right operand is a  
*function* per ES1-3 and backward compatibility.

> I'm not sure how to phrase this, but it seems to me that ES4 is trying
> to make fixed properties and non-fixed properties (and by extension,
> type expressions and value expressions, and compile-time features and
> run-time features) as similar and compatible as possible (e.g. |10 is
> int| and |10 instanceof int|), yet there are evidently many cases  
> where
> they can't be interchanged (e.g. my first example).

I think you are mixing up fixed and non-fixed properties with types  
and functions.

> I know from
> experience that the more similar concepts get, the higher the  
> potential
> for confusion, until they become the one and the same. And the two
> concepts in question here cannot be one and the same if we want ES4 to
> support efficient compilation. Perhaps, to reduce the confusion, the
> differences between the two can be more pronounced, either through
> syntax and/or behavior. I don't have any specific suggestions though.

Here's what should work:

10 is int => true
10 instanceof int => true
type T = int
10 is T => true
10 instanceof T => true

No confusion, so far (IIRC the RI has a bug on the last line, but  
let's assume it is fixed). Now:

let U = int
10 instanceof U => true
10 is U => error

Using a const (or let const) does not help here, only type will do.

> At the very least, the differences and similarities need to be  
> fully and
> carefully documented. ES3 already has plenty of gotchas, and ES4 seems
> to be introducing plenty more.

It's true that ES4 is introducing optional types. But remember,  
they're optiona. You don't have to use them, but if you choose to,  
you need to follow the rules about using type definitions or  
equivalent (class, interface) to make bindings that are fixed typenames.

One escape hatch is to use reflection, which looks something like

     use namespace reflect

That's not working for me in the RI, and I may have misremembered a  
method name. Graydon knows best.


More information about the Es4-discuss mailing list