The short answer is no, there is no way to override the constructor.
proxy is not meant to create a class, it is meant to create an object.

You have an API that requires an object of type A. So you can pass it
either an object of type A, or an object of a subclass of A. You do
not want to create a new class for some reason.* So what (proxy [A]
[]) is doing, in effect, is creating an object of an anonymous class,
which is a subclass of A. Let's call that anonymous class C. But you
do not yourself define C, and cannot affect its implementation. All
you can do is specify the parameters of the constructor of the
superclass, because if the superclass constructor needs parameters,
well, proxy has to get them from somewhere.

So far this may sound pretty useless, but the C class is not just the
equivalent of

public class C extends A {}

Imagine that class C has an instance variable, which we'll call _m,
which is a Map<String, Function<List<Object>, Object>, if it was
implemented in Java 8 (Function is java.util.function.Function), and
for which each method is implemented as follows. Assuming there is a
method

public String myMethod(Integer a, String b) {...}

in class A, the equivalent method for class C would be:

public String myMethod(Integer a, String b) {
    if _m.contains("myMethod") {
        List<Object> args = new LinkedList<>();
        args.add(a);
        args.add(b);
        return (String) _m.get("myMethod").apply(args);
    } else {
        return super(a, b);
    }
}

That is, for every method in A, C has a method with the same signature
which looks up an implementation in _m and uses that.

Within the (proxy ...) form, when defining method bodies, you can use
the symbol "this" to refer to the object itself. When you define a
method with

(proxy [A] ["MyWindow"]
  (someMethod [arg1 arg2] (some-code this arg1 arg2)))

what you get in the proxy mappings will be the equivalent of (ignoring
other entries):

{"someMethod" (fn [this arg1 arg2] (some-code this arg1 arg2))}

so the "this" magic is only done by the proxy macro itself. (For that
reason, I personally would not recommend using the proxy macro within
a let that actually defines a local this binding; there will be some
confusion at some point.)

So you basically have two options to emulate your constructor: create
the proxy object, then call methods on it, if all of the work of your
constructor can be done by calling methods, or close over some
variables, if you want the equivalent of new instance variables for
your object. So, for example:

(defn date-from [origin]
  (proxy [java.util.Date] []
    (toString [] (str (proxy-super toString) " coming from: " origin))))

user=> (.toString (date-from "localhost"))
"Sun Feb 01 19:16:12 CET 2015 coming from: localhost"
user=> (proxy-mappings (date-from "localhost"))
{"toString" #<user$date_from$fn__2905 user$date_from$fn__2905@6e3cfc75>}

proxy-super is used to access the superclass of the proxy object, when
you want to skip the proxy class implementation (i.e. exactly in the
same way you would use super in Java).

You can never change C's constructor. You can set the values in _m.
You can actually even change the values in _m after the creation of
the proxy object, with the help of clojure.lang.update-proxy.

I hope this clears things up. The performance hit of proxy versus a
"real" subclass is the dictionary lookup.

With all that said, the code snippets you have shown so far suggest to
me that you do not actually need any subclassing here. It is a pretty
common way of doing GUI things in the Java world, but subclassing GUI
components should, IMHO, be a last resort. You can do everything you
have shown so far just using a Window instance and calling its public
methods.

On 1 February 2015 at 17:32, Fluid Dynamics <a2093...@trbvm.com> wrote:
> On Sunday, February 1, 2015 at 11:08:19 AM UTC-5, Michael Blume wrote:
>>
>> Yes, but that's for methods you're overriding and OP wants a constructor
>
> For that you just replace
>
> (proxy foo ...)
>
> with
>
> (doto
>   (proxy foo ...)
>   (.doThisThingy x)
>   (.addThatComponent y)
>   (.etc))
>
> I would expect.
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with your
> first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to