Hopefully not too dead of a topic (just catching up on the list...), but 1) I think a lot of this pattern can be encoded at the library level assuming a catch-all operator
2) A practical use case I had wanted to do this for was distributed objects (e.g., batching updates until a commit). Either way, again, I think it's a library-level thing assuming an updated meta object protocol. Regards, - Leo On Apr 13, 2011, at 1:37 AM, [email protected] wrote: > Send es-discuss mailing list submissions to > [email protected] > > To subscribe or unsubscribe via the World Wide Web, visit > https://mail.mozilla.org/listinfo/es-discuss > or, via email, send a message with subject or body 'help' to > [email protected] > > You can reach the person managing the list at > [email protected] > > When replying, please edit your Subject line so it is more specific > than "Re: Contents of es-discuss digest..." > Today's Topics: > > 1. Re: [Harmony proxies] Discussion on the "declarative object" > experiment (Dmitry A. Soshnikov) > 2. Re: [Harmony proxies] Discussion on the "declarative object" > experiment (David Bruant) > 3. Re: 'this' is more complicated than I thought > (PropertyReferencesbreak equivalences) (Claus Reinke) > > From: "Dmitry A. Soshnikov" <[email protected]> > Date: April 13, 2011 1:18:51 AM PDT > To: David Bruant <[email protected]> > Cc: [email protected] > Subject: Re: [Harmony proxies] Discussion on the "declarative object" > experiment > > > On 13.04.2011 12:08, David Bruant wrote: >> >> Le 13/04/2011 09:02, Dmitry A. Soshnikov a écrit : >>> >>> On 12.04.2011 20:41, David Bruant wrote: >>>> >>>> Hi, >>>> >>>> I'd like to share my experience on a recent experiment. First off, I'd >>>> like to apologize for the name; "declarative object" doesn't really >>>> capture it and may be confusing. Second of all, what I have created >>>> doesn't really solve any use case (I'll discuss it), but offers at most >>>> some syntactic sugar. Code can be found here : >>>> https://github.com/DavidBruant/DeclO >>>> >>>> One idea is to have an object "o". This object can accept any property >>>> name (get trap only in my case). Accessing a property will generate an >>>> object on-the-fly which itself can accept any property name and generate >>>> an object, etc. At the end, the object can be used as a constructor to do >>>> something. Example: >>>> --- >>>> var a = new o.azerty.are.the.first.letters.of.my.keyboard(); >>>> var b = new o.David.Bruant.writes.JavaScript(); >>>> --- >>>> The point could be to build something based on the property names (stored >>>> in the propNames variable and added with the push l.8). Of course, a >>>> constructor taking a string array could be as useful. That's the reason >>>> why I said earlier it doesn't solve any use case. The syntax sugar is the >>>> only added value I can think of. >>>> The exact use of the string array is to be defined in the constructTrap >>>> function. The pattern is here. >>>> >>> >>> Yes, the pattern is interesting, though, really, which practical use-case >>> will it have? >> I warned from the beginning that I didn't see any :-p >> More seriously, the main point of sharing my experiment was the discussion >> on shared handlers for several proxies. >> >>> Currently a one possible I see -- a query to database with building the >>> query itself. Sort of: >>> >>> where >>> .name("Dmitry") >>> .surname("Soshnikov") >>> .active(true) >> I have tried to think of a lot of use cases. This one, for instance, doesn't >> even requires proxies (As I understand it). As long as you know the number >> and names of the all properties (I assume you do by knowing which database >> table you're querying), ES5 accessor properties could be used. This goes >> with the restriction that it's likely to be far more memory consumming, but >> the pattern could be applied the same way. >> Now that I think about it, I realize that for getters/setters, the exact >> same object could be used (may depend on the use case). Same for my pattern, >> I use Proxy.createFunction for each intermediary (l.10), but I could >> factorize it and return the same proxy each time since traps don't change at >> all. >> >> Also, I'd like to note that if each of your property is a function call, you >> don't even need accessor properties. That's what jQuery already does by >> returning "this". >> >> >>> etc (though, it should be callable in contrast with yours implementation). >>> But, it also arguable whether it's so useful. >> I have no strong opinion on callable or not. It was just an idea that the >> pattern would better be used as a constructor. The main point of the pattern >> lies on the use of the get trap in "firstHandler" and "middleHandler". It >> could be improved by a different call/construct trap (and the use of >> arguments for these). >> > > Yeah, right, that's why I also mentioned that it's arguable whether the > pattern is useful to apply to this particular issue. It wast just a guess. > > Regarding shared handlers, if exactly this is the point, we have also think > which practical things can we have. > >> >>> >>> However, your letter made me think on proposing existential operator, which >>> is a syntactic sugar to avoid long testing whether a property exists and >>> only after that to apply it. This already is again used in CoffeeScript, so >>> I'll show the examples: >>> >>> let street = user.address?.street >>> >>> which desugars e.g. into: >>> >>> street = (typeof user.address != "undefined" && user.address != null) >>> ? user.address.street >>> : undefined; >> Shouldn't it desugar to "(typeof user.address == "object" && user.address != >> null)?" ? >> > > Yeah, it's also just an example, any (but the most efficient) desugared > variant can be used. > > Dmitry. > > > > From: David Bruant <[email protected]> > Date: April 13, 2011 1:32:14 AM PDT > To: "Dmitry A. Soshnikov" <[email protected]> > Cc: [email protected] > Subject: Re: [Harmony proxies] Discussion on the "declarative object" > experiment > > > Le 13/04/2011 10:18, Dmitry A. Soshnikov a écrit : >> >> On 13.04.2011 12:08, David Bruant wrote: >>> >>> Le 13/04/2011 09:02, Dmitry A. Soshnikov a écrit : >>>> Yes, the pattern is interesting, though, really, which practical use-case >>>> will it have? >>> I warned from the beginning that I didn't see any :-p >>> More seriously, the main point of sharing my experiment was the discussion >>> on shared handlers for several proxies. >>> >>> (...) >>> >> (...) >> >> Regarding shared handlers, if exactly this is the point, we have also think >> which practical things can we have. > The straightforward benefit I see for shared handlers is to avoid one handler > instanciation per proxy instanciation. The downside is the brainfuck it > produces in terms of scope definition and code organisation (I've worked hard > to make my code easy to read. I find it hard nonetheless). > > Do you have other practical things in mind? > > David > > > > From: "Claus Reinke" <[email protected]> > Date: April 13, 2011 1:38:07 AM PDT > To: <[email protected]>, "Lasse Reichstein" <[email protected]> > Subject: Re: 'this' is more complicated than I thought > (PropertyReferencesbreak equivalences) > > >> The behavior of References isn't as arbitrary or different from other >> languages as it might seem. It's really a way to specify l-values. > > Not arbitrary, but different, and quite drastically so (as far as > usage is concerned). Your remarks helped me to pin down the difference (and > eliminated two of my questions, thanks!-): References are l-values, but they > cannot be used as such, due to forced, implicit conversion curtailing their > lifetimes. > > The differences between References and general l-values (_values_ that > represent locations where other values may be > stored) lies in how they may be used and how long they live: > > - l-values are first-class values: they can be passed around, assigned to > variables, stored in data structures; they happen to support a > de-referencing operation, but merely evaluating > an l-value does not de-reference it; l-values can be de-referenced > explicitly; some languages implicitly coerce l-values into r-values > (causing de-reference) depending on > usage context (this is where the names come from: values on the left and > right hand sides of assignments), but even those languages tend to provide > means to control when coercions take place > > - References start out as l-values, but don't live long enough > to be used as such. They cannot be passed around, stored in data > structures, or assigned to variables; any attempt to evaluate them leads > to immediate de-reference, no matter whether the usage context expects an > l-value or not; there > is no way to prevent the implicit de-reference > > It is mostly the implicit coercion in evaluation, combined with > the early evaluation inherent in Javascript's call-by-value semantics, that > breaks those equivalences. > >> In other languages, e.g., C or Java, you have the same problem: >> int x = something.prop; >> x = 10; >> is not the same as >> something.prop = 10; > > My C has been buried for too long, but were not l-values > one of C's showcases? Something like this > > int *x = &(something.prop); > *x = 10; > > should work, by making x hold l-values (in case I messed up the syntax beyond > recognition: x should be a pointer to int, > its value being the address of something.prop, so we can use > the r-value of x as an l-value in the second assignment). > > C allowed us to be explicit about whether we wanted l-values > or r-values, overriding the default conversions when necessary. > Some later languages, such as Haskell or Standard ML, dropped > the implicit coercions entirely, so all de-references are explicit. > > ECMAScript relies on implicit de-reference, but triggers that by > every evaluation. So we don't have explicit de-reference, we do > not have C's flexibility for explicit de-reference control, and we > do not even have C's context-sensitive implicit de-reference. > > Which means that things like > > (1 ? obj.prop : obj.prop) = 3; > (0, obj.prop) = 2; > > will work in C, but fail in ES (References are very short-lived > l-values - every operation evaluates and de-references them, > independent of whether the result is going to be used in an > l-value or r-value context). > Also, in C we can write > > x = &(obj.prop); > *x = 4; > > to express that we want x to hold l-values, and storing l-values in arrays > isn't much different > > int *a[1] = { &obj.prop }; > *(a[0]) = 1; > > In ES, we only have the default-to-r-value path. For instance, > > [obj.prop][0] = 1; > will not use obj.prop as an l-value, and there does not seem to be a > straightforward alternative for programmers who want to work with ES > References as l-values. >> So far, References as a specification mechanism is just following other >> languages, and behaving exactly as any seasoned programmer would expect. > > Does the above explain why a seasoned programmer > might reasonably expect differently, because ECMAScript behaves differently > from other languages? > >> The binding of "this" when calling a Reference value mimics method calls. It >> does so fine when you treat objects as objects, but not when you try to >> extract a method from its object .. It's a shallow abstraction, but it does >> work when you play along with it. > > I was trying to point out that the mechanism works for the > simple case and is known to confuse programmers for other cases. In > particular, I am trying to find out whether the current mechanism is a > special case of a more complete mechanism, > one that works equally well for simple and non-simple cases. > > Since PropertyReferences hold the object the method was > selected from, all that seems needed is to make References > survive evalutation, ie, make References first-class values. > > An alternative would be to preserve context-information > during evaluation: if the result of '(?:)' is to be used as an > l-value, then evaluation should perhaps not de-reference > the l-values in the conditional. > > I am less concerned with being able to use '(?:)' on the > left hand side of assignments, and more with being able > to use equivalences like '(true ? x : x) <--> x', independent > of where the expression occurs. Since we can write such > conditionals on left hand sides, why not make sure that > they actually work there? > >>> Question 1: Should a Reference hold on to the current >>> property value? >> Which value? The one the property (if it existed) had when the reference was >> created? Or the current one - if the Reference survives for any amount of >> time, the object property could change its value in the meantime. > > Thanks. So the answer probably is 'no' - which value we get depends on when > we look behind the reference. > I guess I was confused by property accessors not actually accessing the > property - once the decision is made to return a Reference instead of the > property value, it would only be > consequent to keep Reference construction and de-reference > separated. As long as we are able to specify when to pass the reference and > when to look up the value behind it. > >>> Question 2: >>> If a Reference allows us to recover 'obj' from 'obj.method', >>> why does this information have to get lost when passing it through a >>> variable binding? >>> .. could this error source be eliminated by passing the Reference >>> as a value, instead of only the value component >>> without the base object, one step further? >> Of course it's possible, but personally I prefer to have the "this" object >> obvious in the call line. That way I know what object the method is being >> called on. Without it, the loss of context is in the source code, making it >> harder to read and maintain. > > I'm afraid you won't get that comfort;-) At the moment, programmers can just > write the more complicated > > var short = function(x) { return obj.method(x); }; > short("hi"); // no 'this' object on the call line > > We can try to make this more readable, and we can try to > eliminate a common source of bugs, but the rest is between > you and your team's coding style and style checker. >>> Question 3: >>> It seems that trying to reuse References for 'this' forces >>> early calls to GetValue (because users should not have to >>> call 'obj.method.valueOf()' or 'obj.property.valueOf()' to trigger >>> the delayed selection, and because the property >>> value is not stored in the PropertyReference). >> I'm not sure I understand what the problem is here. > > Probably because the description is a bit confusing. I was > trying to understand why References get eliminated early, > through calls to GetValue, and was enumerating non-reasons > before coming to my question: > >>> This loses information that we would like to hold on to - if we really >>> cannot solve this for References in general, >>> why not store the 'this'-candidate in the function instead >>> (similar to the fairly new '[[boundThis]]')? >> Won't work. The same function can be used in many places at the same time. > > Ah, good point. If functions were constants, we could make copies (sharing > the code, but with different this values). But > they aren't, so we need the 'this'-candidates outside the function. > >> E.g. >> [obj1.foo, obj2.foo][(Math.random() * 2) | 0](); > > Note that, currently, either selection will have that anonymous first array > as 'this', not obj1 or obj2. But > you were aware of that, right?-) >>> Question 4: (general version of question 2) >>> Why is the origin information in References lost so easily? >>> >>> It seems that most parts of the spec require GetValue() by >>> default, with few exceptions. What would go wrong if the >>> available information would be passed on instead (isn't >>> it sufficient for the final consumers to call GetValue(), >>> provided that the original property value is stored in the >>> PropertyReference, to avoid interference)? >> References is a specification tool. If it survived for an extended amount of >> time, and visibly so, implementations would have to actually implement >> something to represent it. As it is now, a reference is found and >> immediately consumed, which allows implementations to never create it at >> all, and work directly on the value in r-value contexts, and on the object >> and property in l-value contexts. > > Yes, and that is my argument. L-values as first-class values is the common > way to handle references, whether it is in C, in Haskell, in ML, .., ever > since Strachey documented l-values in 1967, and probably longer than that. > Once references become visible to programmers, one might as well support them > fully. Eliminating > temporary structures is a common implementation optimization, not limited to > References, and not a language spec concern. > >>> Broken equivalences: > .. >>> var x = obj.m; x(); <-/-> obj.m(); >>> >>> obj.m.valueOf() <-/-> obj.m >> Why should that work? The valueOf function isn't guaranteed to return >> anything related to the object it's on. > > The default valueOf for Function comes from Object, > where it is 'ToObject this', which for Object is the input > argument without conversion. I think.. > >> This is exactly correct. Extracting a method from its object will break the >> connection to the object. Which is kind of expected when you allow any >> function to be used as both a method and a non-method. > > I expected none of these: > > - Property access is not extraction. > - Extraction is triggered by constructs that could just > as well pass on the property accessor (and probably > should, as the alternative leads to runtime errors). > - Extraction alone will not break the connection, only > some forms of triggering extractions will do so. > - A new connection is established by trying to pass > a property accessor through an Array. > >>> I was not aware that just about any code transformation >>> would be invalidated by the handling of References. If this cannot be >>> fixed, could the specification be more explicit about this, please? >> When I think of References as l-values, the current behavior actually become >> the expected one. The only tricky bit is that method-calls actually need an >> l-value to work correctly. > > Even the l-value part is unusual, as I've tried to show. > > Claus > > > > > _______________________________________________ > es-discuss mailing list > [email protected] > https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

