Re: adding metadata to java objects

2011-11-17 Thread Ben Mabey

On 11/17/11 4:21 AM, Chas Emerick wrote:

Ben,

It's a good idea, but it's going to bite you:

- what if the class in question has fields or package-private methods that are 
touched by Java code?


Yeah, there are some use cases where this would fall apart in.  Assuming 
that you use only public methods then everything should delegate as 
expected. Point taken about the potential of unpleasant surprises.



- what if the class take ctor arguments?
- what if the ctor has side effects?
I don't think these last two points apply.. in my use case the object 
has already been created and so the original constructor never is 
called.  The instantiated object is simply passed from one delegate to 
another with the different metadata associated on to it.


-Ben




On Nov 16, 2011, at 11:28 AM, Ben Mabey wrote:


Hi,
I would like to be able to add metadata to arbitrary java objects that have 
already been instantiated.  I know that you can use proxy to add metadata to 
objects that you create but in my case the object already exists (i.e. it is 
returned from another method call outside of my control).

It seems like the best solution would be to create a delegate class/object that 
wraps the original one.  Being able to write something like this would be ideal:

(defn wrap-with-meta
  ([obj]
 (wrap-with-meta obj nil))
  ([obj meta]
   (delegate obj
 clojure.lang.IObj
 (withMeta [this new-meta] (wrap-with-meta obj  

new-meta))
 (meta [this] meta

The delegate function would operate very similar to proxy, but instead of 
taking a class it takes an object.  A class would be created that extends the 
object's class, just like a class is generated for proxy. However, instead of 
stubs being generated that call super the stubs would delegate to the given 
object.  (Also note, I am also using reify-like syntax since I prefer that to 
the syntax in proxy.)

I'm curious to hear people's thoughts on this approach.  I'd also be really 
interested to see how other people have addressed this in the past (I doubt I'm 
the first one to run into this).

I know that clojure mentality is to avoid wrappers, but I don't see this as 
being much different than what proxy already does.  Of course, I may be missing 
something... if so, please enlighten me. :)

Thanks,
Ben

--
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 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


Re: adding metadata to java objects

2011-11-17 Thread Chas Emerick
Ben,

It's a good idea, but it's going to bite you:

- what if the class in question has fields or package-private methods that are 
touched by Java code?
- what if the class take ctor arguments?
- what if the ctor has side effects?

- Chas

On Nov 16, 2011, at 11:28 AM, Ben Mabey wrote:

> Hi,
> I would like to be able to add metadata to arbitrary java objects that have 
> already been instantiated.  I know that you can use proxy to add metadata to 
> objects that you create but in my case the object already exists (i.e. it is 
> returned from another method call outside of my control).
> 
> It seems like the best solution would be to create a delegate class/object 
> that wraps the original one.  Being able to write something like this would 
> be ideal:
> 
> (defn wrap-with-meta
>  ([obj]
> (wrap-with-meta obj nil))
>  ([obj meta]
>   (delegate obj
> clojure.lang.IObj
> (withMeta [this new-meta] (wrap-with-meta obj 
>   
>
> new-meta))
> (meta [this] meta
> 
> The delegate function would operate very similar to proxy, but instead of 
> taking a class it takes an object.  A class would be created that extends the 
> object's class, just like a class is generated for proxy. However, instead of 
> stubs being generated that call super the stubs would delegate to the given 
> object.  (Also note, I am also using reify-like syntax since I prefer that to 
> the syntax in proxy.)
> 
> I'm curious to hear people's thoughts on this approach.  I'd also be really 
> interested to see how other people have addressed this in the past (I doubt 
> I'm the first one to run into this).
> 
> I know that clojure mentality is to avoid wrappers, but I don't see this as 
> being much different than what proxy already does.  Of course, I may be 
> missing something... if so, please enlighten me. :)
> 
> Thanks,
> Ben
> 
> -- 
> 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 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


Re: adding metadata to java objects

2011-11-17 Thread Chas Emerick

On Nov 17, 2011, at 1:01 AM, Ben Smith-Mannschott wrote:

>> (def o (Object.))
>> 
>> (def om (with-meta* o {:foo true}))
>> 
>> (def whatever (with-meta* o {:foo false}))
>> 
>> (meta* om) ;=> {:foo false}
>> 
>> Doesn't really support Clojure's concept of metadata if it's shared
>> global mutable state.
> 
> Yes, that's true. Though it wouldn't occur to me to expect some random
> POJO to behave as if it were persistent WRT metadata. POJOs generally
> conflate state and identity and are mutable. That's life. If that's a
> problem, then you'll need to wrap it in something that supports
> metadata.

Mechanisms like what Ben proposed have been discussed before, but declined for 
core (which is probably a good decision).  However, something is generally 
better than nothing.

meta* isn't clojure.core/meta, so it can have weaker/different semantics 
without apologizing for it, IMO.

- Chas



-- 
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


Re: adding metadata to java objects

2011-11-16 Thread Ben Smith-Mannschott
On Wed, Nov 16, 2011 at 22:32, Alan Malloy  wrote:
> On Nov 16, 11:53 am, Ben Smith-Mannschott 
> wrote:
>> On Wed, Nov 16, 2011 at 17:28, Ben Mabey  wrote:
>> > Hi,
>> > I would like to be able to add metadata to arbitrary java objects that have
>> > already been instantiated.  I know that you can use proxy to add metadata 
>> > to
>> > objects that you create but in my case the object already exists (i.e. it 
>> > is
>> > returned from another method call outside of my control).
>>
>> > It seems like the best solution would be to create a delegate class/object
>> > that wraps the original one.  Being able to write something like this would
>> > be ideal:
>>
>> > (defn wrap-with-meta
>> >  ([obj]
>> >     (wrap-with-meta obj nil))
>> >  ([obj meta]
>> >   (delegate obj
>> >             clojure.lang.IObj
>> >             (withMeta [this new-meta] (wrap-with-meta obj
>>
>> >  new-meta))
>> >             (meta [this] meta
>>
>> > The delegate function would operate very similar to proxy, but instead of
>> > taking a class it takes an object.  A class would be created that extends
>> > the object's class, just like a class is generated for proxy. However,
>> > instead of stubs being generated that call super the stubs would delegate 
>> > to
>> > the given object.  (Also note, I am also using reify-like syntax since I
>> > prefer that to the syntax in proxy.)
>>
>> > I'm curious to hear people's thoughts on this approach.  I'd also be really
>> > interested to see how other people have addressed this in the past (I doubt
>> > I'm the first one to run into this).
>>
>> > I know that clojure mentality is to avoid wrappers, but I don't see this as
>> > being much different than what proxy already does.  Of course, I may be
>> > missing something... if so, please enlighten me. :)
>>
>> > Thanks,
>> > Ben
>>
>> Here's an approach that may be of use: don't store the metadata in a
>> Map instead of decorating the Object with it. This map should use
>> object identity, not equality and should hold its keys weakly so that
>> it prevent collection of  objects that otherwise would be garbage.
>> Safe to use concurrently would also be a plus. Conveniently, Google's
>> Guava library provides such a thing. Here's a sketch:
>>
>> == project.clj 
>>
>> (defproject pojometa "0.0.1-SNAPSHOT"
>>   :dependencies [[org.clojure/clojure "1.3.0"]
>>                  [com.google.guava/guava "10.0.1"]])
>>
>> == src/pojometa/core.clj ==
>>
>> (ns pojometa.core
>>     (:import [com.google.common.collect MapMaker]))
>>
>> (def meta-map
>>     (-> (MapMaker.) .weakKeys .makeMap))
>>
>> (defn meta* [o]
>>     (if (instance? clojure.lang.IMeta o)
>>         (clojure.core/meta o)
>>         (.get meta-map o)))
>>
>> (defn with-meta* [o m]
>>     (if (instance? clojure.lang.IMeta o)
>>         (clojure.core/with-meta o m)
>>         (do (.put meta-map o m)
>>             o)))
>>
>> == usage ==
>>
>> pojometa.core=> (def o (Object.)) ;; arbitrary java object
>> pojometa.core=> (meta* (with-meta* o {:foo true}))
>> {:foo true}
>>
>> ;; also "does the right thing" for Clojure types that
>> ;; already know how to have metadata.
>>
>> pojometa.core=> (meta* (with-meta* {} {:bar 1}))
>> {:bar 1}
>
> (def o (Object.))
>
> (def om (with-meta* o {:foo true}))
>
> (def whatever (with-meta* o {:foo false}))
>
> (meta* om) ;=> {:foo false}
>
> Doesn't really support Clojure's concept of metadata if it's shared
> global mutable state.

Yes, that's true. Though it wouldn't occur to me to expect some random
POJO to behave as if it were persistent WRT metadata. POJOs generally
conflate state and identity and are mutable. That's life. If that's a
problem, then you'll need to wrap it in something that supports
metadata.

// ben

-- 
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


Re: adding metadata to java objects

2011-11-16 Thread Alan Malloy
On Nov 16, 11:53 am, Ben Smith-Mannschott 
wrote:
> On Wed, Nov 16, 2011 at 17:28, Ben Mabey  wrote:
> > Hi,
> > I would like to be able to add metadata to arbitrary java objects that have
> > already been instantiated.  I know that you can use proxy to add metadata to
> > objects that you create but in my case the object already exists (i.e. it is
> > returned from another method call outside of my control).
>
> > It seems like the best solution would be to create a delegate class/object
> > that wraps the original one.  Being able to write something like this would
> > be ideal:
>
> > (defn wrap-with-meta
> >  ([obj]
> >     (wrap-with-meta obj nil))
> >  ([obj meta]
> >   (delegate obj
> >             clojure.lang.IObj
> >             (withMeta [this new-meta] (wrap-with-meta obj
>
> >  new-meta))
> >             (meta [this] meta
>
> > The delegate function would operate very similar to proxy, but instead of
> > taking a class it takes an object.  A class would be created that extends
> > the object's class, just like a class is generated for proxy. However,
> > instead of stubs being generated that call super the stubs would delegate to
> > the given object.  (Also note, I am also using reify-like syntax since I
> > prefer that to the syntax in proxy.)
>
> > I'm curious to hear people's thoughts on this approach.  I'd also be really
> > interested to see how other people have addressed this in the past (I doubt
> > I'm the first one to run into this).
>
> > I know that clojure mentality is to avoid wrappers, but I don't see this as
> > being much different than what proxy already does.  Of course, I may be
> > missing something... if so, please enlighten me. :)
>
> > Thanks,
> > Ben
>
> Here's an approach that may be of use: don't store the metadata in a
> Map instead of decorating the Object with it. This map should use
> object identity, not equality and should hold its keys weakly so that
> it prevent collection of  objects that otherwise would be garbage.
> Safe to use concurrently would also be a plus. Conveniently, Google's
> Guava library provides such a thing. Here's a sketch:
>
> == project.clj 
>
> (defproject pojometa "0.0.1-SNAPSHOT"
>   :dependencies [[org.clojure/clojure "1.3.0"]
>                  [com.google.guava/guava "10.0.1"]])
>
> == src/pojometa/core.clj ==
>
> (ns pojometa.core
>     (:import [com.google.common.collect MapMaker]))
>
> (def meta-map
>     (-> (MapMaker.) .weakKeys .makeMap))
>
> (defn meta* [o]
>     (if (instance? clojure.lang.IMeta o)
>         (clojure.core/meta o)
>         (.get meta-map o)))
>
> (defn with-meta* [o m]
>     (if (instance? clojure.lang.IMeta o)
>         (clojure.core/with-meta o m)
>         (do (.put meta-map o m)
>             o)))
>
> == usage ==
>
> pojometa.core=> (def o (Object.)) ;; arbitrary java object
> pojometa.core=> (meta* (with-meta* o {:foo true}))
> {:foo true}
>
> ;; also "does the right thing" for Clojure types that
> ;; already know how to have metadata.
>
> pojometa.core=> (meta* (with-meta* {} {:bar 1}))
> {:bar 1}

(def o (Object.))

(def om (with-meta* o {:foo true}))

(def whatever (with-meta* o {:foo false}))

(meta* om) ;=> {:foo false}

Doesn't really support Clojure's concept of metadata if it's shared
global mutable state.

-- 
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


Re: adding metadata to java objects

2011-11-16 Thread Ben Smith-Mannschott
On Wed, Nov 16, 2011 at 17:28, Ben Mabey  wrote:
> Hi,
> I would like to be able to add metadata to arbitrary java objects that have
> already been instantiated.  I know that you can use proxy to add metadata to
> objects that you create but in my case the object already exists (i.e. it is
> returned from another method call outside of my control).
>
> It seems like the best solution would be to create a delegate class/object
> that wraps the original one.  Being able to write something like this would
> be ideal:
>
> (defn wrap-with-meta
>  ([obj]
>     (wrap-with-meta obj nil))
>  ([obj meta]
>   (delegate obj
>             clojure.lang.IObj
>             (withMeta [this new-meta] (wrap-with-meta obj
>
>
>  new-meta))
>             (meta [this] meta
>
> The delegate function would operate very similar to proxy, but instead of
> taking a class it takes an object.  A class would be created that extends
> the object's class, just like a class is generated for proxy. However,
> instead of stubs being generated that call super the stubs would delegate to
> the given object.  (Also note, I am also using reify-like syntax since I
> prefer that to the syntax in proxy.)
>
> I'm curious to hear people's thoughts on this approach.  I'd also be really
> interested to see how other people have addressed this in the past (I doubt
> I'm the first one to run into this).
>
> I know that clojure mentality is to avoid wrappers, but I don't see this as
> being much different than what proxy already does.  Of course, I may be
> missing something... if so, please enlighten me. :)
>
> Thanks,
> Ben

Here's an approach that may be of use: don't store the metadata in a
Map instead of decorating the Object with it. This map should use
object identity, not equality and should hold its keys weakly so that
it prevent collection of  objects that otherwise would be garbage.
Safe to use concurrently would also be a plus. Conveniently, Google's
Guava library provides such a thing. Here's a sketch:

== project.clj 

(defproject pojometa "0.0.1-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.3.0"]
 [com.google.guava/guava "10.0.1"]])

== src/pojometa/core.clj ==

(ns pojometa.core
(:import [com.google.common.collect MapMaker]))

(def meta-map
(-> (MapMaker.) .weakKeys .makeMap))

(defn meta* [o]
(if (instance? clojure.lang.IMeta o)
(clojure.core/meta o)
(.get meta-map o)))

(defn with-meta* [o m]
(if (instance? clojure.lang.IMeta o)
(clojure.core/with-meta o m)
(do (.put meta-map o m)
o)))

== usage ==

pojometa.core=> (def o (Object.)) ;; arbitrary java object
pojometa.core=> (meta* (with-meta* o {:foo true}))
{:foo true}

;; also "does the right thing" for Clojure types that
;; already know how to have metadata.

pojometa.core=> (meta* (with-meta* {} {:bar 1}))
{:bar 1}

== END

Hope that helps,
Ben

-- 
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


adding metadata to java objects

2011-11-16 Thread Ben Mabey

Hi,
I would like to be able to add metadata to arbitrary java objects that 
have already been instantiated.  I know that you can use proxy to add 
metadata to objects that you create but in my case the object already 
exists (i.e. it is returned from another method call outside of my control).


It seems like the best solution would be to create a delegate 
class/object that wraps the original one.  Being able to write something 
like this would be ideal:


(defn wrap-with-meta
  ([obj]
 (wrap-with-meta obj nil))
  ([obj meta]
   (delegate obj
 clojure.lang.IObj
 (withMeta [this new-meta] (wrap-with-meta 
obj  
new-meta))

 (meta [this] meta

The delegate function would operate very similar to proxy, but instead 
of taking a class it takes an object.  A class would be created that 
extends the object's class, just like a class is generated for proxy. 
However, instead of stubs being generated that call super the stubs 
would delegate to the given object.  (Also note, I am also using 
reify-like syntax since I prefer that to the syntax in proxy.)


I'm curious to hear people's thoughts on this approach.  I'd also be 
really interested to see how other people have addressed this in the 
past (I doubt I'm the first one to run into this).


I know that clojure mentality is to avoid wrappers, but I don't see this 
as being much different than what proxy already does.  Of course, I may 
be missing something... if so, please enlighten me. :)


Thanks,
Ben

--
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