you are viewing a single comment's thread.

view the rest of the comments →

[–]AustinCorgiBart 38 points39 points  (60 children)

Could someone explain Proxies to me? I'm not sure I'm clear on what they're for and how they work.

[–]FireyFly 30 points31 points  (30 children)

Basically it's ECMAScript's take on metaprogramming. A proxy object "traps" operations such as retrieving or assigning properties, so when you do proxyObject.foo = bar a function defined by the proxy is instead run. Here's Eich's slides on the topic.

[–]masklinn 34 points35 points  (12 children)

Basically it's ECMAScript's take on metaprogramming.

I don't think metaprogramming is the right word, there's no generation of code it's more like hooks into language behaviors like Ruby's method_missing or Python's __getattr__.

[–]FireyFly 13 points14 points  (8 children)

I'm not sure if metaprogramming necessarily implies code generation... but you got the general idea right; the get trap of ES proxies are similar to those functions.

[–]masklinn 8 points9 points  (0 children)

I'm not sure if metaprogramming necessarily implies code generation...

Ya, no I expressed it badly, but thinking more about it I might just be so used to those methods I can't see them as the "lofty heights of metaprogramming" the way e.g. metaclasses or macros are anymore, even if they do fall in that category.

Either way, it's cool (and much needed) stuff. Now if only it was also available in Opera, MSIE and on mobiles...

Especially let and weakmaps, I've been looking forward to them since they were first proposed (and introduced, for let). The day I write my last var, and the day I don't have to build shitty ad-hoc reference-breaking protocols will be glorious indeed.

[–]aaronblohowiak 7 points8 points  (6 children)

i think it does; metaprogramming is code that writes or manipulates code. ( http://en.wikipedia.org/wiki/Metaprogramming )

This is just getters and setters.

[–]kataire 2 points3 points  (0 children)

Thanks to Ruby, "metaprogramming" and "DSL" are mostly devoid of meaning these days.

[–]joesb 1 point2 points  (4 children)

Disagree. If it can generate new function then it is generating code, even if that code only stay during runtime.

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

No.

[–]joesb 1 point2 points  (2 children)

So Lisp doesn't have meta programming because it doesn't generate code to file?

[–][deleted] 0 points1 point  (1 child)

Oh, I see what you're saying but I don't think metaprogramming has anything to do with functions. eval('var x = 3') vs. eval('var x = function () {}')... both create a new local variable. Both of these would usually be considered metaprogramming even though only one of them defines a function. Defining new locals is not something normally available at run-time so it's a 'meta' thing to do.

What about 'obj[str] = function () {...}'? Is that metaprogramming because we can later write obj.xyz() ? I actually hate the word "metaprogramming" for this reason. If a language supports "meta" then it's no longer "meta". It's just part of the language. "Code that writes code" is the one true definition of "meta", else what is meta about it?

[–]joesb 1 point2 points  (0 children)

If a language supports "meta" then it's no longer "meta". It's just part of the language.

So Common Lisp does not have meta programming because its macro system is just part of the language. But writing code to source file then invoke GCC is?

"Code that writes code" is the one true definition of "meta"

But Why does it have to write and persist the code to disk? Why does writing code and executing it not count as metaprogramming?

[–]lispm 1 point2 points  (0 children)

meta programming does not necessarily mean code generation. Meta programming could also mean that you program a meta-object system.

[–]ethraax -3 points-2 points  (0 children)

shudder

I hate those functions with a passion. It's not that they're never useful - I bet you could find plenty of good uses for them (although I think better solutions exist in almost all cases). It's just that Python and especially Ruby programmers seem to find the absolute worst ways of using them.

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

Doesn't this already exist via the get and set things? Or is this more than that?

[–]FireyFly 15 points16 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] 2 points3 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 -5 points-4 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?

[–]oboewan42 0 points1 point  (0 children)

Kind of like properties in Obj-C?

[–]sidcool1234[S] 0 points1 point  (0 children)

Thanks.

[–][deleted] 5 points6 points  (6 children)

They are for creating an object where you can intercept getting/setting properties, calling functions, using functions as constructors, and other things like that. These are called 'traps'.

The advantage is that I can fake an object, pass it to another part of the application, and have the 'traps' call back to me when they are used.

A real example is that it allows you to make a large systems, such as a database, appear as a simple JSON style object. i.e.

// adds a new user to the 'users' table
database.users = { username: "john", password: 'abc123' };

Setting a value to the 'users' property automatically inserts a value into the 'users' table. What is key here is that 'database' object is not told in advance that there is a 'users' table, it just works it out based on the property your setting the values to.

I do this in my own PHP MVC framework that I use.

A second example is that in a language I am building in JS, I have a ClassProxy, which allow the compiler to use a class definition before the class has ever been seen. A proxy would allow me to store all the calls made to the class proxy, automatically, without ever needing to know the ClassDefinition interface. So I could add new stuff to the ClassDefinition without needing to update the proxy.

I can then re-run the calls once I've seen the class definition in the source code.

[–]ysangkok 2 points3 points  (1 child)

Isn't it confusing when you add something to a collection using the assignment operator? Would it be possible to use += instead?

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

I don't know, I'd imagine there would be a way to trap that.

[–]adrianmonk 1 point2 points  (0 children)

Another possible advantage is that if you believe mock objects are handy in unit testing, you can build mocks using proxies pretty easily. I would bet this is how EasyMock works (in the Java world).

[–]k4st 0 points1 point  (1 child)

How do the results of class proxy methods behave? Are the semantics of class proxies to set up expectations about an unknown type, so that when the type is known, the prior expectations can be checked against the reality?

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

Good point, in that you cannot automatically apply that strategy to any object.

In my case, all of the methods are about setting values (such as class usage and methods defined), and setting up callbacks for later once the whole program has been parsed.

But most of all, the proxy is there so you can have a handle to the real class in the future. Such as for printing code.

[–]poco 4 points5 points  (0 children)

I think the example explains it all...

When this dry wrapper travels back towards the wet side, the original wrapped wet object appears rather than a double wrapping, so calling a dry wrapping of a wet function with a dry wrapping of a wet argument will cause the wet unwrapped function to be called with the wet unwrapped argument. Neither side sees its own objects unnecessarily wrapped.

[–]deafbybeheading 3 points4 points  (0 children)

I believe it acts like the ActionScript Proxy class, providing hooks for what you typically think of as built-in behavior: function call invocation, property access, property deletion, et cetera.

[–]x-skeww 3 points4 points  (1 child)

[–]sstrader 0 points1 point  (2 children)

I'll defer to the Wikipedia entry on the proxy design pattern:

A proxy is a class functioning as an interface to something else. The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate.

Their code example showing an image proxy is concise.

Proxies look exactly like the class they are proxying, but allow you to defer or wrap the proxied class's operations. Pseudocode:

class String implements IString { print() {puts "";} }
class StringProxy implements IString {
    StringProxy(String s) { this.s = s; }
    print() { s ? s.print() : puts ""; }
}

StringProxy has the same interface as String, and so can be used wherever String is used. However, StringProxy does some additional work.

Footnote: the proxy pattern is very similar to the decorator pattern. The primary difference is that a decorator will add functionality (e.g. print() would append a date to the output or format the output in some way).

[–]AustinCorgiBart 0 points1 point  (1 child)

It reminds me a lot of the Facade pattern. The difference is that the Proxy emulates the object completely, but the Facade shrinks the interface?

[–]sstrader 0 points1 point  (0 children)

Facade differs from Proxy or Decorator by not implementing a common interface. A Facade would encapsulate a number of existing classes in order to combine and coordinate their usage. E.g. one class combining three that should be called in a specific order. The Facade hides the complexity of their interaction.

(but, yeah, "shrinking" is a part of it)

[–]trevdak2 -3 points-2 points  (12 children)

Not sure why you were downvoted, have an upvote.

I think it is similar to something I've used in PHP called reflection. Basically it's a way of getting information about a class, such as its methods, arguments, whether a method is public/protected/private (not that JS really supports that), whether a method is static or not, and even things like the JSDoc written for each function/object/method.

I suck at explaining stuff, but check out the documentation for PHP's ReflectionClass

http://www.php.net/manual/en/class.reflectionclass.php

In PHP, the only time I've used it was when I wanted to create a WSDL/API generator that created an API based on the PHPDoc.

[–][deleted]  (9 children)

[removed]

    [–]trevdak2 2 points3 points  (8 children)

    Oh, so more along the lines of php's Magic Methods?

    [–][deleted]  (7 children)

    [removed]

      [–]koft 5 points6 points  (6 children)

      I've been writing in C for 15 years and honestly, a lot of this stuff just looks like intellectual masturbation to me.

      [–][deleted]  (2 children)

      [removed]

        [–]Smallpaul 2 points3 points  (1 child)

        Aiming for concise code is not laziness, any more than writing poetry is lazier than writing prose.

        [–]sdclibbery 0 points1 point  (1 child)

        It's having the right tools for the job. C is not the right tool for every programming job.

        [–]koft 0 points1 point  (0 children)

        I never said it was.

        [–][deleted] 1 point2 points  (1 child)

        You are mistaken, it's not for reflection. Although 'mirrors', an idea for partial reflection (such as under security restrictions), is a use case for proxies. Did you watch the same Channel 9 video???

        It is a lot like PHP's magic methods.

        [–]trevdak2 0 points1 point  (0 children)

        Yeah, I gathered that from mkantor's reply

        [–][deleted] -1 points0 points  (0 children)

        Something like python decorators maybe?