To that excellent analysis I would add that, if you're going to iterate through a whole collection, it's much more efficient to call seq on it at the outset, and then use (next s) to progress through the seq; (next s) returns nil when there are no more elements, and is semantically equivalent to (seq (rest s)) but much more efficient (both in characters of source code and at runtime).
On Sun, May 26, 2013 at 6:47 AM, Alex L. <alexander.lo...@gmail.com> wrote: > Hello, > > I just wanted to share the following piece from The Joy of > Clojure<http://www.amazon.com/The-Joy-Clojure-Thinking-Way/dp/1935182641/ref=sr_1_2?ie=UTF8&qid=1369564691&sr=8-2&keywords=the+joy+of+clojure>, > *Chapter 3, page 45*, since I found it interesting and it might be > valuable to the thread: > > *3.2* > * > * > *Nil pun with care* > *Because empty collections act like true in Boolean contexts, we need an > idiom for* > *testing whether there’s anything in a collection to process. Thankfully, > Clojure pro* > *vides just such a technique:* > *(seq [1 2 3])* > * > * > *;=> (1 2 3)* > * > * > *(seq [])* > * > * > *;=> nil* > * > * > *The seq function returns a sequence view of a collection, or nil if the > collection is* > *empty. In a language like Common Lisp, an empty list acts as a false > value and can be* > *used as a pun (a term with the same behavior) for such in determining a > looping ter* > *mination. As you saw in section 2.3, Clojure’s empty sequences are > instead truthy, and* > *therefore to use one as a pun for falsity will lead to heartache and > despair. One solu* > *tion that might come to mind is to use empty? in the test, leading to > the awkward* > *phrase (when-not (empty? s) ...). Though it would work, this isn’t > idiomatic. A* > *better solution would be to use seq as a termination condition, as in > the following* > *function print-seq:* > * > * > *(defn print-seq [s]* > * (when (seq s)* > * (prn (first s))* > *(recur (rest s))))* > * > * > *(print-seq [1 2])* > *; 1* > *; 2* > *;=> nil* > * > * > *(print-seq [])* > *;=> nil* > * > * > *There are a number of points to take away from this example. First, the > use of seq as a* > *terminating condition is the idiomatic way to test whether a sequence is > empty. If we* > *tested just s instead of (seq s), then the terminating condition > wouldn’t occur even* > *for empty collections, leading to an infinite loop.* > > Regards, > > Alexander > > On Tuesday, May 14, 2013 7:26:20 AM UTC+3, Mike Thvedt wrote: >> >> In regards to the allocation objection--how often are you calling seq >> millions of times on something that's not already a seq? In re using count >> instead of seq, a lazy seq's count might be arbitrarily expensive to >> calculate and might not be able to tell if it's empty without realizing its >> head. >> >> On Monday, May 13, 2013 4:21:54 AM UTC-5, Meikel Brandmeyer (kotarak) >> wrote: >>> >>> >>> 2013/5/13 Mike Thvedt <cynic...@gmail.com> >>> >>>> A good implementation of ISeq won't return a new object, and new >>>> short-lived objects are cheap on the JVM anyway. OTOH count can be slow for >>>> some data structures. if you don't like instantiating lots of new objects >>>> only to throw them away, you're missing out on one of HotSpot's most >>>> significant performance/convenience sweet spots, so it's strange you call >>>> that premature optimization. >>>> >>>> There is however an optimization story against seq: Hotspot (at least >>>> on my machine) refuses to inline the call to seq by default (it might still >>>> inline if the stars are right or something, the JVM is mysterious). My >>>> guess is it's because the code in seq and seqFrom is too big, on my box it >>>> exceeds the inline threshold by one byte... >>>> >>>> >>> I'm not sure what you mean. For an ISeq seq won't return a new object. >>> But for everything else it will. And count is cheap (a simple field >>> access) for clojure data structures (a seq is not a data structure). While >>> initialising an immediately-to-be-thrown-away object might be (relatively) >>> expensive even when allocation is cheap. >>> >>> I called my point of view "premature optimisation" because it's probably >>> like you said: allocation is cheap and initialisation usually not worth >>> worrying about. So worrying about it is "premature optimisation". >>> >>> I still feel empty? to be too ugly in its current implementation. (And >>> to be honest: I almost never needed it, up to now...) >>> >>> 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 > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/groups/opt_out. > > > -- -- 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 unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.