Cedric, hello. On 2012 Jan 15, at 20:32, Cedric Greevey wrote:
> On Sun, Jan 15, 2012 at 6:52 AM, Norman Gray <norman.x.g...@gmail.com> wrote: >> user=> (def m (proxy [java.util.HashMap] [] >> (finalize [] >> ;(proxy-super finalize) >> (prn "finalizing...")) >> (hashCode [] >> 99))) >> #'user/m >> user=> (.hashCode m) >> 99 >> user=> (.finalize m) >> IllegalArgumentException No matching field found: finalize for class >> user.proxy$java.util.HashMap$0 clojure.lang.Reflector.getInstanceField >> (Reflector.java:289) > (TL;DR version: just skip to the end.) (not too long at all; read avidly) I'll work through this again tomorrow, but a couple of things occur to me now. > Actually, ancestors expects a class rather than an instance, and > returns nil for anything that's not a class. Aha. That's not particularly obvious from the 'ancestors' docs.... But I do see that in my case above, the new object appears to have some sort of subclass relationship with java.util.HashMap: user=> (ancestors (.getClass m)) #{clojure.lang.IProxy java.lang.Object java.io.Serializable java.util.Map java.util.HashMap java.lang.Cloneable java.util.AbstractMap} Excellent -- that makes sense. > So, your problem is actually very simple: you tried to call a > protected method from an unrelated class, which won't even work with > reflection. At least, not normally. Section 6.6.2 of the JLS mentions that "A protected member or constructor of an object may be accessed from outside the package in which it is declared only by code that is responsible for the implementation of that object" (this is echoed in Sect 2.7.4 of the JVM spec). Now, the text which follows that seems to boil down to saying that subclass implementations can see protected instance fields or methods, which we all know, of course. Also, you established that methods overridden in a proxy are public. What those two statements appear to mean is that the overriding finalize method should be a public one, and that it should be able to call its super.finalize() method (of course, in this case the fact that finalize is public doesn't really matter, since what matters is that the GC can call finalise(), but we want to be able to call finalize() explicitly only to verify that it's there and doing what it should) You conclude that: > So, a proxy [...] will NOT override Object's finalize method, EVEN IF > explicitly > told to do so and given an implementation for such an override. > > Apparently it's treating that as a special case, either as an > undocumented but intentional limitation of the proxy facility of > clojure or else as a bug perhaps caused by the JVM treating finalize > specially. And further... > Any further information is probably going to have to come, directly or > indirectly, from someone who is knowledgeable about the intentions of > the developers of the proxy macro, and not via the docs, since the > docs, as you're aware, are mute on any special limitations on which > protected methods can be overridden (they say only that they can be in > general, but the user-supplied proxy code will not have access to > protected fields of the proxied class). There seem to be a couple of possibilities. * There's an edge-case of the legalese in JLS 6.6.2 or JVMS 2.7.4 or 5.4.4 that is triggered by Clojure's implementation of the proxy class, and which is beyond my current forensic powers to spot. * Or there's a special case. The 'generate-proxy' function in <https://github.com/clojure/clojure/blob/master/src/clj/clojure/core_proxy.clj> does mention "finalize" in a test which apparently excludes specifically that method from a "set of supers' non-private instance methods", but I can't work out quite what it's doing with those. It _may_ be that the goal there is to automatically call super.methods for each method in the proxy, and I can see why one would want finalize() to be exempt from that, but if so, it may be this code which is, inadvertantly or not, preventing extending-classes adding finalizers. The fact that (as you note) the proxy code is documented not to have access to protected members does suggest that the proxying class is at least not straightforwardly a subclass of the base class. The Joy of Clojure mentions (p196) that "Clojure doesn't encourage implementation inheritance", that gen-class and proxy only provide "something like Java-style implementation inheritance", and suggests (p210) that proxy classes trade flexibility for performance. In this case, I can broadly understand why 'proxy' isn't producing what I think, or at least thought, it was producing (a straightforward subclass of the proxied class). But in that case, I'm stumped, and don't know how I would go about overriding a finalize() method in an idiomatic and non-painful (ie non-gen-class) way. Best wishes, Norman -- Norman Gray : http://nxg.me.uk -- 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