Funny, I posted an article of my Clojure gotcha's today 
(http://www.russet.org.uk/blog/2991), and this is one of them. I've also had 
very nasty bugs, in addition to the general hassle of wrapping a Java API which 
works through side-effects.

I created a few functions covering the most common ones (domap, dofor and so 
on); having a comprehensive list somewhere in it's own namespace would be quite 
useful.

Phil
________________________________________
From: clojure@googlegroups.com [clojure@googlegroups.com] on behalf of Lee 
Spector [lspec...@hampshire.edu]
Sent: 02 June 2014 21:32
To: clojure@googlegroups.com
Subject: non-lazy clojure?

I've generally liked Clojure's pervasive laziness. It's cute and it sometimes 
permits lovely, elegant approaches to particular programming problems. And 
although I've long known that it can get you into trouble in a few unusual 
cases -- I think I recall seeing a nice blog post on issues related to 
"binding" and laziness by Chas Emerick several years ago -- it has generally 
seemed safe enough for most purposes. I figured that while it may not always 
provide benefits it should at least be mostly harmless.

However, after spending a couple of days tracking down a particularly confusing 
bug, and finding once again (this has happened to me at least a few times) that 
the bug was due to laziness that I never really wanted in the first place, I'm 
reconsidering.

I don't have a pared-down version of the bug that I was just dealing with (see 
below for a pointer to the non-pared-down version), but it goes away when I 
wring out all of the laziness. In this particular case I do so by calling vec 
or doall on the results of all of my calls to map and other functions function 
that produce lazy sequences (none of which I actually want to be lazy in this 
application). I was getting StackOverflowErrors and I have a half-baked 
half-theory that it was due to some bad interaction between laziness and 
garbage collection, with the JVM not realizing that it could reclaim lazy 
things that weren't yet fully evaluated. That doesn't make complete sense to 
me, and maybe that kind of bad interaction is not even possible -- I don't 
know. But I do know that all is well when I wring out all of the laziness.

One possible lesson from this experience (which was particularly frustrating, 
BTW, because the stack backtraces were particularly uninformative [1]) is that 
I should just be careful to surround any call to any function that produces a 
lazy sequence with something like vec that ensures that the laziness will be 
eliminated as soon as it is created -- except in those relatively rare cases 
where I really want the laziness. But this would be a pain, and ugly. I rely 
heavily on Clojure's sequence processing functions and I would hate to clutter 
up every call to every one of them or to have to reimplement my own non-lazy 
versions of everything.

Is there a more elegant way? Maybe somebody has already made non-lazy clones of 
all of the core functions that normally produce lazy sequences? And if so, 
maybe there's some clean way to cause my code to use the non-lazy versions 
unless specifically directed to use the lazy versions?

I realize that this is fighting with a core feature of Clojure, and that the 
idea will probably rub lots of folks the wrong way. But I've now been down this 
road a couple of times and I'm beginning to think that I'd spend less time 
tracking down mysterious bugs if I could avoid laziness more easily.

In case anybody is motivated to look into the specific bug that I was just 
dealing with, I've put the project at 
http://hampshire.edu/lspector/temp/world2D.zip. If you do "lein run" in its 
present state it will run fine, making little balls bounce around. (This is a 
very early version of some code that I plan to use both for teaching an AI 
class and for some ALife experiments...) But if you edit src/world2D/vec2D.clj, 
commenting out the definitions of *v, +v, and -v, and uncommenting the 
alternatives (which are the same except that they lack the calls to vec) then 
after running for a few seconds or a minute or so you'll get the stack overflow.

Thanks for any suggestions,

 -Lee


[1] The stack traces I was getting provide no information about where/what the 
offending lazy sequences are, since they don't show locals etc. I see no 
references to any of my own code, just a repeating sequence that starts:

StackOverflowError
        clojure.core/seq (core.clj:133)
        clojure.core/map/fn--4211 (core.clj:2490)
        clojure.lang.LazySeq.sval (LazySeq.java:42)
        clojure.lang.LazySeq.seq (LazySeq.java:60)
        clojure.lang.RT.seq (RT.java:484)
        clojure.core/seq (core.clj:133)
        clojure.core/map/fn--4211 (core.clj:2490)
        clojure.lang.LazySeq.sval (LazySeq.java:42)
        clojure.lang.LazySeq.seq (LazySeq.java:60)
        clojure.lang.RT.seq (RT.java:484)
[etc]

--
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/d/optout.

-- 
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/d/optout.

Reply via email to