Re: gen-class and state...
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...
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 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...
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 wrote: > 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 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...@googlegr
Re: gen-class and state...
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 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...
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...
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
Re: gen-class and state...
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...
> 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...
Hi, On 24 Mrz., 10:40, Ulises 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...
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...
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...
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
Re: gen-class and state...
On Wed, Mar 23, 2011 at 3:43 AM, Jules 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