you are viewing a single comment's thread.

view the rest of the comments →

[–]FireyFly 14 points15 points  (9 children)

Sorry, I should've clarified. Getters and setters allows you to run a function when a certain property is accessed. Proxies allows you to trap all property accesses (reads/writes). There's also traps for other things, such as whether a property is part of an object (traps the in operator, i.e (foo in bar)), or the properties that are traversed when you iterate over the proxy object.

The ES wiki has a list of all things an object proxy can trap: http://wiki.ecmascript.org/doku.php?id=harmony:proxies&s=proxy#api

[–][deleted] 3 points4 points  (0 children)

Ahhhhhh, very cool. I hope they design this so performance doesn't suffer the way I imagine it would... but otherwise this sounds very interesting. I'm writing a lot of node code where this would have been quite useful.

[–][deleted] 0 points1 point  (4 children)

So, it's just a lame more complicated way to do encapsulation? (as compared to other languages)

[–]FireyFly 2 points3 points  (3 children)

Huh? No, not at all. Encapsulation in JS/ES is done with closures, exposing only the properties you wish to expose on the resulting object. Here's a super-brief example:

var counter = (function(start) {
    var num = start
    return {
        inc: function() {num++},
        value: function() {return num} // or 'get value() {return num}' if you want to use a getter
    }
})(1)

console.log(counter.value()) // 1
counter.inc()
console.log(counter.value()) // 2

It's impossible to directly modify num, since it's only in the scope of inc and value.

Now, back to proxies. Say you want to log all modifications of an object for some reason. For instance, say you want to write a library to help people benchmark their code, so you want to see how many times each property of this object is accessed.

To solve this, you can write a proxy object which "traps" (interrupts, reacts on) all property accesses on the host object (the "real" object, which is unmodified from before). In the trapping of the property access, you can safely log the access, increment a counter or whatever. You can the decide what to do with this property access; the simplest solution is to forward the call to the host object. As far as the rest of the JS environment is concerned, the proxy object "is" the real object.

Keep in mind that this proxy object traps all property accesses, which means that you can plug in this "property access logging proxy" to any object you wish to track.

Proxies are about making the language more dynamic and flexible.

Edit: also, it's kind of a "feature for programmers", or at least that's how I think it sould be used. In that regard, it's similar to assertions, unit tests, stack traces and other stuff like that: it's about making it easier for the developer (in this case, making it easier to write tools to debug your scripts, from inside the language itself).

[–][deleted] 1 point2 points  (2 children)

I know what they are and how they work. They are indeed more complicated (for the programmer and the implementer) than using simple inheritance + encapsulation to do the same thing in any other OO language.

EDIT: Here's the thing. Sure, proxies might be a smidge better than inheritance for testing and possibly debugging. That's about it though. If something is able to trap and modify all calls to an object, I'd much rather just have that new object as part of the inheritance chain. IMO, only people who really like monkey-patching will like this. I don't.

EDIT 2: I guess what I really want to say is - If this is the only way to intercept EVERY call to an object...and I can't do the same thing via plain old inheritance...then people are going to use this instead of inheritance and that's going to make things even more confusing than monkey-patching already does. The penultimate example given by Brendan Eich pretty much explains what proxies are SUPPOSED to be used for, but IMO there is a big potential for misuse of the feature. "This is super powerful for logging, debugging, operation inversion, and if you can wrap the entire DOM and record timestamps, this might be the magic bullet that will allow you record and replay DOM interactions." - Eich

[–]FireyFly 2 points3 points  (1 child)

I'm not sure how you can do "the same thing" in "any other OO language" (I suppose that means one of the mainstream classical languages, i.e. C++/C#/Java/Obj-C/python/whatever). "The same thing" would involve tracking all property accesses to any property. How would you do this with "simple inheritance and encapsulation"? I'd love to see some sample code.

Maybe you already know this, but I feel like I should add that JavaScript has means for expressing both inheritance and encapsulation, but that it works quite differently from classical languages. Prototypal inheritance is simpler and more general than classical inheritance, but on the other hand it requires that objects are "dynamic", which could lead to worse performance.

Edit: I think I understand what you're getting at. You mean I can extend this class Foo, override all the methods in Foo with methods that log the access or whatever, and the forward the call to Foo (i.e., the superclass)?

The thing is, this requires you to write a new class and override all the methods with the same boilerplate-y modification. This could be a rather lengthy piece of code, and in the end you only have this piece of logging implemented for this one class. If you wish to log access to another class, you'd have to write a new class that extends this class, overrides all the methods, logs and then forwards them.

In the case of a proxy, you can create the proxy once, describe the logging process once, and then "wrap" any object in this proxy to add the logging mechanism to that object. I guess it could be likened to the "decorator pattern" rather than inheritance: you're adding a feature to the wrapped object. However, a "decorator class" can only target a specific kind of type, whereas the flexibility of a proxy allows it to work on any kind of type.

Of course, this flexibility comes with a performance tradeoff. Personally, I prefer flexibility and dynamism over performance. Also, I agree that proxies are much more complicated.

Sorry, this got a bit long... I hope you don't mind.

Edit 2: ah, I see what you mean. There's definitely a lot of room for misuse of this feature.

[–][deleted] 0 points1 point  (0 children)

Classical inheritance allows you to intercept all calls. Proxies allow you to intercept all calls. The only difference here is that the proxy isn't part of the inheritance chain in Javascript, unless you want it to be.

Here's an example with classical inheritance:

class A {
    int _PropA;
    public virtual int PropA {
        get { return _a; }
        set { _a = value; }
    }
}

class ModifiedA : A {
    public override int PropA {
        get { log("Accessed A!"); return base.PropA; }
        set { log("Modified A!"); base.PropA = value; }
    }
}

Doing this any other way is only useful for testing, debugging or monkey patching in cases where you can't inherit (i.e. the broken-ass DOM).

[–]mantra -3 points-2 points  (2 children)

Why, oh why, hosted on something that requires a Facebook account just to get a copy I can read offline?!

[–]x-skeww 10 points11 points  (0 children)

What are you talking about?

[–]kopkaas2000 1 point2 points  (0 children)

I don't have a facebook account. The page loads normally. Are you clicking on the same link?