need some clarification on compile-time type vs. run-time type
Brendan Eich
brendan at mozilla.org
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
http://wiki.ecmascript.org/doku.php?id=proposals:self_type
> 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
"instance-of"ish.
> 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'.
/be
More information about the Es4-discuss
mailing list