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

Brendan Eich brendan at
Mon Nov 12 15:58:22 PST 2007

On Nov 12, 2007, at 1:40 PM, YR Chen wrote:

> Definitely like it. I wonder how convoluted the grammar change was  
> - did it require a new value_expr_no_conflicts_with_type_expr  
> production and all related productions/rules?

Not sure, but top-down parsers have it easy, discriminating on the  
leftmost token and if none of the short list of structural type  
tokens match, falling into a value-expression sub-parser invocation.

As I noted elsewhere, we have such a grammar (not quite the same,  
consider '(' as the leftmost token of the new operand) for the new  
operator (see the overview, "Record and array types" section).

> Yeah, I meant "anonymous interfaces". I know they're not the same  
> as interfaces, but they're similar in that they place a set of  
> restrictions or guarantees on a class or object that "implements"  
> them.

Just FYI, we tried for self-types (see Kim Bruce's work) to make  
structural types with "methods" stronger, but deferred. See

> I think that would be a good thing. Another thought: if |x is v|,  
> where |v| is a meta-object, works, then one would think that it  
> should also work for |like|, e.g.
> var x = int
> 10 is x; // ok
> 10 is like x; // ?
> But if that last statement is allowed, then so is |var y: like x|,  
> which is undecidable (if that's the correct term), so evidently | 
> like| shouldn't work with value exprs.

This is a hot topic. We could indeed allow all sorts of type  
expressions, and define evaluation rules so that (I hope) nothing  
diverges and we don't need to set a watchdog timer on strict mode's  
type checker. The static guarantees go down because strict mode will  
punt anything it can't figure out to runtime, treating the compile- 
time type as *. It seems wiser at the moment to restrict type  
annotations and remain future proof, but make 'is' friendlier as you  
and I have been discussing.

> Might want to mention this in any clarification you put into the  
> spec, even if it's strictly disallowed in the formal grammar - that  
> even though |is| allows a value expr on the right side, it cannot  
> be nested within a type expr. That means given |var x|, none of |10  
> is like x|, |10 is (x)|, |10 is {p: x}|, etc. are syntactically  
> allowed.

I think we're now inclined to allow those but insist on a type at  
runtime. But this is something to discuss more.

> There are couple potential problems with upgrading |instanceof| to  
> match the syntax of the revised |is|:
> 1) Function expr syntax ambiguity. Consider:
> a) x is function(p: int): int // ok
> b) x is function(p: int): int {} // syntax error
> c) x instanceof function(p: int): int // ok?
> d) x instanceof function(p: int): int {} // syntax error?

Oh, I see -- on second thought I meant nothing like allowing (d) --  
sorry. instanceof only takes a value expression on its right, but if  
that evaluates to a type meta-object, it does something sane and  

> 2) Object literal syntax ambiguity. If it is possible to simulate a  
> constructor with an object literal, namely creating an object with  
> [[HasInstance]], we'll have a similar situation to (1). I'm not  
> sure if it's possible, so I'll make up some syntax in the following  
> example to indicate what I mean:
> x instanceof {meta::construct: function() {}}
> That object literal is supposed to create a constructor-like  
> object, but like I said, I'm not sure if it's really possible and  
> of the exact syntax required.

Not possible, so if we want to allow {p: t, q: u} on the right of  
instanceof, we have the choice to treat that as a type expression  
(likewise for [a, b] and (c, d)). Again the new operator can handle  
array and object types similarly, because there's no way for you to  
write a constructible value initialiser (object or, needless to say,  
array initialiser). If we do not fear closing the door to future  
extensions that enable constructible or has-instance-able  
initialisers, then I think we're on solid ground. And I see no point  
in adding ways to make such things, given the alternative meanings  
competing for the same syntax here (value vs. type expressions with  
instanceof and new, I mean).

> Anyway, that |{...}| is ambiguous in that it can either be treated  
> as a record structural type or an object literal. In ES3, there's  
> no way to create a constructor from an object literal (AFAIK), so  
> the above syntax (ignoring the namespace) would be a runtime error.  
> Thus, there is no backwards compat issue. If it were allowed in  
> ES3, as before, it is guaranteed to resolve to false. So the | 
> {...}| should be treated as a record structural type.
> 3) Parenthesis ambiguity. This is the most troublesome one. Consider:
> a) x is (int) // ok
> b) x is (some_constructor) // syntax error
> c) x is ({p: int}) // ok
> d) x instanceof (int) // ok
> e) x instanceof (some_constructor) // syntax error?
> f) x instanceof ({p: int}) // how should this be treated?

Yes, and parenthesized expression may follow operator new, so this is  
a hard limit.

> If we really want to upgrade |instanceof| yet keep it coherent with  
> |is| in both semantics and syntax, we may have to visit the |type|  
> operator again, but that should be a last resort.

That unary type operator is still around in the spec space, awaiting  
hookup in the RI, at least as far as I can recall. But with the  
unification (partial, but practical) of type and (else) value  
expressions for 'is", or vice versa for instanceof/new, I agree we  
should avoid reaching for unary 'type'.


More information about the Es4-discuss mailing list