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.