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

Yuh-Ruey Chen maian330 at
Mon Nov 19 01:31:53 PST 2007

More clarifications and updates to my proposal:

Yuh-Ruey Chen wrote:
> The only real non-syntactic issue between type exprs and value exprs is
> that in type exprs, the identifiers must be fixed type properties.
> Everything else, such structural types and function types (ignoring the
> identifiers), is fixed. For ex, |{p: x}| will always mean the same
> thing, given that x is a fixed type; it can't be mutated. The rest of
> the issues are syntactic ambiguities. So for each of these ambiguities
> that I'm aware of, I'll either prefix it with |type| or "match" the
> semantics between the value and type expr. Note that |type| is no longer
> an operator; it can only be used in certain situations as listed below
> (and as the type declaration/alias statement).

Just realized a problem. The grouping operator (parentheses) means
something different for type exprs and value exprs. Type exprs can only
nest type exprs within parenthesis, while value exprs can nest any value
expr within them. Couple choices here:

1) Leave this is a distinction between type expr and value expr.
Downside to this is that type expr and value expr won't fully be unified
(and the downside to that has been amply discussed).

2) Eliminate the ambiguity in the grammar. Introduce |type (...)|.
Downside is the verbosity and possible confusion as to when to use |type
(...)| rather than |(...)| (or at least why they have to be different).

3) Don't change the grammar and handle the ambiguity by keeping track of
whether a particular expression resolves to a type and throwing early
errors when we're in a type expr context and we're trying to perform an
illegal operation on the type (e.g. non-type operators like +). Since
types are computed early, determining whether a particular expr resolves
to a type can also be computed early, so this type of processing can be
done. I have some experience making a pseudo-C parser, and this is
similar to keeping track of whether an expr is an lvalue. In essence,
the term "type expr" is not a grammar production and is unrelated to
operator precedence; it's an "aspect" of an expression (just like
lvalues). Downside to this is that it complicates the parser logic.

I think (3) is the best solution. It's the most convenient for the user.
It does make the learning curve slightly steeper in that now the user
needs to keep in mind that type exprs cannot contain non-type exprs AND
in type annotations and all type operators besides |is| and
|instanceof|, type exprs must contain only fixed type prop identifiers.
But I don't think it's that bad.

Also, although it's not strictly necessary to keep the "type exprs only
nest type exprs" principle outside of type annotations et al., I think
it makes type annotations and |is| more coherent, in that the only
difference between them is the fixed type prop identifier restriction.
BTW, we really need a term that represents type exprs in type
annotations et al.; it's getting repetitive to say "type exprs in type
annotations and all type operators besides |is| and |instanceof|" all
the time...

> 2) union types:
> Create a new union meta-object type so that "x | y", where both x and y
> are meta-objects, evaluates to a meta-object of this type representing
> the union of the types within x and y. The enclosing parentheses can be
> omitted, but |()| still means the bottom type. Thus, the parenthesis
> only purpose now is grouping. However, since |is| and |instanceof| have
> higher precedence than "|", the parentheses must be used for "|" in
> those exprs.

The way I've defined the union operator here introduces another value
vs. type expr conflict. Although pretty nifty, it would allow exprs
like: "x | func()" or "(b? int : double) | string", which shouldn't be
allowed in type exprs considering that type exprs should only nest other
type exprs. The precedence of "|" also poses an issue since it's
completely different from that of type primaries. The operands of "|"
can not only be type primaries but also any value expr with higher
predence than "|". This violates the principle that type exprs can only
nest type exprs.

I think solution (3) above can handle this though with some
modification, especially because it redefines the term "type expr" to
have nothing to do with operator precedence. Specifically, if an operand
of "|" resolves to a type, throw early errors if the other operand
doesn't resolve to a type. This would invalidate and throw early errors
for the above "|" examples.

> 4) type parameters:
> With the above changes, not sure if anything needs to be changed since
> type exprs are now a subset of value exprs.

I'm wrong here because that violates the "type exprs only nest type
exprs" principle. Also, I meant to refer to "type arguments" rather than
"type parameters". Is there any reason why type arguments should accept
value exprs in a value expr context? If not, then this can be resolved
by restricting type arguments to type exprs.

-Yuh-Ruey Chen
-------------- next part --------------
An HTML attachment was scrubbed...

More information about the Es4-discuss mailing list