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

Reply via email to