Re: gen-class and state...

2011-03-30 Thread Stuart Sierra


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

-- 
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: gen-class and state...

2011-03-28 Thread Jules
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


On Mar 25, 10:22 am, Jules jules.gosn...@gmail.com wrote:
 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

-- 
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: gen-class and state...

2011-03-27 Thread Stefan Sigurdsson
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

On Fri, Mar 25, 2011 at 10:22 AM, Jules jules.gosn...@gmail.com wrote:
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

--
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: gen-class and state...

2011-03-27 Thread Stefan Sigurdsson
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)))



On Sun, Mar 27, 2011 at 12:17 PM, Stefan Sigurdsson ste...@gmail.comwrote:

 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

 On Fri, Mar 25, 2011 at 10:22 AM, Jules jules.gosn...@gmail.com wrote:
 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

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

Re: gen-class and state...

2011-03-24 Thread 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

-- 
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: gen-class and state...

2011-03-24 Thread Ulises
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

-- 
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: gen-class and state...

2011-03-24 Thread Meikel Brandmeyer
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

-- 
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: gen-class and state...

2011-03-24 Thread Ulises
 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

-- 
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: gen-class and state...

2011-03-24 Thread 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

-- 
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: gen-class and state...

2011-03-24 Thread Stuart Sierra
 A typical pattern for resource management is a function or macro like 
`with-open-file`.

-S

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

gen-class and state...

2011-03-23 Thread Jules
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

-- 
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: gen-class and state...

2011-03-23 Thread Ken Wesson
On Wed, Mar 23, 2011 at 3:43 AM, Jules jules.gosn...@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. :)

-- 
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: gen-class and state...

2011-03-23 Thread Stuart Sierra
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

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