need some clarification on compile-time type vs. run-time type
brendan at mozilla.org
Sun Nov 11 23:04:02 PST 2007
On Nov 11, 2007, at 10:41 PM, Yuh-Ruey Chen wrote:
>> The key difference is that
>> instanceof results can change over time for a given object on the
>> left and plain old function on the right, while 'is' results cannot
>> vary over the lifetimes of the same operands.
> If |is| is a purely runtime check, does this really matter? Can you
> me a use case involving a runtime type check that requires that the
> check always be the same for a pair of operands?
Your poor-man's type parameters example will do. The 'is' operator is
how you write an expression testing subtype, and the : type
annotation colon enforces subtype relation for all writes to the
annotated slot. So 'is' and annotations are closely related (ignore
the hardcoded conversions within AnyString, AnyNumber, and AnyBoolean
> Ok, thanks for the clarification. However, that still doesn't answer
> this question: if the |x| in |type x| has to be a type expr, then how
> did |type x| in the example work? |x| in that case was a value expr
> (evaluating to a meta-object), not a type expr.
Maybe that was just a mistake :-).
>> The tension between is/cast/wrap and is/instanceof is painful,
>> isn't it?
> Indeed. And it's all so subjective too...
See latest mail from me, Lars's Gordian knot slicing. It makes 'is'
DWIM. 'cast' need not accept value expressions since it is useful
only for the type checker (optional strict mode), and for
documentation purposes. 'wrap' should do what 'like' does (require a
type expression, currently).
> As I said before, is there any value in making sure that the value
> of |x
> is y| never changes for a given pair x and y? I can understand the
> importance of that guarantee for type annotations, but since |is| is a
> late type check, I don't see the value.
Even if (as we believe so far) 'is' should not be analyzed by strict
mode, you want the parallel between type annotations and 'is' to hold
up over the lifetime of the slot in the case of a type annotation,
and the operands in the case of 'is'. Well, I do, at any rate. Both
'let x:T' and 'x is T' invoke the subtype relation. And the prototype
relation is not the subtype relation.
> FYI, I'm not really in favor of merging to the two operators. I do
> recognize that there is a fundamental difference between the
> |instanceof| test and the |is| test. But I could also say that
> there is
> a fundamental difference between the |is| test and the |is like| test.
Remember, nothing special goes on with 'is like'. Imagine explicit
parenthese (not allowed because they mean union type, but pretend):
x is T
x is (like T)
We know this must be the case since you could have defined
type T = like U
before the first line (x is T), and the result should be the same as
if you expanded the typename:
x is like U
> On the other hand, unless structural types are mutable, |is| and |is
> like| are similar in that the values of both |is| and |is like| are
> a given pair of operands can never change. And structural types are
> immutable, right?
Right. But don't believe 'is like' is a compound-keyword type
operator -- it's two operators, the right one a unary prefix type op
(type constructor really).
> Yeah, misunderstood you. I can see now that record types are like
> undeclared interfaces.
Not sure if you meant anonymous interfaces, but interfaces can have
only methods, which can be overridden along the inheritance chain in
the nominal type system. Structural types on the other hand describe
records with fields -- not methods, although a field's type could be
a function structural type.
Bottom line: interfaces != structural object types.
> However, as I noted before, the |like| test for
> structural types is still a different beast.
There's a possible generalization of 'like' to accept any type on its
right (conversion is not an issue: http://bugs.ecmascript.org/ticket/
258). Remember, no non-compositional special cases or ad-hoc patches,
if we can avoid 'em.
> A thought: If the |type| operator can accept a value expr that
> to a meta-object and returns that meta-object, then |type| can be
> chained, e.g. |type type type T| is equivalent to |type T|. In this
> a user that's unsure if a particular type expression is ambigious can
> just prefix it with |type| without worries.
But the parser (not optional strict mode, the fundamental grammar)
will reject a non-type expression (if we want it to). This is a case
of load/edit/reload at worst.
But hey, I'm jazzed by Lars's "have our cake and eat it" proposal for
'is'. For instanceof, we could do what you and I seem to be talking
about: extend it to do what 'is' does, with the gravy that its right
operand is always a value expression. So 'instanceof' could be used
to handle all kinds of instantiation, ES3 mutable-prototype function
constructors and ES4 types. Comments?
More information about the Es4-discuss