gen-class and state...

107 views
Skip to first unread message

Jules

unread,
Mar 23, 2011, 3:43:54 AM3/23/11
to Clojure
I only have a brief posting window this morning (I have to leave for
work) so have not researched this as well as I should before coming to
the list - so please forgive if this is a bit lame...

Should I still be using gen-class to achieve link time compatibility
with Java ?

If so, why am I constrained to using a single field to hold my state
(.state) ? (or have I missed something?).

I am finding that all my gen-class-ed types need to define themselves,
as well as a structure for their immutable parts and a structure for
their mutable parts. Every method invocation involves at least two
lookups one to fetch the immutable part from the .state field and one
to lookup some useful piece of data in it.

I'd like to reduce this to one lookup, directly into an immutable
field in the POJO.

Why doesn't gen-class allow e.g. :state [^Integer i ^String s ....] in
a more record like way ? and perhaps a flag to indicate that I want it
to inherit the necessary fn-ality such that I can dereference fields
in it in the same way as in a record ?

It may be that I am using an out of date way of achieving my goals -
I'd appreciate some guidance either way ? I am aware of e.g.
defprotocol and reify but am under the impression that they are for
dynamic typing creation and will not give me link-time compatibility
with the Java code in my project ?

thanks for your time,

Jules

Ken Wesson

unread,
Mar 23, 2011, 4:18:14 AM3/23/11
to clo...@googlegroups.com
On Wed, Mar 23, 2011 at 3:43 AM, Jules <jules....@gmail.com> wrote:
> I only have a brief posting window this morning (I have to leave for
> work) so have not researched this as well as I should before coming to
> the list - so please forgive if this is a bit lame...
>
> Should I still be using gen-class to achieve link time compatibility
> with Java ?
>
> If so, why am I constrained to using a single field to hold my state
> (.state) ? (or have I missed something?).
>
> I am finding that all my gen-class-ed types need to define themselves,
> as well as a structure for their immutable parts and a structure for
> their mutable parts. Every method invocation involves at least two
> lookups one to fetch the immutable part from the .state field and one
> to lookup some useful piece of data in it.
>
> I'd like to reduce this to one lookup, directly into an immutable
> field in the POJO.

If you're implementing an interface, you can use deftype to create
objects with multiple mutable and immutable fields and with methods
corresponding to that interface.

And you can use definterface to make an interface. You don't even have
to call the objects via the interface. :)

Stuart Sierra

unread,
Mar 23, 2011, 8:20:59 PM3/23/11
to clo...@googlegroups.com, Jules
Ahead-of-time compiled (AOT) code with `defprotocol` and `defrecord` creates interfaces and classes you can access from Java.  You don't need gen-class, which is usually only necessary for "public static void main" methods and edge-case Java interop problems.

I wrote about this on IBM developerWorks: http://www.ibm.com/developerworks/java/library/j-clojure-protocols/#N1058C

-Stuart Sierra
clojure.com

Jules

unread,
Mar 24, 2011, 5:34:29 AM3/24/11
to clo...@googlegroups.com, Jules
Guys,

Thanks for your replies - I'm glad I posted as this is exactly what I was looking for. I wish I had found Stuart's article when he wrote it. I had an inkling that my gen-class struggles were out of date - now I can go and rework all that code :-)

Problem solved.

Thanks again,

Jules

Ulises

unread,
Mar 24, 2011, 5:40:04 AM3/24/11
to clo...@googlegroups.com
Sorry for hijacking but I wouldn't mind some clarification on the subject.

Right now I can get java classes and interfaces with defprotocol and
defrecord and the world is good.

Can somebody please educate me in the uses/needs for :gen-class and friends?

Keep in mind that I haven't really done much Java interop so my
question may indeed be a silly one.

Cheers!

U

Meikel Brandmeyer

unread,
Mar 24, 2011, 5:45:21 AM3/24/11
to Clojure
Hi,

On 24 Mrz., 10:40, Ulises <ulises.cerv...@gmail.com> wrote:

> Can somebody please educate me in the uses/needs for :gen-class and friends?

You need gen-class when you want (or have to) derive from another
class. defrecord/deftype/reify don't allow that, while gen-class/proxy
do.

Sincerely
Meikel

Ulises

unread,
Mar 24, 2011, 5:50:30 AM3/24/11
to clo...@googlegroups.com
> You need gen-class when you want (or have to) derive from another
> class. defrecord/deftype/reify don't allow that, while gen-class/proxy
> do.

I suppose this is for when you want to add fields to an already
existing class? (I'm assuming that adding methods could be done with
extend/extend-protocol?)

U

Jules

unread,
Mar 24, 2011, 1:13:43 PM3/24/11
to clo...@googlegroups.com, Jules
Stuart,

I still think in a very OO way - which is probably why I am having difficulty with this :-)

A common OO pattern is to encapsulate complex resource acquisition/release within a class.

I can do this with gen-class - since I control ctor args and the instances initial state, as well as having post-init for when some part of my initialisation requires a reference to itself.

I'm guessing that I can't do this with deftype/reify - so this might be another reason to fall back on gen-class ?

[although I could leave space for an atom in my state and provide ctor/dtor fns which read/wrote this atom... - so I suppose this would be one way around the problem,,,]

Would you mind clarifying ?

Thanks

Jules

Stuart Sierra

unread,
Mar 24, 2011, 4:44:50 PM3/24/11
to clo...@googlegroups.com
 A typical pattern for resource management is a function or macro like `with-open-file`.

-S

Jules

unread,
Mar 25, 2011, 5:22:25 AM3/25/11
to clo...@googlegroups.com
yes

and that's great where the resource usage is scoped on a per-thread basis, but not a per-object basis - but then, I am thinking in OO terms again :-)

Jules

Stefan Sigurdsson

unread,
Mar 27, 2011, 6:17:59 AM3/27/11
to clo...@googlegroups.com, Jules
How do you guys normally manage resources when using lazy sequences?

I was playing around with this question, and I looked into extending line-seq to take a file path parameter that is coerced to reader:

    (defn line-seq
        ([^java.io.BufferedReader rdr]
            (when-let [line (.readLine rdr)]
                (cons line (lazy-seq (line-seq rdr)))))
        ([^String path]
            (line-seq (clojure.java.io/reader path))))   ;   Oops

This sort of works, but not well, because we're relying on finalize to close the reader.

(If the extended line-seq is being used by code that opens a lot of files, but reads all it needs from each file before moving on, then we'd only have one live file handle at any given time, but we could exhaust the number of concurrently available file handles before the garbage collector catches up.)

Instead the extended line-seq needs to control the closing of the reader it opens, but that reader needs to remain open until the last sequence element has been consed - which is normally long after the extended line-seq returns.

The normal Clojure-style with-open approach doesn't work at all since the reader is closed after reading the first line, and we can't read any of the remaining lines:

    (defn line-seq
        ([^java.io.BufferedReader rdr]
            (when-let [line (.readLine rdr)]
                (cons line (lazy-seq (line-seq rdr))))))
        ([^String filename]
            (with-open [rdr (clojure.java.io/reader filename)]   ;   Oops...
                (line-seq rdr))))

Closing the reader explicitly when the file has been read fixes the extended line-seq but would
 break other applications that rely on the original line-seq:

    (defn line-seq
        ([^java.io.BufferedReader rdr]
            (if-let [line (.readLine rdr)]
                (cons line (lazy-seq (line-seq rdr)))
                (.close rdr)))   ;   Ouch
        ([^String filename]
            (line-seq (clojure.java.io/reader filename)))

Adding another overload seems to be the most reasonable solution:

    (defn line-seq
        ([^java.io.BufferedReader rdr]
            (line-seq rdr (fn [rdr] (.readLine rdr))))
        ([^java.io.BufferedReader rdr extract]
            (when-let [line (extract rdr)]
                (cons line (lazy-seq (line-seq rdr)))))
        ([^String filename]
            (let [extract (fn [rdr] (if-let [line (.readLine rdr)] line (.close rdr))
                (line-seq (clojure.java.io/reader filename) extract)))

But this feels a little cumbersome. Am I missing something? Is there a better way?

(I'm just using line-seq for illustration here.)

Cheers,

Stefan
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@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
For more options, visit this group at

Stefan Sigurdsson

unread,
Mar 27, 2011, 6:58:14 AM3/27/11
to clo...@googlegroups.com, Jules
Aieh, I oversimplified a bit here, and forgot about not being able to overload with the same arity, without multimethods. 

Here is the actual code I was experimenting with, which actually runs... 

(defn- read-seq-
  [reader extract advance]
  (let [segment (extract reader)
        reader (advance reader)]
    (if segment
        (cons segment (lazy-seq (read-seq- reader extract advance))))))

(defmulti read-seq (fn [source & more] (class source)))

(defmethod read-seq clojure.lang.ISeq
  ([reader]
   (read-seq reader (fn [reader] (first reader))))
  ([reader extract]
   (read-seq reader extract (fn [reader] (next reader))))
  ([reader extract advance]
   (read-seq- reader extract advance)))

(defmethod read-seq java.io.BufferedReader 
  ([reader]
   (read-seq reader (fn [reader] (. reader readLine))))
  ([reader extract]
   (read-seq reader extract (fn [reader] reader)))
  ([reader extract advance]
    (read-seq- reader extract advance)))

(defmethod read-seq String
  [path]
  (let [reader (clojure.java.io/reader path)]
    (read-seq reader 
      (fn [reader] 
        (let [segment (. reader readLine)]
          (if segment segment (. reader close)))))))

Jules

unread,
Mar 28, 2011, 7:50:57 AM3/28/11
to Clojure
So I have come up with a solution to my desire to move to defprotocol/
type in spite of my requirement for gen-class' init/post-init
methods :

(def protocol Resource
(open [this])
(close [this])
...
)

(deftype ResourceImpl [resource]
Resource
(open [this]...)
(close [this] (.close resource)...)
....)

(defn init-resource-impl [path]
(ResourceImpl (acquire-resource path)))

Use an aux fn as a ctor/init (init-resource-impl) - this gives you the
opportunity to take a few params from upstream and acquire necessary
resources to inject into your new types ctor. The contract between
init-fn and type is that the type takes ownership of all resources
acquired within the fn and is responsible for tidying them up when
they are finished with.

Post-init fn-ality (which needs a self-reference) may be done in a
method - in this case open(). If you are in the unfortunate
circumstance where post-init also needs to mutate your instance's
state, then you will have to leave an atom placeholder in the type def
and inject an atom in your init fn.

I can tidy up using another method - close() - if this needs to mutate
state then you will need to hold this in an atom as above.

The advantage (for me) of doing this over using gen-class is that my
code is much simpler to write as I do not have to manage all state
explicitly anymore.

I'm having a little trouble type-hinting etc but am hoping that I can
figure it all out.

Hope this helps anyone who finds themselves in the same position as
myself :-)


Jules

Stuart Sierra

unread,
Mar 30, 2011, 5:29:09 PM3/30/11
to clo...@googlegroups.com


On Sunday, March 27, 2011 6:17:59 AM UTC-4, Stefan Sigurdsson wrote:
How do you guys normally manage resources when using lazy sequences?


You have to manage resources at a larger scope that encompasses all your use of the lazy sequence.  The quick-and-dirty solution is to use `doall` inside `with-open`.  The more refined solution is to have a resource manager that controls when resources get cleaned up.  This has been discussed as a possible language feature called "scopes."  After countless discussions, no one on the Clojure/core team has been able to come up with a comprehensive description of what scopes are, much less how to implement them.

-Stuart Sierra
clojure.com
Reply all
Reply to author
Forward
0 new messages