Re: function hoisting like var
FWIW, I definitely like this proposal more than any convoluted var-scoping block proposal. I just don't see the value of adding var-scoping blocks for the added parser complexity, and problematic return/break/continue. Even if the return/break/continue problem is solved, it shouldn't just be for var-scoping blocks - it should be generalized to first-class Ruby-esque block. So if we ever want to add var-scoping blocks with proper return/break/continue, consider Ruby-esque blocks. Something like: function treePreorder(tree, func) { func(tree.value); if (tree.left) treePreorder(tree.left, func); if (tree.right) treePreorder(tree.right, func); } function treeContains(tree, x) { treePreorder(some_tree, block(val) { if (val == x) return true; }); return false; } Though, I'd imagine implementing this would also be difficult (at the very least, non-trivial), and this example can be easily replaced with one that used exceptions/try/catch anyway. -Yuh-Ruey Igor Bukanov wrote: > 2008/7/28 Ingvar von Schoultz <[EMAIL PROTECTED]>: > > > > {{ }} is just the same as a scoping function used on ES3: > > > >(function() { code })() > > As Lars Hansen has pointed out any proposal for a shorthand for > (function() { code })() has to deal with break/continue/return inside > the code. This is the the reason if anything I would prefer in ES3.1 > just shorthands for function definitions like > > function() expr - equivalent to function () { return expr; }. This is > already in ES4 and is implemented by at least on implementation > (SpiderMonkey). > > or > > function optional_name { code } - equivalent to function > optional_name() { code } - a hypothetical shortcut that would allow to > write a pseudo-blocks like > > function { > }(); > > with clear emphasis that this is a lambda with usual rules for > break/continue/return. > > Regards, Igor > ___ > Es3.x-discuss mailing list > [EMAIL PROTECTED] > https://mail.mozilla.org/listinfo/es3.x-discuss > > ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Namespaces on definitions
I agree. I don't see why there should be multiple syntaxes that are as concise as each other and both have about equal precedent (AS3 vs. E4X). If in some futuer spec, properties can inhabit multiple namespaces, then we can consider the |ns1 ns2 ... var foo| syntax again. -Yuh-Ruey Waldemar Horwat wrote: > My views on this are: > > - There should be only *one* syntax for specifying namespaces in definitions. > It shouldn't be > ns::foo = xyz > in one place (object initializers) and > ns var foo = xyz > someplace else (variable definitions). > > - The historical reason I chose the syntax > ns var foo = xyz > for ES4 was that I allowed the same definition to simultaneously go into > several namespaces: > ns1 ns2 ns3 var foo = xyz > would create ns1::foo, ns2::foo, and ns3::foo, which would be aliases of the > same variable (not three different variables). ES4 doesn't support that any > more, so this reason goes away and the issue can be reconsidered. > > Now that the issue has been brought up, I'm warming up to the syntax > var ns::foo = xyz > everywhere. It's simpler to remember. It doesn't match Java, but if that > were a goal then we should first change our type annotation syntax to that of > C++ and Java. > > Waldemar > ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Controlling DontEnum
Garrett Smith wrote: > The order of the boolean parameters is kind of annoying to have to remember. > > Would it be OK to shorten the method? > > obj.__setProperty__("c"); // undefined value > obj.__setProperty__("c", 2); > obj.__setProperty__("c", undefined, "dontenum", "readonly"); > obj.__setProperty__("c", undefined, "dontdelete"); > Not sure what ES4 policy is on how to pass "flags". Obvious method should be named parameters, but ES3/4 lack that feature. I also don't recall any ES3/4 method that uses bitflags (e.g. Object.READ_ONLY | Object.DONT_DELETE) or any variant of such flags. So that leaves strings (as you have), or an array of strings, both of which are less efficient. Hmm, this gives me an idea - more below. > -- or -- > > obj.__setProperty__("c", undefined). // Reference type. > dontEnum(). > readOnly(). > dontDelete(); > That kind of defeats the purpose of setting all the flags during assignment, since this would allow you do so after assignment. Ok, new suggestion based off previous ones: obj.__setProperty__(prop, value) obj.__setProperty__(prop, value, Object.DONT_ENUM) obj.__setProperty__(prop, value, Object.READ_ONLY, Object.DONT_DELETE) obj.__getPropertyAttribute__(prop, Object.READ_ONLY) // returns true or false BTW, names subject to change (could be just DONT_ENUM, or Object.dontenum, or whatever). -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Peter Hall wrote: > > The latter. It is weird, I agree. But the enumerator can easily be > > customized, so I want the default enumerator be as non-magical as > > possible - and therefore, as simple as possible. In fact, I'm a bit > > bothered that propertyIsEnumerable is a method of Object yet can be > > rendered useless when changing the enumerator - along this line of > > reasoning, one would think that such a specific method shouldn't be a > > method of Object at all, but rather the enumerator itself. > > > > So how would you go about enumerating the properties of an arbitrary > dynamic object, whose properties could be in namespaces? > I thought there was an iterator that would enumerate all properties regardless of enumerability (including those in other namespaces), but apparently not. There should be such an iterator though. > > Yeah, I vaguely remember some discussion concerning multiple namespaces > > per property a long time ago (maybe a year ago). It was rejected > > probably due to complexity. > > Not being able to combine them effectively makes many of the initial > proposal's use-cases useless, because two use-cases may arise > simultaneously when integrating two codebases, and be irreparably > conflicting. > > Peter > What "initial proposal" are you talking about? -Yuh-Ruey ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Brendan Eich wrote: > If we end up making all namespaced properties non-enumerable, then we > may want a property iterator that returns the names of all properties > in a given object. Even if this is not in the standard, it's likely > to be an extension. Or it could be added in the future. > Absolutely. In fact, I thought there was already an iterator that yields all properties regardless of enumerability, just that this iterator would not be the default iterator for objects. If it's not in ES4, it should definitely be there because it's essential for those that want to customize enumerability. > The question of whether ES3+4 mixtures might not want enumerable ES3 > properties to appear to be in a predefined-in-ES4 namespace seems to > me worth considering, at the limit as a future-proofing step. > What do you mean by ES3+4 mixture - how would you tell that one part is ES3 and another part ES4, or how a program is pure ES4? -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Peter Hall wrote: > Yuh-Ruey Chen <[EMAIL PROTECTED]> wrote: > > Which gets me back to the cognitive load issue. Even with a name like > > 'hidden', they may think they may have to do some funky syntax like > > |obj.hidden::other_ns::prop| do hide a prop in another namespace. > > > This was confusing me... How would you define a property to have a > qualified name and be in the dontenum namespace at the same time? Or > are namespaced properties non-enumerable anyway? (That would feel > wrong to me..) > The latter. It is weird, I agree. But the enumerator can easily be customized, so I want the default enumerator be as non-magical as possible - and therefore, as simple as possible. In fact, I'm a bit bothered that propertyIsEnumerable is a method of Object yet can be rendered useless when changing the enumerator - along this line of reasoning, one would think that such a specific method shouldn't be a method of Object at all, but rather the enumerator itself. > ES4 > doesn't currently have a way to express AND/OR namespace combinations. > Yeah, I vaguely remember some discussion concerning multiple namespaces per property a long time ago (maybe a year ago). It was rejected probably due to complexity. -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Brendan Eich wrote: > On Mar 9, 2008, at 3:01 PM, Yuh-Ruey Chen wrote: > > > Brendan Eich wrote: > >> ES3 code can't detect namespaces, so arguably shouldn't care if we > >> were to implement DontEnum using an open namespace. But this could be > >> a problem for mixed ES3 and ES4 scenarios where the ES4 code does > >> introspect via Name objects and is surprised to find "ES3" objects > >> with qualified property names. > >> > > > > I'm talking about how the enumerability (or lack thereof) of > > Object.prototype.* are determined. Or are prototype methods also not > > enumerable by default like fixtures? > > My reply was not meant to be an answer, but a question: should we > drop this dontenum-namespace idea because it will break ES3+ES4 > mixtures where the ES4 code reflects on a property's namespace > qualifier by using a Name object? > > > Does this included ES3-style prototype methods? And would it > > be possible to init a fixture to be enumerable? > > In the sketch I mailed, you didn't see any mention of fixtures -- > IIRC you asked about them in reply. Just to explain what my proposal > was aiming to do: It seems to me that if we have to add a magic bit > back into the skinny is-it-enumerable decision tree, we may as well > keep DontEnum. > > And the RI does print > > it, so I'm not sure what you're talking about. > > The RI is (a) not normative (nothing apart from ES3+fixes is yet), > (b) based on a DontEnum attribute model, not on my proposal. Not sure > why you thought I was talking about it. I was making a new proposal. > Ok, that cleared things up a bit. I didn't realize you were making a proposal and asking questions based off it :) I thought you were mentioning how the RI was implemented today at the moment. Can you elaborate on cases where "ES4 code does introspect via Name objects and is surprised to find "ES3" objects with qualified property names."? I can't think of any. > > BTW, what exactly is a fixture? > > That's a good question, and it seems the answer is not in the wiki. > Trying the trac: > > http://bugs.ecmascript.org/ticket/233 > > which references the overview document. > > In ES3 terms, a fixture is a property with the DontDelete attribute set. > > But there's more to it than that, for reasons expanded on in #233 to > do with namespace lookup and early binding. And there is another case > that Lars pointed out recently to do with dynamic classes, but I'll > avoid trying to summarize it except to say that a fixture is a fixed > property that can't be deleted or shadowed. > Thanks, that's a good summary, though some of the commentary in the ticket was confusing (like lth's example - was x.toString decided to be ambiguous?). > >> Is that the right design? > >> > >> dynamic class C { > >> public var fixture; > >> function C() { this.expando = 42; } > >> } > >> for (var i in new C) > >> intrinsic::print(i); > >> > >> wouldn't you expect to see "expando" printed? Is it printed because > >> the default namespace for expando is the public-default one? I > >> believe it is not, in the current proposal and the RI. Rather, each > >> class or package gets a nonce-named public namespace, different from > >> every other such per-class or per-package public. IIRC package trumps > >> class -- classes within a package share the package's nonce-named > >> public namespace (Jeff, Lars, please correct me if I'm wrong). > >> > > > > I meant non-expando vars and methods defined within the class, > > whatever > > the terminology is used (I see 'fixture' thrown around everywhere), are > > not enumerable. So yes, expando should be printed. > > From your numbered steps above, step 3 must have been reached -- so > expando is in the public-public (null qualifier in Name object > reflection) namespace. Not in the class-C-public namespace. My > question is whether that is the right design choice. > Are they any particular disadvantages that you can think of? Maybe another ES4 designer can chime in here. BTW, a bit off topic: if a class is defined in a namespace, are the properties of that class also defined in that namespace (instead of just public/class-public)? Namespaces aren't clearly specified in the wiki or the overview, the tickets are unorganized, and the RI tends to barf when it comes to them. Ugh, I feel Apple's pain when they complain that they don
Re: ES4 draft: Object
Brendan Eich wrote: > On Mar 8, 2008, at 1:16 PM, Yuh-Ruey Chen wrote: > > But doesn't DontEnum still have to be there for ES3 objects? How else > > would you prevent the enumeration of ES3 builtin methods, e.g. > > Object.prototype.toString()? Or is there some more open namespace > > magic > > that I'm unware of? > > ES3 code can't detect namespaces, so arguably shouldn't care if we > were to implement DontEnum using an open namespace. But this could be > a problem for mixed ES3 and ES4 scenarios where the ES4 code does > introspect via Name objects and is surprised to find "ES3" objects > with qualified property names. > I'm talking about how the enumerability (or lack thereof) of Object.prototype.* are determined. Or are prototype methods also not enumerable by default like fixtures? Let me get this straight. The rules of enumerability are: 1) If a property is a fixture, it's not enumerable. BTW, what exactly is a fixture? Does this included ES3-style prototype methods? And would it be possible to init a fixture to be enumerable? 2) If a property is not in the public namespace, it's not enumerable. 3) Otherwise, it is enumerable. 4) No hidden DontEnum attribute. Are we trying to simplify this to the last three rules using some namespace voodoo to handle the fixture rule? I'm confused. > > Well, I think the only overlap is that public-in-class-context methods > > (or any method really) default to be non-public in terms of > > enumerability > > Is that the right design? > > dynamic class C { > public var fixture; > function C() { this.expando = 42; } > } > for (var i in new C) > intrinsic::print(i); > > wouldn't you expect to see "expando" printed? Is it printed because > the default namespace for expando is the public-default one? I > believe it is not, in the current proposal and the RI. Rather, each > class or package gets a nonce-named public namespace, different from > every other such per-class or per-package public. IIRC package trumps > class -- classes within a package share the package's nonce-named > public namespace (Jeff, Lars, please correct me if I'm wrong). > I meant non-expando vars and methods defined within the class, whatever the terminology is used (I see 'fixture' thrown around everywhere), are not enumerable. So yes, expando should be printed. And the RI does print it, so I'm not sure what you're talking about. Are you saying that each property is defined in a "class-specific public" namespace, and therefore does not get enumerated? I would say that expando properties should be defined in the "global public" namespace, so that they would be enumerated. -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Brendan Eich wrote: > > - Users may think this dontenum namespace is magical and yet another > > thing to keep in mind, when it really just relies on the namespace > > trick > > you mentioned. With the introduction of classes and namespaces, the > > rules of enumerability are already more complex, so this adds to the > > cognitive load slightly. > > Slightly, but it takes away the magic DontEnum attribute, formerly > hogged by the specification and magic predefined objects. > But doesn't DontEnum still have to be there for ES3 objects? How else would you prevent the enumeration of ES3 builtin methods, e.g. Object.prototype.toString()? Or is there some more open namespace magic that I'm unware of? > > BTW, if setPropertyIsEnumerable() is added, > > would it be possible to make fixtures enumerable? Enumerability is > > orthogonal to static analysis (which fixtures are meant to help with), > > so I don't see why not. > > This gets to the heart of the public vs. public-in-context-of-class- > or-package issue. We need to sort this out to find out exactly how > orthogonal enumerability is, as well as decide how flexible it should > be. > Well, I think the only overlap is that public-in-class-context methods (or any method really) default to be non-public in terms of enumerability > > - The name sucks :p > > Indeed. How about 'hidden' or 'nonEnumerable'? > I'd prefer 'hidden', since 'nonEnumerable' implies more strongly that a prop needs to be in that namespace to not be enumerable, when that's not the case. Which gets me back to the cognitive load issue. Even with a name like 'hidden', they may think they may have to do some funky syntax like |obj.hidden::other_ns::prop| do hide a prop in another namespace. While we're on the topic of namespaces, I read in the ES4 overview: "In addition, the names internal, public, protected, and private denote namespace values, but the values depend on the context of the use." As the wiki doesn't talk about this, and the online spec is inaccessible/outdated, can you elaborate on this? I wonder if 'private' could be used somehow for enumerability. -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Brendan Eich wrote: > Suppose we had a predefined, open namespace, say dontenum (surely > not the best name). If you write > > obj = {dontenum::cant_see_me: 33} > > then > > for (i in obj) print(i) > > shows nothing. But > > obj.cant_see_me > > works, because dontenum is always open. No more need for an > orthogonal DontEnum attribute. > > Instead of > > obj.propertyIsEnumerable('i_want_to_hide', false) > > users would just say > > obj.dontenum::i_want_to_hide = ... > Interesting and clever proposal. Some thoughts: - It would become harder to change the enumerability of a property (compared to a enumerability method): |obj.prop=obj.dontenum::prop; delete obj.dontenum::prop;| That said, I'm not sure there are many use cases that involving changing enumerability after the prop's enumerability is initially defined. - If you add setPropertyIsEnumerable(), how would that interact with this? Would it change the namespace as described above, or just toggle the hidden DontEnum attribute? - Users may think this dontenum namespace is magical and yet another thing to keep in mind, when it really just relies on the namespace trick you mentioned. With the introduction of classes and namespaces, the rules of enumerability are already more complex, so this adds to the cognitive load slightly. BTW, if setPropertyIsEnumerable() is added, would it be possible to make fixtures enumerable? Enumerability is orthogonal to static analysis (which fixtures are meant to help with), so I don't see why not. - The name sucks :p > > Object.prototype.iterator::setPropertyIsEnumerable(prop, > > enable). For consistency, you could also have > > Object.prototype.iterator::isPropertyEnumerable(prop) which > > delegates to > > Object.prototype.isPropertyEnumerable(prop). > > Clever relocation of "is" in the predicate names ;-). We're probably > stuck with propertyIsEnumerable. > Honestly, that wasn't intentional - it just came off my fingers naturally :) -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Brendan Eich wrote: > To avoid injecting a public name into Object.prototype, we could put > a new "setPropertyIsEnumerable" (yechh) name in the __ES4__ > namespace. Then there's no breaking change. We do this already, of > course, but not for property attribute fiddling. > Since enumerability only applies to for-in, how about the iterator namespace? Object.prototype.iterator::setPropertyIsEnumerable(prop, enable). For consistency, you could also have Object.prototype.iterator::isPropertyEnumerable(prop) which delegates to Object.prototype.isPropertyEnumerable(prop). > An alternative we've discussed, which Ian also brought up: add a > keyword for declaring DontEnum properties. This dontenum modifier can be used in addition to the method for convenience - it would make class declarations cleaner. But despite that, I think dontenum is inelegant. Its only effect would be on the default enumerator, which is only one iterator, and AFAIK is not special at all. IMO, it isn't worth the bloat. If there was a way to define such modifiers within script, then I think the dontenum modifier would be nice. If such a capability is planned for a future ES edition, then I think dontenum is fine. -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Name
Lars Hansen wrote: Name (a, b=…) *Description* The |Name| class object called as a function creates a new |Name| object by passing its arguments /a/ and /b/ to the |Name| constructor. *Returns* The |Name| class object called as a function returns a |Name| object. *Implementation* static meta function invoke(a, b=undefined): Name new Name(a, b); If a is already a Name, shouldn't Name(a) simply return a? Not sure what the policy on this is, but if you've changed Map to work similarly, then I don't see why not here as well. -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Add call and apply methods to RegExp.prototype
Brendan Eich wrote: > On Dec 21, 2007, at 7:33 AM, StevenLevithan wrote: > > > Yes, its easy to pull off oneself, so I don't care much other way. > > Still, it > > seems pretty weird to me to be able to do ``regex(str)`` but not > > ``regex.call(context, str)``. This is accentuated when typeof returns > > "function" for regexes (though it seems ES4 will change this to > > "object"). > > Hey Steve, Yuh-Ruey (I owe both of you replies to the list, for Steve > agreeing about ES3 capturing paren broken design, Yuh-Ruey on fine > points about instanceof, etc. -- I wanted to drop a note here, > quickly, and catch up next week while I'm off). > I'm glad you still remember it :) > This raises the question: since there is only one argument to exec or > test, so why do you ever need to delegate invocation using apply or > call? The only case that comes to mind is a generic programming use- > case where you might have either a function object or a regexp and > you want to .apply it with an argument array. But again, you could > just invoke foo(arg) given foo denoted either a function or a regexp. > True, the most generic program would not want to hardwire argument > count, so would want .apply. But still, the motivation for call and > apply in RegExp.prototype seems weak. With currying, I find that use case a moot point. For example, we could do: foo(regex.exec.bind()) and foo would still be generic. So really, regex invocation is not needed. Speaking of bind (or whatever it's called), I hope the function is memoized, since it might be used a lot. ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Add call and apply methods to RegExp.prototype
Sounds like a good idea to me. On the other hand, this can already easily be done in ES3. Steven L. wrote: > ES4 proposals include making regexes callable as a function on a > single string argument, which serves as a shorthand for calling the > regex's exec method. To further extend this idea, what about also > including call and apply methods on RegExp.prototype, so that regexes > can more easily be used with functional programming? For e.g., if one > were to model a "where" function after JS 1.6's Array.prototype.filter > like so: > > function where (array, func, context) { > var results = []; > for (var i = 0; i < array.length; i++) { > if (func.call(context, array[i], i, array)) > results.push(array[i]); > } > return results; > } > > ...They could then use, e.g., where(["ab", "ba", "a", "b"], /^a/) to > return all array elements starting with the letter "a" (["ab", "a"]). > > Thoughts? Is this possibly already included in the proposals? (sorry > if I missed it) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: need some clarification on compile-time type vs. run-time type
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 th
Re: Exception handling vs. hasNext()
Garrett Smith wrote: > How is it possible to iterate over the keys in a Map? I'd like to > avoid using try/catch, unless something in the loop body might require > it, and in that case, I'll want to be very clear on what might throw > an exception, how, and why, as well as provide correct handling of > that exception. Is there a way to get a maps keys as an Array? > I think you're misunderstanding how iterators work. You don't need to explicitly use the next() method or catch StopIteration. Please look at how Python does it. There are plenty of examples on the web; here's one: for x in range(10): print(x) which is practically equivalent in ES3 to: for (let x = 0; x < 10; ++x) print(x); The Python for-in is equivalent in ES4 (assuming range is defined equivalently) to: for (let x in range(10)) print(x); This practically translates to: let $iter = range(10); // $iter not visible to rest of code try { for (;;) { let x = $iter.next(); print(x); } } catch (e: StopException) {} As you can see, the for-in loop syntax completely hides the next() and StopIteration. It's definitely not as cumbersome as you think - in fact, it's even easier to use than hasNext()/next()-style iterators. To answer your specific question, Map should have a getKeys() method (according to the wiki) that returns an iterator iterating over the keys of the map: for (let k in map.getKeys()) print(k); FYI, the original ES3 for-in is actual a special case of the ES4 for-in. When you do |for (let p in obj)|, it's actually iterating over obj's intrinsic iterator (obj.iterator::get() according to the wiki), which enumerates obj's properties, just like what it does in ES3. -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: need some clarification on compile-time type vs. run-time type
Yuh-Ruey Chen wrote: > If the main problem is that value exprs and type exprs are incompatible, > then why not make them compatible? Make it so that the only difference > between the two is that type-expr-like value exprs evaluate to > meta-objects and actual type exprs require fixed type properties. With > these as the only two differences and with no exceptions, I hope it will > be as intuitive as possible. The additional benefits is that type exprs > can be used much more freely since they will be a subset of value exprs. > Since the syntax of value exprs is fixed (due to compatibility > constraints), the only way to do this is to adjust the syntax of type > exprs. And this is where I'll violate the syntax brevity goal, which may > not be such a bad thing since it the intent of the syntax is now more > clear. Now to get into details: > > 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). Also, the elimination of the separation between type exprs and value exprs in favor of focusing on fixed type properties vs. non-fixed properties should be vaguely familiar with C++ programmers. If you consider fixed type properties in type exprs as a form of C++ "const", then it's similar in that you have to make sure everything that everything that is const, only contains const exprs, and ultimately const identifiers. Actually, a more proper analogous example would be C++ templates, which work on the equivalent of ES4 fixed types (and const values). This fixed vs. non-fixed distinction is the only thing users need to be aware of - otherwise, they can mix and match type and value exprs freely. That's why I argue that this is easier to grasp (or at least more familiar) than the current type expr vs. value expr distinction. -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Bringing up the issue of numerical constraints again
Is it not possible to emulate this already with classes? I think you can use the implicitly-called construct method, e.g. class myint { private var i: int; function myint(x: int) { this.i = int; } meta static function invoke(x: int) { if (x > SOME_MAX_VALUE || x < SOME_MIN_VALUE) throw some_error; return new myint(x); } } Or something like that. Above code is probably wrong. I'm not sure exactly when and how invoke is called or even what the implicit type conversion customization protocol is. However, if it isn't possible to create a class to emulate such constraints, maybe we ought to do something about it... -Yuh-Ruey Chen liorean wrote: > Hello! > > Since we now have a namespace for uint specific math operations, and > discussion in another thread about using pragmas for throwing if > assigning to ReadOnly properties... Is it possible we could have a > look at the idea of adding constrained primitive types or adding a > pragma changing the mechanism for, or adding a separate set of > operations, constraining number types by the simple rule of (input > > output_type.MAX_VALUE) and (input < output_type.MIN_VALUE) throwing an > out-of-bounds error. > > I'm a little concerned that a type of uint allows assigning negatives > with a silent round-the-corner conversion and allows values of NaN and > Infinity. (I imagine for example the DOM interfaces that have uint > constraints really would like these to throw an out-of-bounds > exception or similar.) > > Also, the RI gives an Overflow exception for values 2^32 or greater, > which I'm not sure whether it's the intended behaviour or a result of > the underlying implementation that is in fact intended to fail > silently like the other cases. > > >> function fn(input:uint):uint input; > >> fn(0x7fff); > 2147483647 > >> fn(-0x8000); > 2147483648 > >> fn(Infinity); > 0 > >> fn(NaN); > 0 > >> fn(0x1); > unhandled exception: Overflow > > >> function fn(input:int):int input; > >> fn(0x7fff) > 2147483647 > >> fn(0x8000) > -2147483648 > >> fn(-0x8000) > -2147483648 > >> fn(NaN) > 0 > >> fn(Infinity) > 0 > >> fn(0x1) > unhandled exception: Overflow > ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: need some clarification on compile-time type vs. run-time type
pe 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). 1) structural record and array types: Require prefixing with |type|. e.g. |type {p: int}|. 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. 3) function types: Require prefixing with |type|, e.g. |type function(a: int): void|. 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. Furthermore, now that type exprs and value exprs are unified, |is| can now accept value exprs. For type annotations, type declarations, and every other type operator besides |is| and |instanceof| (and |new|), if any identifier would resolve to a non-fixed type property, then throw a syntax error. As for future-proofing, we just have to make sure that new type exprs are unambiguous and prefix the new syntax with |type| as necessary. With this I should meet all goals except the brevity one, and even that goal isn't violated very much. So what does this all mean? I love examples, so I'll be liberal with them: Given: type T1 = int type T2 = double V1 = int V2 = double // valid (note how V1 and V2 are freely used): x is int x is type {p: int} x is like int x is like type {p: int} x is (T1 | T2) x is V1 x is (V1 | T2) x is {p: V2} x is (like V1 | type {p: V2} | string) x is () x is (T1) x is (V1) x is [like V2] x is type function(a: T1, b: type {p: V1}): V2 // invalid (|type| is no longer an operator): x is type int x is type T1 x is type V1 // although "|" has low precedence, that precedence is higher than statements and type annotations type T3 = T1 | T2 V3 = T1 | V2 var x: T1 | T2 function foo(a: T1 | T2) // invalid (|type| prefix is required) type T5 = {p: int} type T5 = [T1] type T5 = function(): void function foo(a: {p: int}) // |instanceof| shares same syntax with |is| now: x instanceof int x instanceof like int x instanceof (like T1 | type {p: V2}) // but still works with constructors (even if meaningless) x instanceof function(){} // valid type annotations: var x: T1 var x: type [T1] var x: like type {p: T2} var x: T1 | T2 function foo(a: T1, b: T2) // invalid type annotations (if they contain any non-fixed type property identifiers) var x: V1 var x: T1 | T2 | V1 var x: T1 | (type {p: T2, q: type [like V1]} function foo(a: T1, b: V2) |new| remains the same. All the other type operators have the same restrictions as type annotations (allow only fixed type properties), so don't need examples for them. Thoughts? I hope I haven't missed anything. -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Exception handling vs. hasNext()
More advantages to StopIteration: 1) There are some iterations in which calculating whether the next iteration exists is non-trivial, such as iterating on trees. 2) While one could work around non-trivial hasNext() calculations by "pre-advancing" the iterator, i.e. if an iterator has returned the i-th item, it has already calculated the (i+1)-th item, making hasNext() simply check if the (i+1)-th item exists, such an approach is not only less efficient, but won't work if the iterator makes side effects. 3) Repeated hasNext() checks can be slower than throwing and catching a StopIteration, especially if the compiler is optimized to expect that StopIteration from an iterator. 4) Iterator-generators hide the messy business of StopIteration: // range is an iterator-generator (note the yield statement) function range(len) { for (let i = 0; i < len; ++i) yield i; } for (let x in range(10)) print(x); No mention of StopIteration - or even next() - anywhere in that code yet |range(10)| is clearly an iterator. In case you were wondering, ES4's iteration protocol is heavily inspired from Python, and I think Python has handled this iteration business very well. -Yuh-Ruey Chen Erik Arvidsson wrote: > One benefit of StopIteration is that code inside map/some/every etc > can just throw a StopIteration to stop the iteration. The same thing > is harder to keep clean with a hasNext/next pattern. > ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: generic function with structural types questions
By "fixed", do you mean an RI bug or a spec issue? If it's just an RI bug, can you tell me what those exprs are supposed to evaluate to? -Yuh-Ruey Chen Lars T Hansen wrote: > At present, generic functions do not discriminate on structural types. > This probably needs to be fixed, but I've not looked into it. > > --lars > > On 11/12/07, Yuh-Ruey Chen <[EMAIL PROTECTED]> wrote: > > Given the following definitions: > > > > class C {var p: int}; > > type S1 = {p: int}; > > type S2 = {p: int, p2: double}; > > generic function foo(x); > > generic function foo(x: *) 0 > > generic function foo(x: C) 1 > > generic function foo(x: S1) 2 > > generic function foo(x: S2) 3 > > generic function foo(x: like S1) 4 > > generic function foo(x: like S2) 5 > > var o1: C = new C(); > > var o2: S1 = {p: 10}; > > var o3: S2 = {p: 10, p2: 3.14}; > > var o4 = {p: 10}; > > var o5 = {p: 10, p2: 3.14}; > > var o6 = {p: 10, p2: 3.14, p3: "hi"}; > > > > What do the following exprs evaluate to? > > foo(o1); > > foo(o2); > > foo(o3); > > foo(o4); > > foo(o5); > > foo(o6); > > > > Also, I know that S1 <: Object, but is S2 <: S1? I've looked at > > http://wiki.ecmascript.org/doku.php?id=clarification:type_system and > > it's not clear to me. Is it still true that C <: S1? > > > > -Yuh-Ruey Chen > > ___ > > Es4-discuss mailing list > > Es4-discuss@mozilla.org > > https://mail.mozilla.org/listinfo/es4-discuss > > > > ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: need some clarification on compile-time type vs. run-time type
Brendan Eich wrote: > > 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. > I agree. > > 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. > I don't see how that's workable. I mean, technically it is, since |is| is a runtime check. But it creates another "incompatibility" between type annotations and |is|, and you seem pretty adamant to keep the two as coherent as possible. Just consider: T = cond? int : double; x is {p: T}; // ok var y : like {p: T}; // early type error > > 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. > So I take that |x instanceof {p: int}| won't work, and we'd have to use |T = type {p: int}; x instanceof T| instead? >From your other email: > Er, I meant (c), if you remove type annotations from the function > param and result. In ES3 today, you can write > > js> ({}) instanceof function (){} > false > > It's silly, of course, because the function expression is captured by > the right operand and could not have been constructed via operator > new to get the left operand. But it's valid ES3 syntax, so we can't > switch instanceof's right operand to favor a function structural type. I truly doubt there is any code out there with (d). It's a backwards incompatibility I'd be willing to break. If there is code out there with this, well, the new syntax error should tell them that they're doing something really stupid. > > 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. > Plenty of discussion going on in ticket 300 concerning this. Ugh, this semi-merging of value and type exprs is getting awkward. We're ending up with just as many gotchas as we had before at this rate. Alright, overview time again. Our current goals are: 1) Make |is| less restrictive and allow it accept (some) value exprs. 2) Keep |is| and type annotations coherent. 3) Keep |is| and |instanceof| (somewhat) coherent. 4) Keep all the type operators coherent (to a certain extent). 5) Try not to introduce too many exceptions to the rule a.k.a. gotchas. Whatever we do to advance one goal, another goal becomes more compromised. Maybe we can place priorities on these goals? If we can abandon one or two of these in favor of the other goals, this job would be much simpler. Need to think on this some more... -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Is ES3 good enough? Was incrementally strengthening ES3 paradigms considered?
c to those who are "defending the > Shire" (if you get my reference) by objecting to ES4's bigness. And > there's a real risk that ES4, even though backward compatible, will > be twisted via bad programming "culture wars" that in effect stamp > out the old ways. Should it come to this, I'll be on the other side > of those wars, with the Hobbits and Doug Crockford (if they'll have > me. :-/). > Heh, with the super-multi-paradigm-ness of ES4, those programming cultures wars are bound to happen. Witness the creation of hundreds of "ES4/JS2 style" articles that all disagree with each other :) I am glad to hear that the people behind ES4 are very cognizant of the "bigness" of the language. My hope is that a future ES5 will revamp the language into a smaller core syntax with much of the ES4 extensions (and some ES3) somehow morphed into syntactic sugar - or even better, user-defined syntactic sugar (could take bootstrapping to a whole new level).// > But I don't think the old ways suffice. I've seen too many users > waste hours and days struggling to enforce latent types with ad-hoc > checks, or no checks at all. I've seen lots of security exploits that > take advantage of mutability and extensibility at the heart of JS1. > And I hope we all can see the onslaught of alternative but near-the- > web (typically browser plugin at first, but then embrace, extend, > extinguish soon follow) runtimes that boast bigger, stronger, and > more scaleable (in practice) programming languages. > > Against these, JS1 or a small "cleanup" of it cannot compete, not > only in my opinion, but in the successful marketing judgments of > several mighty companies (including Microsoft and Yahoo!). And to be > fair to those big companies, many (most?) programmers do deserve > better programming-in-the-large and integrity support, including an > expressive type system with optional static checking. If they have to > switch to C# or ActionScript to get it, many programmers will. JSLint > is not enough. > Yeah, the proprietary vs. open language war again. > > Nonetheless, I see that languages based on the old ES4 draft > > (2002?) that have been successful, namely ActionScript. I'm not > > very familiar with it, but the overall feeling I get from ppl > > developing in AS is positive. I also want to get my hands dirty > > testing out classes in ES4, but sadly the RI is too buggy at the > > moment. > > Please mail me about these RI bugs, or file them yourself at http:// > bugs.ecmascript.org/ -- I have access to the monotone repository, and > I see classes and interfaces doing more right than wrong, but we need > to see your testcases. Thanks. > Oops, didn't mean to say that the class system in the RI was buggy. I've tried some basic classes and it's working so far, but I haven't gotten knee-deep into it yet. It's just that the best way for me to learn all the ins and outs of a language, learning all its merits and whatnot, is to use for some sort of small experimental project. To give you an example, I didn't really appreciate all the little features Python had until I tried make a game mod with the language. Currently, the RI just doesn't seem stable enough for that. > > Basically, what I'm saying is, I'm willing to give the Java-esque > > type system a chance. > > Java-esque is not fair, even if you are talking only about the > nominal types. Unbounded type parameters are not classically "Java- > esque", and Java generics go beyond what we are doing in some ways > (variance annotations) while still being much less (erased, static > only) in others. ES4 is a dynamic language. Java-esque doesn't begin > to do it justice. > Oh come on :) I was referring to the syntax of the class system, which is undoubtedly Java-esque. Lot of Java haters in the functional (no 1st-class functions!) and scripting (too verbose!) programming crowd. Pretty much everyone's first impression of the class system in ES4 is that Java is being merged into the language. Kinda like how everyone thinks that Java inherited its type system from C++ instead of Modula-3. -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
generic function with structural types questions
Given the following definitions: class C {var p: int}; type S1 = {p: int}; type S2 = {p: int, p2: double}; generic function foo(x); generic function foo(x: *) 0 generic function foo(x: C) 1 generic function foo(x: S1) 2 generic function foo(x: S2) 3 generic function foo(x: like S1) 4 generic function foo(x: like S2) 5 var o1: C = new C(); var o2: S1 = {p: 10}; var o3: S2 = {p: 10, p2: 3.14}; var o4 = {p: 10}; var o5 = {p: 10, p2: 3.14}; var o6 = {p: 10, p2: 3.14, p3: "hi"}; What do the following exprs evaluate to? foo(o1); foo(o2); foo(o3); foo(o4); foo(o5); foo(o6); Also, I know that S1 <: Object, but is S2 <: S1? I've looked at http://wiki.ecmascript.org/doku.php?id=clarification:type_system and it's not clear to me. Is it still true that C <: S1? -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: need some clarification on compile-time type vs. run-time type
Brendan Eich wrote: > On Nov 11, 2007, at 3:09 PM, Yuh-Ruey Chen wrote: > > > Sorry, I'm still not getting it. The upgraded |instanceof| will behave > > exactly the same for the inputs non-upgraded |instanceof| works on. > > There are new guarantees, but they in no way affect the original ones. > > They're stronger than the original ones, and different in kind too. > Seems like apples and oranges mixed under one operator. Not obviously > necessary given 'is', but here's a thought: instanceof does its > prototype chain walk on the left operand, looking for an object equal > to the value of the right operand's 'prototype' property, iff the > right operand has [[HasInstance]] as function objects do in ES3. > Otherwise it does a dynamic form of 'is', and for syntactic > disambiguation, you may have to use unary 'type' on the right operand. > Yes, the upgraded |instanceof| would have to perform two different types of checks. But while the value of |instanceof| can change for function operands, its value cannot change for type operands, just like |is|. The two different type checks are distinct, and the new |is|-like type check in no way affects the former prototype-chain type check, considering that the only overlap between the two is type checking against classes and the two type checks always agree on classes. > > There's no way to change the prototype chain of an object instantiated > > from a class, right? |obj instanceof klass| is practically > > equivalent to > > |obj is klass|. Am I missing something? > > No, classes are not really the issue. 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? > > 2) |is| expects either a type expr or a meta-object, but in the latter > > case, that meta-object must be from a |type| expr. This is a weird > > restriction. Furthermore, I though the |x| in |type x| had to be a > > type > > expr, yet in this case, |x| is a value expr (evaluating to the > > meta-object). Again, very confusing. > > Agreed, and not what anyone wanted. > 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. > > Namely, I can imagine > > a user coming from an ES3 background to instantly see the > > usefulness of > > structural types, yet not care at all about classes, type > > parameters, or > > early type checking. > > Possibly, although structural types either are useful for 'is like' > spot-checks (shape tests), or you end up defining names for them, and > using those names to type objects, arrays, etc. created by > initialisers, so as to get fixed property guarantees. > > Classes come into the picture with 'wrap'. If you are upgrading an > existing API with structural type annotations, but you can't afford > to change all the callers to pass fixture-laden objects (this is > highly likely; and it shouldn't be necessary to change all the > callers of the API anyway), just structural type annotations will > result in type errors for all calls that pass plain old dynamic > objects and arrays. The API upgrader then has a choice: use 'like' > for spot checks, or use 'wrap' for complete coverage (in case the API > client mutates something behind the API implementations back). > > GIven wrap, which creates some built-in nominal proxy type that does > (efficient, we hope, not exponentially complex) checks on all reads > and writes, you get type safety. But it can cost, even if optimized. > As your API evolves and new users come along, if they can use ES4, > you could provide nominal types for their use. > > And even if you never expose nominal types in your API, the API's > factory methods could return nominal types matching the structural > type constraints in the API parameter and result annotations. > > Just pointing out that even without early type checking, there are > use-cases for programmable nominal types. > > Type parameters are used by the iteration protocol (not yet > implemented in the RI, but it's close). See > > http://wiki.ecmascript.org/doku.php? &
Re: ES3 quasi incompatibilities
Garrett Smith wrote: > JavaScript does not provide basic functionality for unique collections. > It's trivial to implement an efficient Set class even in ES3 (with certain restrictions on the "type" of the key) - just use objects which are pretty much specialized hash tables (maps from string to values, keys collides with prototype keys). For ES4, we have maps which are hash tables as bareboned as you'll get in the language. I'm not sure why you have all those |!Map.containsKey(lisx[i])| checks in your Map example, since they're totally unnecessary. A SortedSet is a bit trickier, because that would require some sort of binary search tree to be efficient. But it can be done. ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: need some clarification on compile-time type vs. run-time type
operand > which must be a type expression. Get used to it, poindexter! ;-) But > really, it's a bit harsh and anti-JS to say this, for 'is' at any > rate. Possibly the verb is too short and overloaded. More work > needed, I think. > > /be > Hmm, I can see why it kind of makes sense for |is|, |cast|, and |wrap| all to require type exprs, considering they are all type operators. But since |is| is a purely runtime check (pending Graydon's reply), it makes no sense for it to not accept value exprs. So far I see a couple solutions: 1) Let |is| work on value exprs, but leave |instanceof| alone. Then the difference between the two resolves to whether the operand has a prototype chain. That is, the only inputs that both will work on are classes. It's still a gotcha, but a minor one. 2) Unify |is| and |instanceof| into a single |instanceof| operator. I'm still not sure what you mean by guarantees, so at the moment I don't see an issue other than |is| currently requiring a type expr. I also just learned from your post that AS3 already has an |is| operator that works similarly, so that may be another barrier to this solution. |instanceof| composed with |like| also sounds awkward, e.g. |instanceof like type {a: int}|, unless it's the other way around, e.g. |instanceof type like {a: int}|. 3) Let |is| work on value exprs, and upgrade |instanceof| to work on everything |is| works on. Again, not sure what you mean be guarantees. This solution doesn't require the removal of |is| and so is more compatible with AS3. On the other hand, the fewer keywords, the better. 4) As you say (I think), |is| may be too overloaded. That it works both classes/interfaces and structural types even though the two are very distinct tests is a cause for concern. Yet it is convenient to group them into one operator. In addition to all that, if |is| works on value exprs, there's still the confusion I've previously pointed out: // |b| is a class, |a| is instance of |b| a is type b a is b Maybe we can just explain to the user that |type| is only required for structural types to avoid syntactical ambiguity (in the same vein as block {} vs. object literal {})? -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: need some clarification on compile-time type vs. run-time type
Brendan Eich wrote: > I'm going to summon Graydon and stand back now. > > /be > Right, I'll wait to reply in full until then. I just want to point out that the spec namespace isn't public. http://wiki.ecmascript.org/doku.php?id=spec:spec gives me a "permission denied" page. ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: need some clarification on compile-time type vs. run-time type
Brendan Eich wrote: > On Nov 9, 2007, at 11:24 PM, Yuh-Ruey Chen wrote: > > Ah, so expressions can be annotated with types? > > Array and object initialisers can be annotated with array and object > ("record") structural types to make the expressed object have fixed > properties named by the type, instead of just being a plain old Array > or Object instance that has ad-hoc ("expando") properties given by > the initialiser, where the properties could be deleted in the very > next statement. > I see. I wonder if this can somehow be extended so that it works on non-structural types as well. For example, to initialize a Map, you could use {a: 0, b: 1, c: 2} : Map, instead of Map({a:0, b:1, c:2}). Perhaps it would map onto the |meta static function invoke| method. The downside of this syntax sugar though, is that it hides the cost of the creation of the object literal, fooling the user into thinking that the Map is directly initialized from the literal. > > I acknowledged that |is| is different from |instanceof| but I was > > using > > |instanceof| because it is similar to |is| yet works on value exprs. A > > more proper example would be a combination of |instanceof| and all the > > other checks that |is| allows via reflection. > > Right. You can see from: > > http://wiki.ecmascript.org/doku.php? > id=proposals:syntax_for_type_expressions > > and Graydon's reply that we originally had 'is' take a value > expression right operand, and you had to use 'type E' (the unary type > operator mentioned at the bottom of the above-linked page) to force E > to be treated as a type expression. We've moved away from that to get > experience with the alternative design, where 'is' takes a type > expression on the right, in order to get earlier and more certain > type checking. But this is all subject to change based on feedback -- > such as yours ;-). > I like this revised syntax: |a is type b| is much clearer than |a is b|, which a newbie can mistake for object equality, especially if he comes from a Python background. On purely aesthetic grounds though (ignoring the type vs. value expr distinction), I think |isa| would be even better, but on the other hand, |isa like| sounds like something Mario would say. Can you elaborate on the "earlier and more certain type checking"? I thought you said for |is| checks (along with |instanceof| checks) there can be no early type errors, so that leaves |is| to be a purely runtime check. Anyway, we still have a similar confusion to what we had with |instanceof|, except this time it's all in |is|: // assume |b| is a class and |a| is an instance of it a is type b a is b Since both work, this can fool the user into thinking that the |type| operator is optional. Furthermore, the latter can still lead to newbie confusion (thinking that the expr is equivalent to |a == b|). So I'm not sure there is a net win. > > Again, I did not mean to use the strict definition of |instanceof|; I > > meant some abstract operator (which |instanceof| could be > > "upgraded" to) > > that does the same thing as |is| except that it works on value exprs. > > It's not clear (to me at any rate) that you can upgrade instanceof in > a backward-compatible fashion, given mutable prototype properties of > functions. > > For the built-ins (which become classes, not constructor functions), > you could, and that's what we've done. > > For user-defined functions that instanceof takes as right operands, > there's no need to upgrade beyond how things work as in ES3. But the > guarantees with classes are gone: if one changes F.prototype after x > = new F, (x instanceof F) could change from true to false. > Well, I was just suggesting adding additional functionality to |instanceof|, not changing the original behavior of it, so I'm not sure where the compatibility issue is coming into play. > > If |instanceof| works for classes, then I propose that |instanceof| > > also > > work for interfaces for the sake of completeness. Getting this to work > > is a bit trickier than for classes, since a class can implement > > multiple > > interfaces or a parent class and multiple interfaces, but it can still > > work. This change is perfectly backwards compatible, considering that > > interfaces aren't even in ES3. > > It would involve some algorithm other than the prototype chain walk > from x, looking for an object === to y.prototype, for (x instanceof > y), since interfaces do not have prototypes. > > But since (x is I) and (x is J) work fine for x = new C where class C > implements I, J {...}, perhaps for interface
Re: need some clarification on compile-time type vs. run-time type
Brendan Eich wrote: > On Nov 9, 2007, at 5:29 PM, Yuh-Ruey Chen wrote: > > > The confusion I'm getting is that there seems to be many ways to check > > or differentiate between types. For example, consider the following > > ES3 > > function: > > > > function foo(x, t) { > > if (!(x instanceof t)) > > throw some_type_error; > > print(x); > > } > > > > If t were a fixed type property, then foo could be redefined as: > > > > function foo.(x) { > > if (!(x is t)) > >throw some_type_error; > > print(x); > > } > > Here t is the name of a type parameter to foo, so it is by definition > fixed -- it doesn't matter how you instantiate foo. for some T -- > but there again, in the foo. expression, you need a fixed type > term T. > That's what I meant. If t could never be non-fixed, i.e. it's a type alias, class name, or other type expr, then type parameters could be used. But if, for example, t is a constructor or is otherwise computed at runtime, it couldn't be used as a type argument. > > Or maybe the following is possible (it's currently disallowed in > > the RI): > > > > function foo.(x: t) { > > print(x); > > } > > I'll let Graydon reply in full, and give an update -- I heard he > nearly has type params working. > > > Which one is preferred in ES4? The ES3 version is more flexible in a > > way, since it treats types as first-class values, > > A constructor function is not a type in ES1-3, it's a function > object, which if user-defined has a completely writable prototype > property that instanceof checks. So it is not bad (or good), but I'm > here to say: it's not about types in the ES4 sense. > > Indeed user-defined constructor functions all make Object instances, > by definition, although you could strengthen them to make structural > subtypes of Object in ES4: > > function MyConstructor(a, b) { > return {a: a, b: b} : {a: int, b: string}; > } > Ah, so expressions can be annotated with types? Didn't see that on the wiki and it's not implemented in the RI yet. > > but the last version > > is the most efficient. Users will have to deal with this choice, > > but it > > requires a decent understanding of the type system to make a good > > choice. > > Users can buy by the yard. The old ways work for the dynamic > constructor/prototype world everyone knows. > > Above you have made three different things. The instanceof check is > not the same as the |is| check. The type paramter example is yet > again different -- it's just printing x assuming x is compatible with > t -- that is, that there's no type error on attempt to call foo., > e.g. foo.(new RegExp). > I acknowledged that |is| is different from |instanceof| but I was using |instanceof| because it is similar to |is| yet works on value exprs. A more proper example would be a combination of |instanceof| and all the other checks that |is| allows via reflection. What's the rationale behind not throwing a type error when calling foo.(new RegExp)? I'm looking at the type_parameters page in the wiki and I'm not seeing anything... It's odd that this would not throw an exception while the following would: function bar(x: int) { print(x); } bar("hi"); > > And it doesn't end there. I haven't even addressed the |is like| > > compound operator, > > It's not a compound operator: 'like' is a type constructor or type > unary operator if you prefer: like T is a type, you can use it > freely. Thus because (x is T) can be tested, and T can be defined as > like U, you can write (x is like U). Make sense? > Yes indeed, thanks. > > of which there is no counterpart in |instanceof| > > since structural types apparently can't be stored as non-fixed type > > properties (|type x={a:int};y=x;| doesn't work in the RI). > > Type are types, not functions; the instanceof right operand is a > *function* per ES1-3 and backward compatibility. > Again, I did not mean to use the strict definition of |instanceof|; I meant some abstract operator (which |instanceof| could be "upgraded" to) that does the same thing as |is| except that it works on value exprs. The line between types and constructors is somewhat blurred by allowing |instanceof| to work on class objects, which I would hardly consider constructors, if not for the fact that they have an intrinsic::construct method. Allowing |instanceof| to work on classes can trick people into thinking that |instanceof| can work on type exprs. Yet at the sa
Re: need some clarification on compile-time type vs. run-time type
Graydon Hoare wrote: > Yuh-Ruey Chen wrote: > > I've been experimenting with the ES4 RI lately. I've discovered that the > > following doesn't work: > > > > x = int; > > 10 is x;// error > > 10 to x; // error > > 10 cast x; // error > > var y: x; // error > > > > Of course, if I had used |type x = int|, it would work. Is this because > > x is not a compile-time type? > > Roughly. Some refinements to terminology: there are no "compile-time > types" or "run-time types". There are types (and interfaces, and > classes). They get bound to property names. Some of those properties are > fixed, some are not. Some fixed properties are additionally constrained > to hold types, classes or interfaces. Some are not. > > Your example fails because x is not a fixed type-property. Properties > introduced by 'type', 'class' or 'interface' are. > > Type names in type expressions only consult fixed type-properties, > because we want evaluation of type expressions to be as predictable as > possible. There are only ever 2 results to evaluating any type expression: > >#1 full evaluation to a specific "ground" type term >#2 suspended partial evaluation due to incomplete information > > The flow of program control may affect which of these two results we > get, and it can provide new information to restart a suspended > evaluation -- by loading new code containing type definitions using > 'eval', for example -- but it *cannot* invalidate a result of an > evaluation. Types never need to be "re-evaluated" to reflect "mutation" > in their environment. The evaluation of type expressions can (and > should) memoize types. > Ah, so that's why I couldn't delete types. I ended up having to restart the RI once the environment got cluttered with all these test types that I defined. I need to get used to declaring them in scopes... Speaking of which, there's a little bug in the RI: if you try to constrain a property to specific type e.g. |var x: t| (is that the proper terminology?) where t is undefined, then the interpreter correctly reports an error, albeit one that didn't make sense until you explained the "ground" type terminology. However, x remains constrained to this undefined t, so attempts to redeclare x always result in an error (even when trying to reconstrain it to the undefined t again), e.g. |var x: int| results in an "incompatible redefinition of fixture name" error. This bug probably doesn't matter in production, where such errors are supposed to be fatal (I think), but in a REPL interpreter it gets annoying. > I find it a bit odd that |10 is x| didn't > > work while |10 instanceof x| does work, considering that |is| is touted > > as the successor to the |instanceof| operator. Or is |instanceof| the > > run-time counterpart to |is|? Then should |instanceof| work on > > everything that |is| can work on? > > instanceof consults the prototype chain. It happens to be the case that > for classes, the prototype chains are arranged to follow the class > inheritance hierarchy. But there are a variety of differences; for > example, "x instanceof z" may return false in cases where "x is z" > returns true (if z is an interface, say). > Then how would we do a check against an interface bound in a non-fixed property? Is there an expression that does the same thing as |is| except for non-fixed type properties? The confusion I'm getting is that there seems to be many ways to check or differentiate between types. For example, consider the following ES3 function: function foo(x, t) { if (!(x instanceof t)) throw some_type_error; print(x); } If t were a fixed type property, then foo could be redefined as: function foo.(x) { if (!(x is t)) throw some_type_error; print(x); } Or maybe the following is possible (it's currently disallowed in the RI): function foo.(x: t) { print(x); } Which one is preferred in ES4? The ES3 version is more flexible in a way, since it treats types as first-class values, but the last version is the most efficient. Users will have to deal with this choice, but it requires a decent understanding of the type system to make a good choice. And it doesn't end there. I haven't even addressed the |is like| compound operator, of which there is no counterpart in |instanceof| since structural types apparently can't be stored as non-fixed type properties (|type x={a:int};y=x;| doesn't work in the RI). > > These distinctions between compile-time types and these run-time types > > (e.g. x in the above example) are subtle and confusing. I fi
need some clarification on compile-time type vs. run-time type
I've been experimenting with the ES4 RI lately. I've discovered that the following doesn't work: x = int; 10 is x;// error 10 to x; // error 10 cast x; // error var y: x; // error Of course, if I had used |type x = int|, it would work. Is this because x is not a compile-time type? I find it a bit odd that |10 is x| didn't work while |10 instanceof x| does work, considering that |is| is touted as the successor to the |instanceof| operator. Or is |instanceof| the run-time counterpart to |is|? Then should |instanceof| work on everything that |is| can work on? These distinctions between compile-time types and these run-time types (e.g. x in the above example) are subtle and confusing. I figure that all these distinctions will trip many ES4 newcomers coming from an ES3 background. BTW, it doesn't seem like the "like" and "wrap" operators are implemented in the RI yet, so I couldn't really test out structural types. -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Syntax for union types
Yuh-Ruey Chen wrote: > By "generic functions ought to be available on instances", do you mean > non-global generic methods? TBH, I consider generic functions a bit of > an odd fuck in ES4, because of its many restrictions compared to normal > functions (see the "non-features, future directions, etc." section on > the generic functions proposal). > > -Yuh-Ruey Chen > odd duck *sigh* ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Syntax for union types
Lars Hansen wrote: > > Not only is (int | string) more intuitive than (int, string), > > the (int, string) syntax can be reserved for another yet-unknown > purpose. > > Intuition tends to be personal, and the other argument can be turned on > its head (why wouldn't I want to use "int | string" for something else > in the future?). Since "|" is bitwise or, "||" would have been better, > but that has yet other connotations. > Well, I didn't draw that intuitiveness primarily from ES3 operators. It comes from regexes (which are already in the langauge) and common grammar notation (which are well-known to CS majors), which all tend to use "|" as the "or" operator. > > Along the same lines, I find the syntax for constraining list > > types to be unintuitive. [int] is very different from [int, > > string], and [int, string] is very different from (int, > > string). Perhaps that (int, string) can describe the tuple > > type. And [int | string] could be syntactic sugar for [(int | > > string)]. The usage of "|" improves readability in that > > there's no way to confuse a union type with a tuple type. > > This has been discussed at considerable length, and we've concluded that > the current solution represents a workable compromise. > A compromise between what? I'm not aware of any existing implementation (besides the RI) that uses union types. I'm also unaware of any published discussion concerning the syntax of union types (didn't find any in the wiki). > (More interesting open questions about the language are whether generic > functions ought to be available on instances or discriminating on > structural types, or whether packages ought to be sealable for security, > or whether ES4 precludes the use of current ES3 AOP patterns and how > that might be solved. Among other things.) > > --lars > By "generic functions ought to be available on instances", do you mean non-global generic methods? TBH, I consider generic functions a bit of an odd fuck in ES4, because of its many restrictions compared to normal functions (see the "non-features, future directions, etc." section on the generic functions proposal). -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Syntax for union types
Is there any reason why this proposal isn't being considered? Not only is (int | string) more intuitive than (int, string), the (int, string) syntax can be reserved for another yet-unknown purpose. Along the same lines, I find the syntax for constraining list types to be unintuitive. [int] is very different from [int, string], and [int, string] is very different from (int, string). Perhaps that (int, string) can describe the tuple type. And [int | string] could be syntactic sugar for [(int | string)]. The usage of "|" improves readability in that there's no way to confuse a union type with a tuple type. -Yuh-Ruey Chen Jason Orendorff wrote: > On Oct 26, 2007 6:35 PM, James Clark <[EMAIL PROTECTED]> wrote: > > (int, string) doesn't seem to me to be a syntax that the average JS > > programmer will guess means union. I would have thought a better choice > > would be (int | string) (especially given that regexps use |) or a keyword. > > Yep. I read (int, string) as a tuple type every time. ML, Haskell, > Python 3.0... I'm not sure what we gain by going against the grain > here. > > So it's not a big deal, but switching to (t1 | t2) seems all upside to > me. It's a shallow change. +1. > > -j > ___ > Es4-discuss mailing list > Es4-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es4-discuss > > ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Es4-discuss Digest, Vol 8, Issue 44
As far as I can see it, there are a couple of non-technical issues here that have to be resolved, but they all boil down to who is willing to implement what. Is there truly no way to compromise? MS says that they think ES4 deserves to a be a new language. Suppose that is true and ES4 is renamed, say ES++. Then would MS be willing to implementing ES++ in their new browser? Or is the name truly a scapegoat to blame their misgivings of ES4 the language itself? Or if you consider the feature set of ES4 to be too bloated, that ES4 is trying to tackle problems it was never meant to handle, what exactly do you dislike about ES4? What features would do you want to cut out of the language? What features would the pro-ES4 people be willing to cut out? I know this will be hard, but let's ignore feature dependencies for the moment. Say, for example, that you dislike the class system but are fine with the type system (as nonsensical as that sounds). Perhaps you're fine with grafting a type system on top of the prototype system without classes. Or if you also dislike the type system, what do you propose instead? For encapsulation, you might propose sticking with closures. Now, how are you going to address the pitfalls of closures, namely memory usage and inefficiency? ES4 advocates may also be concerned that encapsulation via closures is plain ugly, while ES4 critics say that classes make the language inelegant. Perhaps there is another solution? Anyway, do you see where I'm getting with this? There should be some room for compromise. I'd like to see some active discussion concerning these feature disagreements. Lastly, all this accusations concerning intentions need to stop. Mozilla, this concerns you too - I find that saying you won't let big bully MS block ES4 is somewhat hypocritical, considering that the SVG 1.2 committee did something similar to you guys (make no mistake, I'm not accusing anyone and I hope this is the last time SVG is mentioned on this mailing list). In any case, hypocritical or not, all these accusations are not constructive at all. Responding to accusations with more accusations is plain sophomoric in my book. Please, I have enough of my political bullshit from the news - I don't expect that here. Thanks, Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: is ES4 getting too bloated?
Don't get me wrong - I love most of the new features (some others I'm just indifferent too). But I'm not implementing the interpreter; I would be a user of it. My concern is that of the implementator's burden, and from my point of view, if it takes a long time to implement ES4, it'll be a long time before I can get to use ES4 in practice. What Michael O'Brien just posted sounds very promising though. I haven't had the time to look at the whole spec as a whole, and since the spec is rather disorganized atm with a bunch of proposals, I'd have a hard time doing that in any case. But what I've seen so far is pretty good. I do kind of feel that there is some redundancy, i.e. there are distinct features that seem to overlap a lot. For example, packages and namespaces are both used to make programs more modular, albeit in different ways. Likewise for program units and packages. But like I said, I don't have a clear view of the spec as a whole, so I'll wait until there are good prose sections describing the usage of features before coming to a conclusion. -Yuh-Ruey Chen Garrett Smith wrote: > On 10/21/07, Yuh-Ruey Chen <[EMAIL PROTECTED]> wrote: > > Hey all, > > > > I've been watching ES4 development and occasionally contributing input, > > and I have noticed a somewhat disturbing trend. ES4 is getting ever more > > and more complex. > > > > I understand ES4 is a multi-paradigm language and so must be packed with > > features, but I don't think we want a repeat of the C++ template problem > > (where it took nearly a decade just to get most compilers near > > compliance with the C++ spec). My point is that although a significant > > update to ES is needed, if it takes too long to implement a conforming > > compiler/interpreter for it, the adoption of new features is going to be > > slow. Heck, I wonder how willing MS would be to provide a fully (or near > > enough to it) conforming interpreter for ES4 if the spec is so large. > > > Tamarin will be included as a plugin for IE. > > > Small proposals like bug fixes and reformed with and company, or > > proposals that generalize syntax to make the language more elegant are > > perfectly fine by me. But we already have such huge features like > > classes, generators, namespaces, type system, and now generic functions. > > Perhaps we should start deferring more features to ES5? > > > Which features do you feel are unjustified? Can you bring a specific issue? > > ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
is ES4 getting too bloated?
Hey all, I've been watching ES4 development and occasionally contributing input, and I have noticed a somewhat disturbing trend. ES4 is getting ever more and more complex. I understand ES4 is a multi-paradigm language and so must be packed with features, but I don't think we want a repeat of the C++ template problem (where it took nearly a decade just to get most compilers near compliance with the C++ spec). My point is that although a significant update to ES is needed, if it takes too long to implement a conforming compiler/interpreter for it, the adoption of new features is going to be slow. Heck, I wonder how willing MS would be to provide a fully (or near enough to it) conforming interpreter for ES4 if the spec is so large. Small proposals like bug fixes and reformed with and company, or proposals that generalize syntax to make the language more elegant are perfectly fine by me. But we already have such huge features like classes, generators, namespaces, type system, and now generic functions. Perhaps we should start deferring more features to ES5? -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss