<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div><div>On Oct 13, 2010, at 6:56 AM, Dmitry A. Soshnikov wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite">
<div bgcolor="#ffffff" text="#000000">Also I think now, that what was named as pros, i.e. ability to have
    funargs and call/apply invariants, in real, not so pros. Because
    users more likely want to catch exactly missing methods (if you
    don't like the word "methods", since there're no methods, there are
    properties, let's say -- missing properties which ended with `call
    expression` at the call-site). </div></blockquote><div><br></div>That's not our experience with E4X (ECMA-357), which specifies XML methods as invoke-only. They seem to be normal function-valued properties of XML.prototype, but getting one by name on an XML instance in a non-callee expression context instead tries to find an XML child element or elements of the method's name, returned as a list.</div><div><br></div><div>Some of this is peculiar to E4X, but the invoke-only nature of the methods, per-spec, is not. And it breaks apply and functional programming, so we extended E4X with the function:: pseudo-namespace to allow one to extract methods from XML instances.</div><div><br></div><div>Others using __noSuchMethod__ are happier as you say, because (for example) they are Smalltalkers (Bill Edney is on this list) who pretend there are only method calls (message sends), never properties or first-class functions.</div><div><br></div><div>But that happiness is not universal, so your "not so pros" judgment is not true for everyone.</div><div><br></div><div>Should we support everyone even if it makes the Proxy system more complicated and allows for not-quite-function methods?</div><div><br></div><div>Our decision was "no". You're asking us to revisit to support the some (not all) developers who want to make not-quite-function methods. That's a fair request but I think you need to do more than assert that the resulting complexity is not a problem. Further below, I'll do some legwork for you.</div><div><br></div><div><br><blockquote type="cite"><div bgcolor="#ffffff" text="#000000">And funargs/apply invariants should
    be leaved for _real functions_ (existing or ad-hoc, explicitly
    returned from the `get`).</div></blockquote><div><br></div>Why shouldn't all methods including missing ones be _real functions_? Why complicate the domain of discourse with real and not-quite-real functions?</div><div><br></div><div><br><blockquote type="cite"><div bgcolor="#ffffff" text="#000000"> Moreover, as it has been mentioned, such
    returning has broken === invariant anyway (and also broken invariant
    with non-existing properties).<br></div></blockquote><div><br></div>Proxy implementors can memoize so === works. It is not a ton of code to write, and it gives the expected function-valued-property-is-method semantics. Here is&nbsp;the not-all-that-inconvenient proxy code:</div><div><div><font class="Apple-style-span" face="'Courier New'"><br></font></div><div><font class="Apple-style-span" face="'Courier New'">function makeLazyMethodCloner(eager) {</font></div><div><font class="Apple-style-span" face="'Courier New'">&nbsp;&nbsp; &nbsp;var cache = Object.create(null);</font></div><div><span class="Apple-style-span" style="font-family: 'Courier New'; ">&nbsp;&nbsp; &nbsp;var handler = {</span></div><div><font class="Apple-style-span" face="'Courier New'">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;get: function (self, name) {</font></div><div><span class="Apple-style-span" style="font-family: 'Courier New'; ">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (!cache[name])</span></div><div><font class="Apple-style-span" face="'Courier New'">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cache[name] = Proxy.createFunction({},</font><font class="Apple-style-span" face="'Courier New'">&nbsp;function () {</font></div><div><font class="Apple-style-span" face="'Courier New'">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return eager[name].apply(eager, arguments);</font></div><div><font class="Apple-style-span" face="'Courier New'">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</font><span class="Apple-style-span" style="font-family: 'Courier New'; ">);</span></div><div><span class="Apple-style-span" style="font-family: 'Courier New'; ">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return cache[name];</span></div><div><font class="Apple-style-span" face="'Courier New'">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</font></div><div><font class="Apple-style-span" face="'Courier New'">&nbsp;&nbsp; &nbsp;};</font></div><div><span class="Apple-style-span" style="font-family: 'Courier New'; ">&nbsp;&nbsp; &nbsp;return Proxy.create(handler, Object.getPrototypeOf(eager));</span></div><div><font class="Apple-style-span" face="'Courier New'">}</font></div><div><font class="Apple-style-span" face="'Courier New'"><br></font></div><div>A little test code:</div><div><font class="Apple-style-span" face="'Courier New'"><span class="Apple-style-span" style="font-family: Helvetica; "><br></span></font></div><div><font class="Apple-style-span" face="'Courier New'">var o = {m1: function () { return "m1"}, m2: function () { return "m2"; }};</font></div><div><font class="Apple-style-span" face="'Courier New'">var p = makeLazyMethodCloner(o);</font></div><div><font class="Apple-style-span" face="'Courier New'">print(p.m1());</font></div><div><font class="Apple-style-span" face="'Courier New'">print(p.m2());</font></div></div><div><br></div><div>Some subtle things here:</div><div><br></div><div>* The missing fundamental traps in the handlers are filled in by the system. This is a recent change to the spec, implemented in SpiderMonkey in Firefox 4 betas.</div><div><br></div><div>* Even p.hasOwnProperty('m1') works, because the get trap fires on 'hasOwnProperty' and clones eager['hasOwnProperty'] using a function proxy, even though that method comes from Object.prototype (eager's Object.prototype). The hasOwnProperty proxy then applies Object.prototype.hasOwnProperty to eager with id 'm1'. No get on 'm1' traps yet -- no function proxy creation just to ask hasOwnProperty.</div><div><br></div><div>* Both p.m1 and p.m1() work as expected. Only one kind of function.</div><div><br></div><div>Now consider if you had a third parameter to the 'get' trap to signal callee context vs. non-callee context. You'd still want to proxy the functions, that doesn't get simpler just due to a change of trap parameters. You'd still want to cache for identity. But you would have made invoke-only methods.</div><div><br></div><div>Ok, let's give up on functional programming and cached methods. Here' s my version written to use only __noSuchMethod__, no proxies:</div><div><br></div><div><div><font class="Apple-style-span" face="'Courier New'">function makeLazyMethodCloner(eager) {</font></div><div><span class="Apple-style-span" style="font-family: 'Courier New'; ">&nbsp;&nbsp; &nbsp;return Object.create(Object.getPrototypeOf(eager), {</span></div><div><font class="Apple-style-span" face="'Courier New'">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;__noSuchMethod__: {</font></div><div><font class="Apple-style-span" face="'Courier New'">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;value: function (name, args) {</font></div><div><font class="Apple-style-span" face="'Courier New'">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return eager[name].apply(eager, arguments);</font></div><div><font class="Apple-style-span" face="'Courier New'">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</font></div><div><font class="Apple-style-span" face="'Courier New'">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</font></div><div><font class="Apple-style-span" face="'Courier New'">&nbsp;&nbsp; &nbsp;});</font></div><div><font class="Apple-style-span" face="'Courier New'">}</font></div><div><font class="Apple-style-span" face="'Courier New'"><br></font></div></div><div>9 lines instead of 13, but broken functional programming semantics -- you cannot extract p.m1 or p.m2 and apply them later, pass them around, etc.</div><div><br></div><div>What good would result from this? Again, our view in TC39 is "not much".</div><div><br></div><div>Note that I used a mechanical, consistent coding style ("JSK&amp;R", &nbsp;{ on same line as function, newline after {), so the comparison is apples to apples. Is the broken semantics really worth four lines of savings?</div><div><br></div><div>So, no fair asserting "practically it's unsoundly complicated and inconvenient". And please stop invoking "ideology" as a one-sided epithet to throw against Tom or TC39. Please do start showing examples, specifically an apples-to-apples comparison with __noSuchMethod__ that is significantly simpler. I don't see it.</div><div><br></div><div>/be</div></body></html>