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