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 > give > me a use case involving a runtime type check that requires that the > type > 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 respectively). > 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 > for > 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 > resolves > 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 > way, > 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? /be _______________________________________________ Es4-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es4-discuss
