Welcome! Please see the About page for a little more info on how this works.

0 votes
in Collections by
Even if underlying seq contains a cached hash, LazySeq computes it every time.


user=> *clojure-version*
{:major 1, :minor 7, :incremental 0, :qualifier "master", :interim true}
user=> (def a (range 100000))
#'user/a
user=> (time (hash a))
"Elapsed time: 21.812 msecs"
375952610
user=> (time (hash a))        ;; hash is cached
"Elapsed time: 0.036 msecs"
375952610
user=> (def b (seq a))
#'user/b
user=> (time (hash b))
"Elapsed time: 0.042 msecs"   ;; uses cached hash
375952610
user=> (def c (lazy-seq b))
#'user/c
user=> (time (hash c))        ;; SHOULD use underlying hash
"Elapsed time: 27.758 msecs"
375952610
user=> (time (hash c))        ;; SHOULD use underlying hash
"Elapsed time: 17.846 msecs"
375952610


*Approach:* If seq produced by LazySeq implementing IHashEq, use it to calculate the hasheq().
*Patch:* clj-1373.diff

5 Answers

0 votes
by

Comment made by: wagjo

Added patch which checks if underlying seq implements IHashEq and if yes, uses that hash instead of recomputing.

0 votes
by

Comment made by: alexmiller

In this patch, can you update the else case (the original code) to use s rather than this, so seq() is not re-called?

0 votes
by

Comment made by: wagjo

Added patch (link: ^clj-1373-2.diff) that reuses {{s}} for else case.

0 votes
by

Comment made by: alexmiller

The -2 patch doesn't compile so I guess that was a bad suggestion. :)

0 votes
by
Reference: https://clojure.atlassian.net/browse/CLJ-1373 (reported by wagjo)
...