In the lazy branch, empty sequences don't always evaluate as false in a boolean context. Tracking down places you've made this assumption can be hard. Attached is a patch that helps by providing a flag, assert-if-lazy-seq.
When this flag is on, 'if' is replaced with a new (slower) version that throws an exception if you're using a lazy-seq as the test expression. This is almost always an error in the lazy branch, and usually just requires wrapping the lazy-seq in a call to 'seq', as has been discussed elsewhere. To turn on the flag you need to rebuild clojure with an extra option, like this: ant -Dclojure.assert-if-lazy-seq=please Any non-empty string will do for the value. You will need to set the value at runtime as well. There may be a way to avoid this, but I haven't thought of how. So for now you'll want at the top of your code: (reset! *assert-if-lazy-seq* true) Now anytime you try to use nil punning, you should get an exception. user=> (when (filter neg? [1 2]) :all-pos) java.lang.Exception: LazySeq used in 'if' (NO_SOURCE_FILE:0) user=> (not (concat)) java.lang.Exception: LazySeq used in 'if' (NO_SOURCE_FILE:0) --Chouser --~--~---------~--~----~------------~-------~--~----~ 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 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 -~----------~----~----~----~------~----~------~--~---
commit b0cec18fb925510502352d8fdcc0a4b93b28bd72 Author: Chouser <chou...@n01se.net> Date: Fri Feb 13 13:02:30 2009 -0500 Add assert-if-lazy-seq diff --git a/branches/lazy/build.xml b/branches/lazy/build.xml index 04583ba..bc5fcc7 100644 --- a/branches/lazy/build.xml +++ b/branches/lazy/build.xml @@ -11,6 +11,7 @@ <property name="build" location="classes"/> <property name="clojure_jar" location="clojure.jar"/> <property name="slim_jar" location="clojure-slim.jar"/> + <property name="clojure.assert-if-lazy-seq" value=""/> <target name="init" depends="clean"> <tstamp/> @@ -28,6 +29,7 @@ <java classname="clojure.lang.Compile" classpath="${build}:${cljsrc}"> <sysproperty key="clojure.compile.path" value="${build}"/> + <sysproperty key="clojure.assert-if-lazy-seq" value="${clojure.assert-if-lazy-seq}"/> <arg value="clojure.core"/> <arg value="clojure.main"/> <arg value="clojure.set"/> diff --git a/branches/lazy/src/clj/clojure/core.clj b/branches/lazy/src/clj/clojure/core.clj index eb31005..8f2ec15 100644 --- a/branches/lazy/src/clj/clojure/core.clj +++ b/branches/lazy/src/clj/clojure/core.clj @@ -36,6 +36,10 @@ fn (fn* fn [& decl] (cons 'fn* decl))) (def + #^{:macro true} + if (fn* if [& decl] (cons 'if* decl))) + +(def #^{:arglists '([coll]) :doc "Returns the first item in the collection. Calls seq on its argument. If coll is nil, returns nil."} @@ -291,6 +295,19 @@ (. (var defmacro) (setMacro)) +(def *assert-if-lazy-seq* + (let [x (System/getProperty "clojure.assert-if-lazy-seq")] + (new clojure.lang.Atom (if x (if (.isEmpty x) false true))))) + +(defmacro if [tst & etc] + (if* (.get *assert-if-lazy-seq*) + (let [tstsym 'no-gensym-for-me] + (list 'let [tstsym tst] + (list 'if* (list 'instance? clojure.lang.LazySeq tstsym) + (list 'throw (list 'new Exception "LazySeq used in 'if'")) + (cons 'if* (cons tstsym etc))))) + (cons 'if* (cons tst etc)))) + (defmacro when "Evaluates test. If logical true, evaluates body in an implicit do." [test & body] @@ -1642,7 +1659,7 @@ ([coll] (sort compare coll)) ([#^java.util.Comparator comp coll] - (when (and coll (not (zero? (count coll)))) + (when (seq coll) (let [a (to-array coll)] (. java.util.Arrays (sort a comp)) (seq a))))) diff --git a/branches/lazy/src/clj/clojure/core_proxy.clj b/branches/lazy/src/clj/clojure/core_proxy.clj index 8517e23..edbc78f 100644 --- a/branches/lazy/src/clj/clojure/core_proxy.clj +++ b/branches/lazy/src/clj/clojure/core_proxy.clj @@ -155,7 +155,7 @@ meths (concat (seq (. c (getDeclaredMethods))) (seq (. c (getMethods))))] - (if meths + (if (seq meths) (let [#^java.lang.reflect.Method meth (first meths) mods (. meth (getModifiers)) mk (method-sig meth)] diff --git a/branches/lazy/src/jvm/clojure/lang/Compiler.java b/branches/lazy/src/jvm/clojure/lang/Compiler.java index 664045f..b29876f 100644 --- a/branches/lazy/src/jvm/clojure/lang/Compiler.java +++ b/branches/lazy/src/jvm/clojure/lang/Compiler.java @@ -40,7 +40,7 @@ public class Compiler implements Opcodes{ static final Symbol DEF = Symbol.create("def"); static final Symbol LOOP = Symbol.create("loop*"); static final Symbol RECUR = Symbol.create("recur"); -static final Symbol IF = Symbol.create("if"); +static final Symbol IF = Symbol.create("if*"); static final Symbol LET = Symbol.create("let*"); static final Symbol DO = Symbol.create("do"); static final Symbol FN = Symbol.create("fn*");