<< Back to previous view

[CLJ-1731] Transient maps can't be assoc!'d to contain more than 8 elements. Created: 17/May/15  Updated: 17/May/15  Resolved: 17/May/15

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Task Priority: Major
Reporter: Peter Herniman Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: assoc!, transient
Environment:

Linux, Fedora 20
Clojure 1.6.0
OpenJDK 64-Bit Server VM 1.7.0_79-mockbuild_2015_04_15_06_33-b00



 Description   

(let [x (transient {})] (dotimes [i 30] (assoc! x i 0)) (persistent! x))
Will result in

{0 0, 1 0, 2 0, 3 0, 4 0, 5 0, 6 0, 7 0}

instead of the expected 30 element map.

I'm not sure if this is fixed in the most recent version (development) but it doesn't work in 1.6.0.



 Comments   
Comment by Alex Miller [ 17/May/15 6:54 AM ]

This is not correct usage of transient maps. You must use the return value of assoc! for further updates, not bash the same instance. In other words, the update model is the same as with normal maps. There is an outstanding ticket to tweak the docstring slightly to make this clearer.

See a similar example with transient vectors at http://clojure.org/transients.

Comment by Peter Herniman [ 17/May/15 6:23 PM ]

Ah ok, looking at the example on clojure.org clears things up a lot.
I'm not too sure if the docstring does need updating, the tutorial on transients does state that you need to capture the return value explicitly.
Thanks!





[CLJ-1718] (if test then else?) is inconsistent Created: 30/Apr/15  Updated: 05/May/15  Resolved: 30/Apr/15

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Jigen Daisuke Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

MacOS X 10.10.2



 Description   

Issue CLJ-1640 was "fixed" by adding a comment to the documentation.
I think that's not enough, because CLJ-1640 actually points to a major inconsistency.
Just have a look at the following code:

;; I know, the definition of y is bad code, and I would
;; never write such rubish, BUT some people do (e.g. the
;; guys at MS, responsible for the sqljdbc4.jar JDBC
;; driver).
(def y (Boolean. false))

(if (= false y)
(println "that's ok"))

(if y
(println "that's inconsistent, because y is " y
" and we proved it with the above if statement"))



 Comments   
Comment by Alex Miller [ 30/Apr/15 3:25 PM ]

CLJ-1640 was closed by the submitter, no change was made for that.

The decision was made long ago by Clojure to canonicalize on Boolean/FALSE as the false value. We do not plan to make any changes in this regard.

In cases where you are dealing with Java libraries that construct new Boolean instances rather than use the canonical ones, you are responsible for normalizing these values. Please file issues with those libraries as appropriate.

Comment by Andy Fingerhut [ 30/Apr/15 3:41 PM ]

The longish example/article on ClojureDocs.org might contain additional useful info. Even Java recommends against ever using (Boolean. false): http://clojuredocs.org/clojure.core/if

Comment by Jigen Daisuke [ 30/Apr/15 5:08 PM ]

But, if Boolean/FALSE is the false value, shouldn't

(if (= (Boolean. false) false) true false)

better return false?

Comment by Andy Fingerhut [ 30/Apr/15 6:12 PM ]

These all return 2:

(if nil 1 2)
(if false 1 2)
(if Boolean/FALSE 1 2)

clojure.core/=, like Java .equals, returns true when comparing Boolean/FALSE and (Boolean. false). Blame Java.

Comment by Jigen Daisuke [ 05/May/15 4:51 PM ]

@Andy Fingerhut

I know all that, but this doesn't make it any more consistent

See, if they won't fix how "if" treats custom made false-values, the next best
thing to do were to manifest this behaviour of "if" into the "=" function (and
yes, that would mean that "=" isn't a mere ".equals" call anymore, because
Boolean false-values would have to be treated in a special way). But then at
least we would have a consistent system - though not exactly in the way I'd
prefer.

Therefore, I can't blame Java. If they had implemented "if" right in the first place,
everything were fine. So this one is on Clojure.

Comment by Andy Fingerhut [ 05/May/15 5:50 PM ]

I'd like to withdraw the last 2 sentences of my previous comment. I think Alex's comment is the shortest accurate answer: It was a choice in Clojure's implementation to do this. As it is right now, there are some compiled 'if' expressions that compare the test expression against both nil (Java null) and Java Boolean.FALSE, and allowing (Boolean. false) to also be treated as false would either require comparing against a third value, or calling a method like Boolean.valueOf() before doing the comparison. Perhaps a micro-optimization, but seems to me like a reasonable one, given the recommendations in Java not to use the Boolean constructors.





[CLJ-1712] clojure.walk returns a different kv pair Created: 21/Apr/15  Updated: 21/Apr/15  Resolved: 21/Apr/15

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.7
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: James Conroy-Finn Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

In Clojure 1.7, a walk that would result in duplicate keys returns different values. Here is a simple example of the behaviour I'm referring to, that passes with Clojure 1.6, and fails with 1.7:

(ns walk.merge-test
  (:require [clojure.walk :refer [keywordize-keys]]
            [clojure.test :refer :all]))

(deftest test-walk-merge
  (is (= (keywordize-keys {:a 1 "a" 2}) {:a 1})))

I don't know if people are relying on this behaviour in production, and consider it a rather pathological example. Regardless, it would certainly be nice if the behaviour were deterministic.

I've pushed a quick demo up to GitHub to make it easier to verify the behaviour should anyone be interested.

https://github.com/jcf/walk-merge



 Comments   
Comment by Alex Miller [ 21/Apr/15 8:34 AM ]

Because maps are unordered, this code should not be expected to have deterministic results.

Changes in which map type is used are the likely cause of this difference, but the prior behavior was not something you should rely on.

Comment by James Conroy-Finn [ 21/Apr/15 9:38 AM ]

Thanks for the update Alex. I really enjoyed your Clojure/West talk, BTW.





[CLJ-1696] Generating BigInt sequences with range Created: 04/Apr/15  Updated: 06/Apr/15  Resolved: 06/Apr/15

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Paul Roush Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

I'm a relative newcomer to the Clojure language, so this input may cover old ground or be seen as naive. The primary substance is a philosophical question, so the response may be that I'm not thinking about this the "right way".

But, for what it's worth, here is the request.

I found myself in a situation where I wanted 'range' to return a sequence of BigInt's. I naively tried something like (range 5N) and had no luck. Later I found that (range 0N 5) would generate BigInt's rather than Long's.

So my first observation / request is that there are cases where it could be "useful" to be able to generate a sequence of BigInt's with a 1-arity call to range.

The bigger point to me, though, is more a philosophical question of whether the behavior of 'range' is as "consistent" with other core API's as it might be. Obviously, this is very subjective.

My naive thinking was something like this...

(* 2 3N 4) => 24N
(* 2 3 4N) => 24N

etc.

...so passing a BigInt value in as any of the 3 possible args to range would promote the result to a sequence of BigInt.

As I now understand, passing in a BigInt as the 'start' value generates a BigInt sequence, but a BigInt 'end' or 'step' value will generate Long's.

To be precise, this "enhancement request" is to modify 'range' so that passing a BigInt as any one of the 3 possible arguments will yield a sequence of BigInt values.

It might also be viewed as a request to make the documentation more explicit in regard to the current behavior.



 Comments   
Comment by Alex Miller [ 06/Apr/15 8:50 AM ]

This is relatively subtle, but the key is that the values of the range are computed based on start (defaults to 0) and step (default to 1) where 0 and 1 are longs. The end value is used for bounds checking but not for computation. From those pieces of info (which are in the docstring, but the long type of the defaults is implied by the lack of N), plus the default numerics behavior of range, I think it's reasonable to predict how this function will work.

I think that modifying the behavior for the computation based on the type of the end value actually breaks the mental model for me and is harder to understand. This, combined with the infrequency of the use case, leads me to close this enhancement.





[CLJ-1666] change 'fun' to 'f' in doc strings Created: 22/Feb/15  Updated: 22/Feb/15  Resolved: 22/Feb/15

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: Patrick Ryan Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: docstring, enhancement

Attachments: File fix-fun-to-f.diff    
Patch: Code

 Description   

fix 'function' term references in core/alter, core/commute, and test/clojure/test_clojure/pprint/test_cl_format.clj for consistency.

Rest of codebase uses 'f' to refer to functions.



 Comments   
Comment by Patrick Ryan [ 22/Feb/15 12:17 PM ]

My first patch, any help/critique welcomed.

Comment by Andy Fingerhut [ 22/Feb/15 1:10 PM ]

It looks like the format of the patch is the one expected, so that is good. Not a big deal, but most people use their actual name and email address to identify themselves, rather than an alias and email address.

I don't know whether this patch is of interest to the Clojure developers or not, but I do know that they will never apply patches written by those who have not signed a Clojure contributor agreement – see http://clojure.org/contributing

I did not see your name on the list there. Were you considering signing the CA?

Comment by Patrick Ryan [ 22/Feb/15 1:19 PM ]

I just signed it about an hour or two ago. Patrick Ryan (phiat99@gmail.com) (phiat on github) Thanks for feedback

Comment by Alex Miller [ 22/Feb/15 1:23 PM ]

Hi Patrick, thanks for navigating the process and submitting the patch! Unfortunately, I don't think this particular change is worth doing so I am going to decline it. Sorry about that and I hope I have not discouraged you on your road to using or contributing to Clojure!

Comment by Patrick Ryan [ 22/Feb/15 1:33 PM ]

No problem Alex! I know its a tiny trivial change, just a small OCD thing when I was looking through docs! Thanks for feedback. I will look for 'bigger fish' to fry





[CLJ-1660] Unify Stepper and MultiStepper in LazyTransformer Created: 16/Feb/15  Updated: 04/Mar/15  Resolved: 04/Mar/15

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Michael Blume Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None

Attachments: Text File CLJ-1660-v1.patch    
Patch: Code

 Description   

This seemed worthwhile to me mainly because some of the stepper logic is actually pretty fiddly, so it seems better not to have it duplicated.



 Comments   
Comment by Alex Miller [ 04/Mar/15 1:06 PM ]

Based on CLJ-1669 direction which eliminates this code.





[CLJ-1641] AOT compilation fails for a kind of circular dependency after CLJ-1544 patch Created: 14/Jan/15  Updated: 16/Jan/15  Resolved: 16/Jan/15

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.7
Fix Version/s: Release 1.7

Type: Defect Priority: Major
Reporter: Andy Fingerhut Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: regression

Attachments: Text File 0001-CLJ-1641-disallow-circular-dependencies-even-if-the-.patch    

 Description   

I am assuming the summary and description will be updated from this initial version. This may not be a bug, but simply the way things are after CLJ-1544 is fixed, and AOT compilation of some kinds of cyclic namespace dependencies not throwing an exception in earlier versions of Clojure was an accident.

Behavior before CLJ-1544 patch applied:

% cat project.clj 
(defproject manifold-cycle "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.7.0-alpha4"]
                 [manifold "0.1.0-alpha4"]]
  :profiles {:uberjar {:aot :all}})

% cat src/manifold_cycle/core.clj 
(ns manifold-cycle.core
  (:require [manifold.stream :as s]))

% lein version
Leiningen 2.5.0 on Java 1.7.0_45 Java HotSpot(TM) 64-Bit Server VM
% lein clean
% lein uberjar
Compiling manifold-cycle.core
Created /Users/jafinger/clj/glosscycle/target/manifold-cycle-0.1.0-SNAPSHOT.jar
Created /Users/jafinger/clj/glosscycle/target/manifold-cycle-0.1.0-SNAPSHOT-standalone.jar

Behavior after CLJ-1544 patch applied, e.g. by changing Clojure version to 1.7.0-alpha5:

% lein clean
% lein uberjar
Compiling manifold-cycle.core
java.lang.Exception: Cyclic load dependency: [ /manifold/stream ]->/manifold/stream/graph->[ /manifold/stream ]->/manifold_cycle/core, compiling:(manifold/stream/graph.clj:1:1)
	at clojure.core$throw_if.doInvoke(core.clj:5612)
	at clojure.lang.RestFn.invoke(RestFn.java:442)
	at clojure.core$check_cyclic_dependency.invoke(core.clj:5763)
	at clojure.core$load.doInvoke(core.clj:5860)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invoke(core.clj:5653)
	at clojure.core$load_lib$fn__5383.invoke(core.clj:5708)
	at clojure.core$load_lib.doInvoke(core.clj:5707)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invoke(core.clj:628)
	at clojure.core$load_libs.doInvoke(core.clj:5746)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invoke(core.clj:628)
	at clojure.core$require.doInvoke(core.clj:5829)
	at clojure.lang.RestFn.invoke(RestFn.java:457)
	at manifold.stream.graph$loading__5322__auto____856.invoke(graph.clj:1)
	at clojure.lang.AFn.applyToHelper(AFn.java:152)
	at clojure.lang.AFn.applyTo(AFn.java:144)
	at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3600)
	at clojure.lang.Compiler.compile1(Compiler.java:7290)
	at clojure.lang.Compiler.compile1(Compiler.java:7280)
	at clojure.lang.Compiler.compile(Compiler.java:7356)
	at clojure.lang.RT.compile(RT.java:398)
	at clojure.lang.RT.load(RT.java:438)
	at clojure.lang.RT.load(RT.java:411)
	at clojure.core$load$fn__5436.invoke(core.clj:5863)
	at clojure.core$load.doInvoke(core.clj:5862)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invoke(core.clj:5653)
	at clojure.core$load_lib$fn__5383.invoke(core.clj:5708)
	at clojure.core$load_lib.doInvoke(core.clj:5707)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invoke(core.clj:628)
	at clojure.core$load_libs.doInvoke(core.clj:5746)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invoke(core.clj:628)
	at clojure.core$require.doInvoke(core.clj:5829)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3600)
	at clojure.lang.Compiler.compile1(Compiler.java:7290)
	at clojure.lang.Compiler.compile(Compiler.java:7356)
	at clojure.lang.RT.compile(RT.java:398)
	at clojure.lang.RT.load(RT.java:438)
	at clojure.lang.RT.load(RT.java:411)
	at clojure.core$load$fn__5436.invoke(core.clj:5863)
	at clojure.core$load.doInvoke(core.clj:5862)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invoke(core.clj:5653)
	at clojure.core$load_lib$fn__5383.invoke(core.clj:5708)
	at clojure.core$load_lib.doInvoke(core.clj:5707)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invoke(core.clj:628)
	at clojure.core$load_libs.doInvoke(core.clj:5746)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invoke(core.clj:628)
	at clojure.core$require.doInvoke(core.clj:5829)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at manifold_cycle.core$loading__5322__auto____21.invoke(core.clj:1)
	at clojure.lang.AFn.applyToHelper(AFn.java:152)
	at clojure.lang.AFn.applyTo(AFn.java:144)
	at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3600)
	at clojure.lang.Compiler.compile1(Compiler.java:7290)
	at clojure.lang.Compiler.compile1(Compiler.java:7280)
	at clojure.lang.Compiler.compile(Compiler.java:7356)
	at clojure.lang.RT.compile(RT.java:398)
	at clojure.lang.RT.load(RT.java:438)
	at clojure.lang.RT.load(RT.java:411)
	at clojure.core$load$fn__5436.invoke(core.clj:5863)
	at clojure.core$load.doInvoke(core.clj:5862)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invoke(core.clj:5653)
	at clojure.core$compile$fn__5441.invoke(core.clj:5874)
	at clojure.core$compile.invoke(core.clj:5873)
	at user$eval9$fn__16.invoke(form-init6042653661846269464.clj:1)
	at user$eval9.invoke(form-init6042653661846269464.clj:1)
	at clojure.lang.Compiler.eval(Compiler.java:6767)
	at clojure.lang.Compiler.eval(Compiler.java:6757)
	at clojure.lang.Compiler.load(Compiler.java:7194)
	at clojure.lang.Compiler.loadFile(Compiler.java:7150)
	at clojure.main$load_script.invoke(main.clj:274)
	at clojure.main$init_opt.invoke(main.clj:279)
	at clojure.main$initialize.invoke(main.clj:307)
	at clojure.main$null_opt.invoke(main.clj:342)
	at clojure.main$main.doInvoke(main.clj:420)
	at clojure.lang.RestFn.invoke(RestFn.java:421)
	at clojure.lang.Var.invoke(Var.java:383)
	at clojure.lang.AFn.applyToHelper(AFn.java:156)
	at clojure.lang.Var.applyTo(Var.java:700)
	at clojure.main.main(main.java:37)
Caused by: java.lang.Exception: Cyclic load dependency: [ /manifold/stream ]->/manifold/stream/graph->[ /manifold/stream ]->/manifold_cycle/core
	... 87 more
Exception in thread "main" java.lang.Exception: Cyclic load dependency: [ /manifold/stream ]->/manifold/stream/graph->[ /manifold/stream ]->/manifold_cycle/core, compiling:(manifold/stream/graph.clj:1:1)
	at clojure.core$throw_if.doInvoke(core.clj:5612)
	at clojure.lang.RestFn.invoke(RestFn.java:442)
	at clojure.core$check_cyclic_dependency.invoke(core.clj:5763)
	at clojure.core$load.doInvoke(core.clj:5860)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invoke(core.clj:5653)
	at clojure.core$load_lib$fn__5383.invoke(core.clj:5708)
	at clojure.core$load_lib.doInvoke(core.clj:5707)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invoke(core.clj:628)
	at clojure.core$load_libs.doInvoke(core.clj:5746)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invoke(core.clj:628)
	at clojure.core$require.doInvoke(core.clj:5829)
	at clojure.lang.RestFn.invoke(RestFn.java:457)
	at manifold.stream.graph$loading__5322__auto____856.invoke(graph.clj:1)
	at clojure.lang.AFn.applyToHelper(AFn.java:152)
	at clojure.lang.AFn.applyTo(AFn.java:144)
	at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3600)
	at clojure.lang.Compiler.compile1(Compiler.java:7290)
	at clojure.lang.Compiler.compile1(Compiler.java:7280)
	at clojure.lang.Compiler.compile(Compiler.java:7356)
	at clojure.lang.RT.compile(RT.java:398)
	at clojure.lang.RT.load(RT.java:438)
	at clojure.lang.RT.load(RT.java:411)
	at clojure.core$load$fn__5436.invoke(core.clj:5863)
	at clojure.core$load.doInvoke(core.clj:5862)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invoke(core.clj:5653)
	at clojure.core$load_lib$fn__5383.invoke(core.clj:5708)
	at clojure.core$load_lib.doInvoke(core.clj:5707)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invoke(core.clj:628)
	at clojure.core$load_libs.doInvoke(core.clj:5746)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invoke(core.clj:628)
	at clojure.core$require.doInvoke(core.clj:5829)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3600)
	at clojure.lang.Compiler.compile1(Compiler.java:7290)
	at clojure.lang.Compiler.compile(Compiler.java:7356)
	at clojure.lang.RT.compile(RT.java:398)
	at clojure.lang.RT.load(RT.java:438)
	at clojure.lang.RT.load(RT.java:411)
	at clojure.core$load$fn__5436.invoke(core.clj:5863)
	at clojure.core$load.doInvoke(core.clj:5862)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invoke(core.clj:5653)
	at clojure.core$load_lib$fn__5383.invoke(core.clj:5708)
	at clojure.core$load_lib.doInvoke(core.clj:5707)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invoke(core.clj:628)
	at clojure.core$load_libs.doInvoke(core.clj:5746)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invoke(core.clj:628)
	at clojure.core$require.doInvoke(core.clj:5829)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at manifold_cycle.core$loading__5322__auto____21.invoke(core.clj:1)
	at clojure.lang.AFn.applyToHelper(AFn.java:152)
	at clojure.lang.AFn.applyTo(AFn.java:144)
	at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3600)
	at clojure.lang.Compiler.compile1(Compiler.java:7290)
	at clojure.lang.Compiler.compile1(Compiler.java:7280)
	at clojure.lang.Compiler.compile(Compiler.java:7356)
	at clojure.lang.RT.compile(RT.java:398)
	at clojure.lang.RT.load(RT.java:438)
	at clojure.lang.RT.load(RT.java:411)
	at clojure.core$load$fn__5436.invoke(core.clj:5863)
	at clojure.core$load.doInvoke(core.clj:5862)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invoke(core.clj:5653)
	at clojure.core$compile$fn__5441.invoke(core.clj:5874)
	at clojure.core$compile.invoke(core.clj:5873)
	at user$eval9$fn__16.invoke(form-init6042653661846269464.clj:1)
	at user$eval9.invoke(form-init6042653661846269464.clj:1)
	at clojure.lang.Compiler.eval(Compiler.java:6767)
	at clojure.lang.Compiler.eval(Compiler.java:6757)
	at clojure.lang.Compiler.load(Compiler.java:7194)
	at clojure.lang.Compiler.loadFile(Compiler.java:7150)
	at clojure.main$load_script.invoke(main.clj:274)
	at clojure.main$init_opt.invoke(main.clj:279)
	at clojure.main$initialize.invoke(main.clj:307)
	at clojure.main$null_opt.invoke(main.clj:342)
	at clojure.main$main.doInvoke(main.clj:420)
	at clojure.lang.RestFn.invoke(RestFn.java:421)
	at clojure.lang.Var.invoke(Var.java:383)
	at clojure.lang.AFn.applyToHelper(AFn.java:156)
	at clojure.lang.Var.applyTo(Var.java:700)
	at clojure.main.main(main.java:37)
Caused by: java.lang.Exception: Cyclic load dependency: [ /manifold/stream ]->/manifold/stream/graph->[ /manifold/stream ]->/manifold_cycle/core
	... 87 more
Compilation failed: Subprocess failed

It is true that Manifold has a kind of cyclic dependency in its implementation. Namespace manifold.stream's ns form has no require of namespace manifold.stream.graph, but there is an explicit require of the namespace after its ns form here: https://github.com/ztellman/manifold/blob/master/src/manifold/stream.clj#L410

Namespace manifold.stream.graph requires manifold.stream in its ns form: https://github.com/ztellman/manifold/blob/master/src/manifold/stream/graph.clj#L5

Reported by Janne Lemmetti in the Clojure Google group thread announcing Clojure 1.7.0-alpha5's release on Jan 11 2015. He discovered the problem while trying to AOT compile a project that uses the gloss library, which depends upon byte-streams, which depends upon manifold.



 Comments   
Comment by Zach Tellman [ 14/Jan/15 3:46 PM ]

Speaking as the author of the circular dependency, I think what I'm doing here should be allowed. I want to surface vars A and C in a namespace, but C relies on B in another namespace, and B relies on A in my original namespace. Therefore, I was able to do this:

(ns b-ns
(:require [a-ns]))

(def b ...)

(ns a-ns)

(def A ...)

(require 'b-ns)

(def C ...)

The assumption here is that the parts of 'a-ns' that 'b-ns' relies on have been defined once 'b-ns' is required and refers back to 'a-ns'. I was happy to find that this worked, as it meant I didn't have to use my previous approach in these situations, which was to factor out the first half of 'a-ns' into a separate namespace, and then import those vars into 'a-ns' (no one has ever liked import-vars).

If the pre-alpha5 behavior I was relying on was too accidental for everyone's taste, I can get rid of it, but I assert that having some official way to "break" reference loops would be very useful.

Comment by Andy Fingerhut [ 14/Jan/15 5:00 PM ]

Zach, I don't know if it makes any difference to you, but I believe that the CLJ-1544 patch did not break what you are doing in Manifold all of the time, only when AOT compilation is used. That may be significant enough of a use case that your statements still stand.

Comment by Alex Miller [ 14/Jan/15 5:44 PM ]

Pulling this into the 1.7 list just so I'm seeing it, not necessarily implying anything re end result as I haven't looked at it yet.

Comment by Andy Fingerhut [ 15/Jan/15 11:42 AM ]

Added to comments as more background, not necessarily suggesting whether this behavior change is a bug or not: Brief email thread from Oct 2014 in Clojure group between Colin Fleming and Steven (Gilardi?) on why Clojure did not warn about any cyclic dependencies in the Manifold library before: https://groups.google.com/forum/#!topic/clojure/wrVFuCjf0_Y/discussion

Comment by Zach Tellman [ 15/Jan/15 1:41 PM ]

I took another look at my code, and found that the design has changed enough that I no longer "need" circular dependencies, and I could just factor out the shared code to a third namespace. This doesn't need to hold up the 1.7.0 release, I guess, but speaking as someone who uses AOT compilation everywhere, divergent behavior between AOT and standard compilation is worrisome.

Comment by Alex Miller [ 15/Jan/15 2:27 PM ]

One way I can read this is as a sign of the tension between "form as unit of compilation" and "file as code container" where these can be separated in normal source loading but are tangled in AOT.

Comment by Nicola Mometto [ 15/Jan/15 3:52 PM ]

Zach, I agree that having different behaviour between AOT and JIT is wrong.

But I also don't agree that having clojure error out on circular dependencies should be considered a bug, I would argue that the way manifold used to implement the circular dependency between manifold.stream and manifold.stream.graph was a just a hack around lack of validation in require.

My proposal to fix this disparity between AOT and JIT is by making require/use check for circular dependencies before checking for already-loaded namespaces.

This way, both under JIT and AOT code like

(ns foo.a (:require foo.b))
(ns foo.b)
(require 'foo.a)

will fail with a circular depdenency error.

This is what the patch I just attached (0001-CLJ-1641-disallow-circular-dependencies-even-if-the-.patch) does.\

Comment by Alex Miller [ 16/Jan/15 12:59 PM ]

CLJ-1544 is being rolled back in alpha6. I'm not exactly sure what to call the status on this one but we do not plan to take further action on it right now. Any future change for CLJ-1544 will consider this case.





[CLJ-1639] Loading both AOT and non-AOT versions of a namespace causes errors Created: 12/Jan/15  Updated: 29/Jan/15  Resolved: 16/Jan/15

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.7
Fix Version/s: Release 1.7

Type: Defect Priority: Critical
Reporter: Sean Corfield Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: regression
Environment:

Clojure 1.7.0-alpha5



 Description   

Change in behavior here due to CLJ-979 added in 1.7.0-alpha5.

Symptom is that code fails to compile when a namespace is loading, claiming a protocol has no implementation for a method (that it does have).

Stack trace from Sean Corfield's code:

Caused by: java.lang.IllegalArgumentException: No implementation of method: :has? of protocol: #'clojure.core.cache/CacheProtocol found for class: clojure.core.memoize.PluggableMemoization 
        at clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:555) 
        at clojure.core.cache$eval1710$fn__1773$G__1699__1780.invoke(cache.clj:20) 
        at clojure.core.cache$through.invoke(cache.clj:53) 
        at clojure.core.memoize$through_STAR_.invoke(memoize.clj:52) 
        at clojure.lang.Atom.swap(Atom.java:65) 
        at clojure.core$swap_BANG_.invoke(core.clj:2236) 
        at clojure.core.memoize$build_memoizer$fn__12665.doInvoke(memoize.clj:134) 
        at clojure.lang.RestFn.applyTo(RestFn.java:137) 
        at clojure.lang.AFunction$1.doInvoke(AFunction.java:29) 
        at clojure.lang.RestFn.invoke(RestFn.java:408) 
        at clojure.tools.analyzer.jvm$desugar_host_expr.invoke(jvm.clj:117) 
        at clojure.tools.analyzer.jvm$macroexpand_1.invoke(jvm.clj:174) 
        at clojure.tools.analyzer$fn__12389.invoke(analyzer.clj:281) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:238) 
        at clojure.tools.analyzer$fn__12346.invoke(analyzer.clj:68) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:233) 
        at clojure.tools.analyzer$analyze_let.invoke(analyzer.clj:505) 
        at clojure.tools.analyzer$fn__12469.invoke(analyzer.clj:530) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:233) 
        at clojure.tools.analyzer.jvm$fn__13956.invoke(jvm.clj:66) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:233) 
        at clojure.tools.analyzer$fn__12389.invoke(analyzer.clj:283) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:238) 
        at clojure.tools.analyzer$fn__12346.invoke(analyzer.clj:68) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:233) 
        at clojure.tools.analyzer$fn__12389.invoke(analyzer.clj:284) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:238) 
        at clojure.tools.analyzer$fn__12346.invoke(analyzer.clj:68) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:233) 
        at clojure.tools.analyzer$fn__12392.invoke(analyzer.clj:295) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:233) 
        at clojure.tools.analyzer.jvm$fn__13956.invoke(jvm.clj:66) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:233) 
        at clojure.tools.analyzer$analyze_body.invoke(analyzer.clj:366) 
        at clojure.tools.analyzer$analyze_let.invoke(analyzer.clj:520) 
        at clojure.tools.analyzer$fn__12471.invoke(analyzer.clj:540) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:233) 
        at clojure.tools.analyzer.jvm$fn__13956.invoke(jvm.clj:66) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:233) 
        at clojure.tools.analyzer$fn__12389.invoke(analyzer.clj:283) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:238) 
        at clojure.tools.analyzer$fn__12346.invoke(analyzer.clj:68) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:233) 
        at clojure.tools.analyzer$fn__12389.invoke(analyzer.clj:284) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:238) 
        at clojure.tools.analyzer$fn__12346.invoke(analyzer.clj:68) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:233) 
        at clojure.tools.analyzer$fn__12392.invoke(analyzer.clj:295) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:233) 
        at clojure.tools.analyzer.jvm$fn__13956.invoke(jvm.clj:66) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:233) 
        at clojure.tools.analyzer$fn__12389.invoke(analyzer.clj:283) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:238) 
        at clojure.tools.analyzer$fn__12346.invoke(analyzer.clj:68) 
        at clojure.lang.MultiFn.invoke(MultiFn.java:233) 
        at clojure.tools.analyzer$analyze.invoke(analyzer.clj:123) 
        at clojure.tools.analyzer.jvm$analyze$fn__14085.invoke(jvm.clj:476) 
        at clojure.lang.AFn.applyToHelper(AFn.java:152) 
        at clojure.lang.AFn.applyTo(AFn.java:144) 
        at clojure.core$apply.invoke(core.clj:626) 
        at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1864) 
        at clojure.lang.RestFn.invoke(RestFn.java:425) 
        at clojure.tools.analyzer.jvm$analyze.invoke(jvm.clj:474) 
        at clojure.tools.analyzer.jvm$analyze.invoke(jvm.clj:467) 
        at clojure.core.async.impl.ioc_macros$state_machine.invoke(ioc_macros.clj:1062) 
        at clojure.core.async$go.doInvoke(async.clj:384) 
        at clojure.lang.RestFn.invoke(RestFn.java:442) 
        at clojure.lang.Var.invoke(Var.java:388) 
        at clojure.lang.AFn.applyToHelper(AFn.java:160) 
        at clojure.lang.Var.applyTo(Var.java:700) 
        at clojure.lang.Compiler.macroexpand1(Compiler.java:6606)

Stacktrace from Andy Fingerhut's code, in Eastwood:

% lein do clean, eastwood '{:namespaces [clojure.reflect]}'
== Eastwood 0.2.1 Clojure 1.7.0-alpha4c979only JVM 1.7.0_45
== Linting clojure.reflect ==
Exception thrown during phase :analyze+eval of linting namespace clojure.reflect
IllegalArgumentException No implementation of method: :do-reflect of protocol: #'clojure.reflect/Reflector found for class: clojure.reflect.JavaReflector
	clojure.core/-cache-protocol-fn (core_deftype.clj:555)
	clojure.reflect/eval6486/fn--6487/G--6470--6490 (form-init6080826551765301071.clj:1)
	clojure.core/partial/fn--4490 (core.clj:2489)
	clojure.reflect/type-reflect (reflect.clj:100)
	clojure.core/apply (core.clj:632)
	eastwood.copieddeps.dep2.clojure.tools.analyzer.jvm.utils/type-reflect (utils.clj:24)
	eastwood.copieddeps.dep2.clojure.tools.analyzer.jvm.utils/members*--1293 (utils.clj:271)
	clojure.core/apply (core.clj:626)
	eastwood.copieddeps.dep3.clojure.core.memoize/through*/fn--1072 (memoize.clj:66)
	eastwood.copieddeps.dep4.clojure.core.cache/through/fn--872 (cache.clj:55)
	eastwood.copieddeps.dep3.clojure.core.memoize/through*/fn--1068/fn--1069 (memoize.clj:65)
	eastwood.copieddeps.dep3.clojure.core.memoize/d-lay/reify--1063 (memoize.clj:54)
	clojure.core/deref (core.clj:2202)
	eastwood.copieddeps.dep3.clojure.core.memoize/build-memoizer/fn--1123 (memoize.clj:152)
	clojure.lang.AFunction$1.doInvoke (AFunction.java:29)
	eastwood.copieddeps.dep2.clojure.tools.analyzer.jvm.utils/members (utils.clj:280)
	eastwood.copieddeps.dep2.clojure.tools.analyzer.jvm.utils/instance-members (utils.clj:289)
	eastwood.copieddeps.dep2.clojure.tools.analyzer.jvm.utils/instance-methods (utils.clj:299)
	eastwood.copieddeps.dep2.clojure.tools.analyzer.passes.jvm.validate/validate-call (validate.clj:91)
	eastwood.copieddeps.dep2.clojure.tools.analyzer.passes.jvm.validate/eval2056/fn--2058 (validate.clj:148)
	clojure.lang.MultiFn.invoke (MultiFn.java:229)
	eastwood.copieddeps.dep2.clojure.tools.analyzer.passes.jvm.validate/validate (validate.clj:264)
	clojure.lang.Var.invoke (Var.java:379)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.passes/compile-passes/fn--574/fn--579 (passes.clj:171)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.passes/compile-passes/fn--574/fn--581 (passes.clj:173)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.passes/compile-passes/fn--574/fn--581 (passes.clj:173)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.passes/compile-passes/fn--574/fn--581 (passes.clj:173)
	clojure.core/partial/fn--4492 (core.clj:2496)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191 (ast.clj:102)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191/walk--192 (ast.clj:96)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children/fn--182 (ast.clj:51)
	clojure.lang.ArrayChunk.reduce (ArrayChunk.java:63)
	clojure.core.protocols/fn--6433 (protocols.clj:103)
	clojure.core.protocols/fn--6395/G--6390--6404 (protocols.clj:19)
	clojure.core.protocols/seq-reduce (protocols.clj:31)
	clojure.core.protocols/fn--6414 (protocols.clj:65)
	clojure.core.protocols/fn--6369/G--6364--6382 (protocols.clj:13)
	clojure.core/reduce (core.clj:6461)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children (ast.clj:56)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/update-children-reduced (ast.clj:64)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191 (ast.clj:99)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191/walk--192 (ast.clj:96)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children/fn--182 (ast.clj:51)
	clojure.lang.ArrayChunk.reduce (ArrayChunk.java:63)
	clojure.core.protocols/fn--6433 (protocols.clj:103)
	clojure.core.protocols/fn--6395/G--6390--6404 (protocols.clj:19)
	clojure.core.protocols/seq-reduce (protocols.clj:31)
	clojure.core.protocols/fn--6414 (protocols.clj:65)
	clojure.core.protocols/fn--6369/G--6364--6382 (protocols.clj:13)
	clojure.core/reduce (core.clj:6461)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children (ast.clj:56)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/update-children-reduced (ast.clj:64)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191 (ast.clj:99)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191/walk--192 (ast.clj:96)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.utils/mapv' (utils.clj:208)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children/fn--182 (ast.clj:51)
	clojure.lang.ArrayChunk.reduce (ArrayChunk.java:58)
	clojure.core.protocols/fn--6433 (protocols.clj:103)
	clojure.core.protocols/fn--6395/G--6390--6404 (protocols.clj:19)
	clojure.core.protocols/seq-reduce (protocols.clj:31)
	clojure.core.protocols/fn--6414 (protocols.clj:65)
	clojure.core.protocols/fn--6369/G--6364--6382 (protocols.clj:13)
	clojure.core/reduce (core.clj:6461)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children (ast.clj:56)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/update-children-reduced (ast.clj:64)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191 (ast.clj:99)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191/walk--192 (ast.clj:96)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children/fn--182 (ast.clj:51)
	clojure.lang.ArrayChunk.reduce (ArrayChunk.java:58)
	clojure.core.protocols/fn--6433 (protocols.clj:103)
	clojure.core.protocols/fn--6395/G--6390--6404 (protocols.clj:19)
	clojure.core.protocols/seq-reduce (protocols.clj:31)
	clojure.core.protocols/fn--6414 (protocols.clj:65)
	clojure.core.protocols/fn--6369/G--6364--6382 (protocols.clj:13)
	clojure.core/reduce (core.clj:6461)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children (ast.clj:56)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/update-children-reduced (ast.clj:64)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191 (ast.clj:99)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191/walk--192 (ast.clj:96)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.utils/mapv' (utils.clj:208)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children/fn--182 (ast.clj:51)
	clojure.lang.ArrayChunk.reduce (ArrayChunk.java:58)
	clojure.core.protocols/fn--6433 (protocols.clj:103)
	clojure.core.protocols/fn--6395/G--6390--6404 (protocols.clj:19)
	clojure.core.protocols/seq-reduce (protocols.clj:31)
	clojure.core.protocols/fn--6414 (protocols.clj:65)
	clojure.core.protocols/fn--6369/G--6364--6382 (protocols.clj:13)
	clojure.core/reduce (core.clj:6461)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children (ast.clj:56)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/update-children-reduced (ast.clj:64)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191 (ast.clj:99)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191/walk--192 (ast.clj:96)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children/fn--182 (ast.clj:51)
	clojure.lang.ArrayChunk.reduce (ArrayChunk.java:63)
	clojure.core.protocols/fn--6433 (protocols.clj:103)
	clojure.core.protocols/fn--6395/G--6390--6404 (protocols.clj:19)
	clojure.core.protocols/seq-reduce (protocols.clj:31)
	clojure.core.protocols/fn--6414 (protocols.clj:65)
	clojure.core.protocols/fn--6369/G--6364--6382 (protocols.clj:13)
	clojure.core/reduce (core.clj:6461)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children (ast.clj:56)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/update-children-reduced (ast.clj:64)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191 (ast.clj:99)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191/walk--192 (ast.clj:96)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children/fn--182 (ast.clj:51)
	clojure.lang.ArrayChunk.reduce (ArrayChunk.java:63)
	clojure.core.protocols/fn--6433 (protocols.clj:103)
	clojure.core.protocols/fn--6395/G--6390--6404 (protocols.clj:19)
	clojure.core.protocols/seq-reduce (protocols.clj:31)
	clojure.core.protocols/fn--6414 (protocols.clj:65)
	clojure.core.protocols/fn--6369/G--6364--6382 (protocols.clj:13)
	clojure.core/reduce (core.clj:6461)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children (ast.clj:56)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/update-children-reduced (ast.clj:64)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191 (ast.clj:99)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191/walk--192 (ast.clj:96)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.utils/mapv' (utils.clj:208)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children/fn--182 (ast.clj:51)
	clojure.lang.ArrayChunk.reduce (ArrayChunk.java:58)
	clojure.core.protocols/fn--6433 (protocols.clj:103)
	clojure.core.protocols/fn--6395/G--6390--6404 (protocols.clj:19)
	clojure.core.protocols/seq-reduce (protocols.clj:31)
	clojure.core.protocols/fn--6414 (protocols.clj:65)
	clojure.core.protocols/fn--6369/G--6364--6382 (protocols.clj:13)
	clojure.core/reduce (core.clj:6461)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children (ast.clj:56)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/update-children-reduced (ast.clj:64)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191 (ast.clj:99)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191/walk--192 (ast.clj:96)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.utils/mapv' (utils.clj:208)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children/fn--182 (ast.clj:51)
	clojure.lang.ArrayChunk.reduce (ArrayChunk.java:63)
	clojure.core.protocols/fn--6433 (protocols.clj:103)
	clojure.core.protocols/fn--6395/G--6390--6404 (protocols.clj:19)
	clojure.core.protocols/seq-reduce (protocols.clj:31)
	clojure.core.protocols/fn--6414 (protocols.clj:65)
	clojure.core.protocols/fn--6369/G--6364--6382 (protocols.clj:13)
	clojure.core/reduce (core.clj:6461)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children (ast.clj:56)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/update-children-reduced (ast.clj:64)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191 (ast.clj:99)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191/walk--192 (ast.clj:96)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.utils/mapv' (utils.clj:208)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children/fn--182 (ast.clj:51)
	clojure.lang.ArrayChunk.reduce (ArrayChunk.java:63)
	clojure.core.protocols/fn--6433 (protocols.clj:103)
	clojure.core.protocols/fn--6395/G--6390--6404 (protocols.clj:19)
	clojure.core.protocols/seq-reduce (protocols.clj:31)
	clojure.core.protocols/fn--6414 (protocols.clj:65)
	clojure.core.protocols/fn--6369/G--6364--6382 (protocols.clj:13)
	clojure.core/reduce (core.clj:6461)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children (ast.clj:56)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/update-children-reduced (ast.clj:64)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191 (ast.clj:99)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191/walk--192 (ast.clj:96)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.utils/mapv' (utils.clj:208)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children/fn--182 (ast.clj:51)
	clojure.lang.ArrayChunk.reduce (ArrayChunk.java:63)
	clojure.core.protocols/fn--6433 (protocols.clj:103)
	clojure.core.protocols/fn--6395/G--6390--6404 (protocols.clj:19)
	clojure.core.protocols/seq-reduce (protocols.clj:31)
	clojure.core.protocols/fn--6414 (protocols.clj:65)
	clojure.core.protocols/fn--6369/G--6364--6382 (protocols.clj:13)
	clojure.core/reduce (core.clj:6461)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/-update-children (ast.clj:56)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/update-children-reduced (ast.clj:64)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk/walk--191 (ast.clj:99)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/walk (ast.clj:95)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/postwalk (ast.clj:115)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.ast/postwalk (ast.clj:113)
	eastwood.copieddeps.dep1.clojure.tools.analyzer.passes/compile-passes/analyze--586 (passes.clj:175)
	clojure.core/comp/fn--4458 (core.clj:2434)
	clojure.core/comp/fn--4458 (core.clj:2434)
	eastwood.analyze-ns/run-passes (analyze_ns.clj:157)
	eastwood.copieddeps.dep2.clojure.tools.analyzer.jvm/analyze/fn--3553 (jvm.clj:474)
	clojure.core/apply (core.clj:626)
	clojure.core/with-bindings* (core.clj:1864)
	eastwood.copieddeps.dep2.clojure.tools.analyzer.jvm/analyze (jvm.clj:470)
	eastwood.copieddeps.dep2.clojure.tools.analyzer.jvm/analyze+eval (jvm.clj:518)
	eastwood.copieddeps.dep2.clojure.tools.analyzer.jvm/analyze+eval/fn--3574 (jvm.clj:505)
	clojure.core/mapv/fn--6657 (core.clj:6558)
	clojure.lang.ArrayChunk.reduce (ArrayChunk.java:63)
	clojure.core.protocols/fn--6433 (protocols.clj:103)
	clojure.core.protocols/fn--6395/G--6390--6404 (protocols.clj:19)
	clojure.core.protocols/seq-reduce (protocols.clj:31)
	clojure.core.protocols/fn--6418 (protocols.clj:53)
	clojure.core.protocols/fn--6369/G--6364--6382 (protocols.clj:13)
	clojure.core/reduce (core.clj:6461)
	clojure.core/mapv (core.clj:6558)
	eastwood.copieddeps.dep2.clojure.tools.analyzer.jvm/analyze+eval (jvm.clj:503)
	eastwood.analyze-ns/analyze-file/fn--4173/fn--4175 (analyze_ns.clj:279)
	eastwood.analyze-ns/analyze-file/fn--4173 (analyze_ns.clj:276)
	eastwood.analyze-ns/analyze-file (analyze_ns.clj:274)
	eastwood.analyze-ns/analyze-ns (analyze_ns.clj:327)
	eastwood.lint/lint-ns (lint.clj:569)
	eastwood.lint/eastwood-core/fn--6336 (lint.clj:1041)
	eastwood.lint/eastwood-core (lint.clj:1040)
	eastwood.lint/eastwood (lint.clj:1154)
	eastwood.lint/eastwood-from-cmdline (lint.clj:1167)
	clojure.lang.Var.invoke (Var.java:379)
	eastwood.versioncheck/run-eastwood (versioncheck.clj:15)
	user/eval21 (form-init6080826551765301071.clj:1)
	clojure.lang.Compiler.eval (Compiler.java:6767)
	clojure.lang.Compiler.eval (Compiler.java:6757)
	clojure.lang.Compiler.load (Compiler.java:7194)
	clojure.lang.Compiler.loadFile (Compiler.java:7150)
	clojure.main/load-script (main.clj:274)
	clojure.main/init-opt (main.clj:279)
	clojure.main/initialize (main.clj:307)
	clojure.main/null-opt (main.clj:342)
	clojure.main/main (main.clj:420)
	clojure.lang.Var.invoke (Var.java:383)
	clojure.lang.Var.applyTo (Var.java:700)
	clojure.main.main (main.java:37)

The following form was being processed during the exception:

(defprotocol
 TypeReference
 "A TypeReference can be unambiguously converted to a type name on\n   the host platform.\n\n   All typerefs are normalized into symbols. If you need to\n   normalize a typeref yourself, call typesym."
 (typename
  [o]
  "Returns Java name as returned by ASM getClassName, e.g. byte[], java.lang.String[]"))

Shown again with metadata for debugging (some metadata elided for brevity):

^{:line 48}
(^{:line 48} defprotocol
 ^{:line 48} TypeReference
 "A TypeReference can be unambiguously converted to a type name on\n   the host platform.\n\n   All typerefs are normalized into symbols. If you need to\n   normalize a typeref yourself, call typesym."
 ^{:line 54}
 (^{:line 54} typename
  ^{:line 54} [^{:line 54} o]
  "Returns Java name as returned by ASM getClassName, e.g. byte[], java.lang.String[]"))

An exception was thrown while analyzing namespace clojure.reflect 
Lint results may be incomplete.  If there are compilation errors in
your code, try fixing those.  If not, check above for info on the
exception.

Exception thrown while analyzing last namespace.

== Warnings: 0 (not including reflection warnings)  Exceptions thrown: 1
Subprocess failed


 Comments   
Comment by Nicola Mometto [ 12/Jan/15 2:04 PM ]

I can't tell about the exception Sean is getting, but the one Andy is getting with eastwood, I believe should not be considered a bug.

What's happening in eastwood is that the entire clojure.reflect namespace is being reloaded, deftypes and defprotocols included, while a reference to an instance of a previous deftype is being used by the eastwood codebase (from the tools.analyzer.jvm dep)

This used to work only because of the bug that CLJ-979 fixed where since clojure.reflect is AOT compiled, re-evaluating the defprotocol didn't change the underlying interface.

This code demonstrates this:

;; PRE CLJ-979, re-evaluating an AOT compiled defprotocol didn't change the underlying interface used
user=> *clojure-version*
{:interim true, :major 1, :minor 7, :incremental 0, :qualifier "alpha4"}
user=> (use 'clojure.reflect)
nil
user=> (in-ns 'clojure.reflect)
#<Namespace clojure.reflect>
clojure.reflect=> (hash (:on-interface Reflector))
2141314409
clojure.reflect=> (defprotocol Reflector (do-reflect [reflector typeref]))
Reflector
clojure.reflect=> (hash (:on-interface Reflector))
2141314409
clojure.reflect=>


;; AFTER CLJ-979, re-evaluating an AOT compiled defprotocol _does_ change the underlying interface used
user=> *clojure-version*
{:interim true, :major 1, :minor 7, :incremental 0, :qualifier "master"}
user=> (use 'clojure.reflect)
nil
user=> (in-ns 'clojure.reflect)
#<Namespace clojure.reflect>
clojure.reflect=> (hash (:on-interface Reflector))
390902174
clojure.reflect=> (defprotocol Reflector (do-reflect [reflector typeref]))
Reflector
clojure.reflect=> (hash (:on-interface Reflector))
1673776464


;; note that while the new behaviour causes the eastwood bug (and maybe the one Sean is seeing too),
;; the new behaviour is consistent with how redefining a protocol not AOT compiled behaved:
user=> *clojure-version*
{:interim true, :major 1, :minor 7, :incremental 0, :qualifier "alpha4"}
user=> (defprotocol foo)
foo
user=> (hash (:on-interface foo))
1058055630
user=> (defprotocol foo)
foo
user=> (hash (:on-interface foo))
1333687570

Again, I don't know if the exception that Sean is getting is related to this issue without looking at the code, bug I suspect a similar scenario given that Sean told me in IRC that there is indeed some AOT compilation involved with a wrapper around clojure.cache.

I personally wouldn't consider this a bug, I want to emphatize that the exception demonstrated by Andy would have occurred in 1.7.0-alpha4 too hadn't clojure.reflect been AOT compiled and the fact that it worked instead is just an accident of the bug fixed with CLJ-979.

Comment by Sean Corfield [ 12/Jan/15 2:19 PM ]

The only AOT compilation in our entire code base is one small library that implements a DBAppender for log4j. That's a separate project that we AOT compile and then depend on in our main (non-AOT) projects. That AOT project, in order to avoid pulling in a lot of transitive dependencies that get AOT-compiled too (due to the over-enthusiasm of Clojure's AOT process), uses runtime require/resolve to load the symbols it needs from the main project.

Given what you're saying, it sounds like that runtime require/resolve is broken by fixing CLJ-979 (and was therefore only working "by accident" before)?

Comment by Nicola Mometto [ 12/Jan/15 2:34 PM ]

Here a better test case showcasing how 1.7.0-alpha5 behaves consistently between AOT and JIT scenarios while 1.7.0-alpha4 has a different behaviour when AOT compilation is involved. 1.7.0-alpha4 JIT is consistent with 1.7.0-alpha5 JIT and AOT

[~]> cat test.clj
(ns test)
(defprotocol p (f [_]))
(deftype t [] p (f [_] 1))
[~]> mkdir classes
;; 1.7.0-alpha4 AOT
[~]> java -cp .m2/repository/org/clojure/clojure/1.7.0-alpha4/clojure-1.7.0-alpha4.jar:.:classes clojure.main
Clojure 1.7.0-alpha4
user=> (binding [*compile-files* true] (load "test"))
nil
user=> (in-ns 'test)
#<Namespace test>
test=> (def a (t.))
#'test/a
test=> (defprotocol p (f [_]))
p
test=> (deftype t [] p (f [_] 1))
test.t
test=> (f a)
1
;; notice how this is the only call that succeds since the re-defined protocol is still backed by the 
;; AOT compiled class rather than the one generated JIT with the defprotocol call at the repl
test=>
[~]> rm -rf classes/*
;; 1.7.0-alpha4 no AOT
[~]> java -cp .m2/repository/org/clojure/clojure/1.7.0-alpha4/clojure-1.7.0-alpha4.jar:.:classes clojure.main
Clojure 1.7.0-alpha4
user=> (load "test")
nil
user=> (in-ns 'test)
#<Namespace test>
test=> (def a (t.))
#'test/a
test=> (defprotocol p (f [_]))
p
test=> (deftype t [] p (f [_] 1))
test.t
test=> (f a)
IllegalArgumentException No implementation of method: :f of protocol: #'test/p found for class: test.t  clojure.core/-cache-protocol-fn (core_deftype.clj:555)
test=>
;; 1.7.0-alpha5 AOT
[~]> java -cp .m2/repository/org/clojure/clojure/1.7.0-alpha5/clojure-1.7.0-alpha5.jar:.:classes clojure.main
Clojure 1.7.0-alpha5
user=> (binding [*compile-files* true] (load "test"))
nil
user=> (in-ns 'test)
#<Namespace test>
test=> (def a (t.))
#'test/a
test=> (defprotocol p (f [_]))
p
test=> (deftype t [] p (f [_] 1))
test.t
test=> (f a)
IllegalArgumentException No implementation of method: :f of protocol: #'test/p found for class: test.t  clojure.core/-cache-protocol-fn (core_deftype.clj:555)
test=>
[~]> rm -rf classes/*
;; 1.7.0-alpha5 no AOT
[~]> java -cp .m2/repository/org/clojure/clojure/1.7.0-alpha5/clojure-1.7.0-alpha5.jar:.:classes clojure.main
Clojure 1.7.0-alpha5
user=> (load "test")
nil
user=> (in-ns 'test)
#<Namespace test>
test=> (def a (t.))
#'test/a
test=> (defprotocol p (f [_]))
p
test=> (deftype t [] p (f [_] 1))
test.t
test=> (f a)
IllegalArgumentException No implementation of method: :f of protocol: #'test/p found for class: test.t  clojure.core/-cache-protocol-fn (core_deftype.clj:555)
test=>
Comment by Sean Corfield [ 12/Jan/15 2:37 PM ]

I removed the runtime require in the AOT'd project and we still get this exception so I'm less inclined to believe our usage is buggy here. The only other runtime require we do is on our New Relic wrapper - but we get the exception in a pure Clojure project that does not use that at all (and now has no runtime require calls at all, as far as I can tell).

Comment by Nicola Mometto [ 12/Jan/15 2:40 PM ]

Sean, I cannot be sure about your case as I don't know the code/compilation scenario behind the exception.
All I said is however true for the exception reported by Andy and that the two exceptions apperas to be the same and to be caused by the same issue.

I can't also tell you whether this will be considered a regression or if the it will be chosen that your code happened to work by accident before.

I personally don't believe this should be considered a regression since the new behaviour makes JIT and AOT consistent while previously they weren't, but I don't have the authority to decide on this matter

Comment by Sean Corfield [ 12/Jan/15 3:39 PM ]

To rule out some other interactions in our code, I moved our one and only AOT-compiled file/namespace into the main project and removed the dependency on that separate library, and I also made sure there are no require or other dynamic loading occurring at runtime. The AOT-compiled namespace has no dependencies except on clojure.core and I verified that no .class files are generated for anything except that single namespace.

I still get that exception, always on `PluggableMemoization`. I'm going to start going through the libraries we depend on and see if anything else might be bringing in an AOT-version of either core.cache or core.memoize.

Comment by Sean Corfield [ 12/Jan/15 3:47 PM ]

Searching through the libraries we use, core.typed seems to contain AOT'd versions of core.cache and core.memoize so I'm going to build a version of our system without core.typed to see if that's the culprit here.

Comment by Sean Corfield [ 12/Jan/15 4:32 PM ]

Removing core.typed completely from our system seems to resolve the problem. I'm still dealing with the fallout from other, earlier changes made for debugging but at this point I'm fairly confident that without core.typed, our applications will run on Alpha 5. Will update again when I'm done testing.

Comment by Sean Corfield [ 12/Jan/15 5:31 PM ]

Confirmed: removing core.typed allows all of our tests to pass and all of our applications to work correctly on Alpha 5. I'll raised an issue against core.typed at this point. If Clojure/core feel this ticket is not a bug, it can be closed.

Comment by Nicola Mometto [ 13/Jan/15 10:14 AM ]

Sean, for the scenario to be what I described is happening in eastwood, loading an AOT core.[cache/memoize] is not enough.
What needs to go on is also having core.[cache/memoize] realoaded JIT after the AOT compiled version has been loaded, this can happen if for example the version that core.typed ships with is older than the one one of your deps is pulling in.

And again, I personally think that this scenario should not be considered a bug but I don't speak for Clojure/core so it's possible that Alex, Rich or some other screener will have a different opinion than mine.

Comment by Sean Corfield [ 13/Jan/15 12:44 PM ]

Sorry if it wasn't clear from my stream of comments: our apps rely on core.cache and so it is brought in via JIT in some namespaces - as well as the AOT version loaded via core.typed in other namespaces. So, yes, the scenario you describe is definitely happening in our code - it just took me a while to find where the AOT version was coming from.

I consider this a bug against core.typed - it should not ship AOT versions of other libraries that folks might also be using via JIT - and created an issue in JIRA for that.

This fix to CLJ-979 will mean that no library would ever be able to bundle AOT versions of other libraries (that contained classes generated via deftype etc) since any applications that used said library - and also used any of those other libraries - would trip over this. That may well be a good thing: bundling libraries can already cause version conflicts and mixing AOT in just makes that harder to debug and harder to deal with.

Comment by Alex Miller [ 15/Jan/15 2:40 PM ]

I agree that shipping versions of other libraries inside your own jar (as core.typed appears to be doing) is bad.

I am a little concerned that from a user's POV maybe we have just replaced one "AOT is weird and doesn't work like I expect" with another, regardless of how consistent that behavior is.

Still something I'm just mulling through.

Comment by Nicola Mometto [ 15/Jan/15 2:53 PM ]

Alex, I share your worry however I'd like to point out that if the cause of the error Sean is getting is the same as the cause for the exception for eastwood, that is, the reloading of namespaces containg deftypes/defrecord after one instance of a said type/interface has been used, then we should expect things to break as there is now no difference between how that behaves under JIT and under AOT.

In other words, I don't believe it is reasonable to expect code like this to work:

(deftype X [a])
(def a (X. 1))
(deftype X [a])
(.a ^X a)

The fact that in some scenarios (strictly under AOT!) code similar to that used to work rather than throw should not be a reason to consider the new, consistent behaviour, wrong IMHO.

Note that if it turns out that Sean's exception (or any other other reported issue caused by CLJ-979) is caused by a different scenario than the one I described, then I agree that this is a regression that should be addressed

Comment by Alex Miller [ 16/Jan/15 12:56 PM ]

No plans for further action on this ticket and will pursue a fix for the bad core.typed jar under that ticket.

Comment by Sean Corfield [ 16/Jan/15 1:11 PM ]

I agree no further action is needed but have a question / suggestion:

Is there a reasonable way for Clojure to detect the situation and provide a better error message?

Or is it perhaps worth expanding the error message to include a suggestion to check whether a namespace has been reloaded or a type has been redefined?

Comment by Alex Miller [ 16/Jan/15 3:15 PM ]

It's a good question. I'm not sure that it's easy to detect?

Comment by Nicola Mometto [ 29/Jan/15 1:29 PM ]

It's possible that CLJ-1650 is actually what's causing Sean's exception.





[CLJ-1632] Mark Clojure-generated classes in order for instrumenters to identify them easily Created: 05/Jan/15  Updated: 05/Jan/15  Resolved: 05/Jan/15

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Fabio Tudone Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: compiler


 Description   

Instrumenting logic specific to Clojure-generated classes should be able to identify them easily.



 Comments   
Comment by Fabio Tudone [ 05/Jan/15 2:23 AM ]

One way could be annotations, another could be interface-marking. Would that be feasible? Any drawbacks?

Comment by Alex Miller [ 05/Jan/15 8:17 AM ]

deftypes have a marker interface clojure.lang.IType.
defrecords have a marker interface clojure.lang.IRecord.
proxy classes have marker interface clojure.lang.IProxy.

I think generic markers for protocols or gen-interface would be undesirable as they may be used to create APIs for external use.

Comment by Fabio Tudone [ 05/Jan/15 8:29 AM ]

Not sure I understand your point about the non-marked (as of now and AFAIK) Clojure features such as protocols and gen-interface; could you elaborate? Does it apply to marking with annotations as well?

Comment by Alex Miller [ 05/Jan/15 10:50 AM ]

My point was that many people wish to generate interfaces that do not extend from interfaces in Clojure and adding those marker interfaces would be seen as a downside for them. Annotations are slightly better but have the same problem (dependencies on parts of Clojure core). You are of course free to add those interfaces or annotations yourself in your own code if that's useful to you!

Comment by Fabio Tudone [ 05/Jan/15 11:15 AM ]

It's clear now, thanks!

Actually my use case is about general tooling that will inspect and instrument all (and only) Clojure-generated code in any application making use of it, so I don't control the code I'm going to examine. This is done in order to add specific runtime features in a general fashion.

I can't find a way to do that reliably on everything that has been generated by Clojure; I could use some imperfect heuristics but I'd rather use a reliable way if one exists. Can you see of any other way of doing this I might have overlooked? Or is some other enhancement possible that would allow me to do this and would not compromise external integrations?

Comment by Alex Miller [ 05/Jan/15 11:31 AM ]

I don't see a general-purpose way to do this now. I do not believe supporting this is something we would spend time on.

Comment by Julien Eluard [ 05/Jan/15 2:03 PM ]

Class#isSynthetic() might be relevant here. If I am not mistaken asm generated classes will be flagged as synthetic.





[CLJ-1627] Incorrect error message: "First argument to def must be a Symbol" Created: 27/Dec/14  Updated: 29/Dec/14  Resolved: 28/Dec/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Trivial
Reporter: Richard Davies Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

All



 Description   

(def (symbol "x")) throws the exception: First argument to def must be a Symbol

Given the first argument to this def is a symbol, the error message is incorrect.

This has resulted in:

See http://stackoverflow.com/questions/2486752/in-clojure-how-to-define-a-variable-named-by-a-string

Which so far has >3000 views suggesting that this is something that regularly stumps people the first time they encounter it.

I suggest changing the error message to:

"First argument to def must be an interned Symbol"



 Comments   
Comment by Nicola Mometto [ 28/Dec/14 4:00 AM ]

The first argument to def is not a symbol, it's the list (symbol "x").
def is neither a macro nor a regular function, it's a special form whose first argument is not evaluated. This is documented.

Comment by Alex Miller [ 28/Dec/14 10:39 AM ]

The current error message is literally correct. I don't see how the requested change would help anyone confused by the prior message.

Comment by Richard Davies [ 29/Dec/14 8:46 PM ]

@Ah. It's not explicit in the docs (at least in http://clojure.org/special_forms) or the error message that the first arg isn't evaluated. The docs talk about the "init?" paramater and symbol metadata being evaluated but not that the first argument itself is not actually evaluated. This is probably obvious to those familiar with the workings of the Clojure compiler but as hacking around with vars isn't something I do every day it wasn't to me.

Compare def's error message with trying to do the same thing with var:

(var (symbol "a"))

clojure.lang.Compiler$CompilerException: java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.Symbol

At least that gives me a hint that the expression wasn't evaluated rather than just a wtf moment...





[CLJ-1608] add split-at to clojure.string Created: 03/Dec/14  Updated: 03/Dec/14  Resolved: 03/Dec/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Dmitr Sotnikov Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: string

Attachments: Text File string.clj.patch    
Patch: Code

 Description   

Add clojure.string/split-at similar to clojure.core/split-at that accepts a string and a number indicating the position where the string should be split. The function returns a vector containing two strings, first containing the characters from 0-n-1, and second n-length.



 Comments   
Comment by Alex Miller [ 03/Dec/14 9:48 PM ]

I do not think this is an operation that is fundamental (it can be easily composed from existing functions like count and subs) or represents a portability opportunity by being a function available on jvm and js with host performance benefits. It is a non-goal for clojure.string to contain every potentially useful string function.

Comment by Dmitr Sotnikov [ 03/Dec/14 11:04 PM ]

Makes sense, thanks for the clarification.





[CLJ-1594] Colons followed by spaces are not ignored within (comment ...) Created: 19/Nov/14  Updated: 22/Nov/14  Resolved: 22/Nov/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Ed Ward Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: bug, comment, function
Environment:

Ubuntu Linux 14.10
Clojure 1.6.0
OpenJDK 64-Bit Server VM 1.7.0_65-b32



 Description   

Running

(comment abc:def)
works, while running
(comment abc: def)
and
(comment abc : def)
fail with the exception

RuntimeException Invalid token: :  clojure.lang.Util.runtimeException (Util.java:221)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: def in this context, compiling:(/tmp/form-init1585368677683647130.clj:1:1010) 
RuntimeException Unmatched delimiter: )  clojure.lang.Util.runtimeException (Util.java:221)


 Comments   
Comment by Nicola Mometto [ 19/Nov/14 11:19 AM ]

`comment` is a macro, it doesn't bypess the reader.
":" is not a regular clojure token so it's expected that this throws.
The only way to include non clojure tokens in a source code is after a ";" comment

Comment by Andy Fingerhut [ 19/Nov/14 3:37 PM ]

I've just added some notes about this to ClojureDocs.org here: http://clojuredocs.org/clojure.core/comment

Comment by Alex Miller [ 22/Nov/14 9:12 AM ]

agreed with Nicola's comment above





[CLJ-1593] Use PAM for small maps when assigned to a var rather than always using PHMs Created: 15/Nov/14  Updated: 09/Mar/15  Resolved: 09/Mar/15

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Nicola Mometto Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: collections, compiler, maps

Attachments: Text File 0001-Use-PAM-rather-than-always-using-PHMs-for-small-maps.patch    
Patch: Code

 Description   

I'm reproposing the fix I implemented for http://dev.clojure.org/jira/browse/CLJ-944 a while ago as an enhancement rather than as a defect.

Currently when a map is used as the value of a `def` expression, unless it's an empty map, it will always be a PersistentHashMap even if it's a small map.

user=> (def a {:foo :bar})
#'user/a
user=> (class a)
clojure.lang.PersistentHashMap

The current patch makes makes small maps be compiled to PAMs, consistently with how it's handled in lexical contexts, only using PHMs when the number of elements is above the threshold

user=> (def a {:foo :bar})
#'user/a
user=> (class a)
clojure.lang.PersistentArrayMap
user=> (class (let [a {:foo :bar}] a))
clojure.lang.PersistentArrayMap
user=> (def a {0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9})
#'user/a
user=> (class a)
clojure.lang.PersistentHashMap


 Comments   
Comment by Alex Miller [ 15/Nov/14 12:17 PM ]

This might be subsumed under the small collections CLJ-1517, not sure.

Comment by Nicola Mometto [ 08/Dec/14 9:19 AM ]

This is now out of scope for CLJ-1517 now that's focused only on vectors.

Comment by Alex Miller [ 08/Dec/14 9:47 AM ]

We're just splitting the ticket apart, maps will be a separate ticket/patch.

Comment by Nicola Mometto [ 09/Mar/15 1:40 PM ]

This change has been included by Rich in commit https://github.com/clojure/clojure/commit/692645c73c86d12c93a97c858dc6e8b0f4280a0b#diff-f17f860d14163523f1e1308ece478ddb





[CLJ-1574] Vars defined in wrong namespace if ns form is not top-level Created: 28/Oct/14  Updated: 28/Oct/14  Resolved: 28/Oct/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6, Release 1.7
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Tassilo Horn Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

I have a macro that given some file containing some data model description generates an API for accessing instances of that data model. That's the scenario although it's not really relevant. I've tracked down the issue to this minimal example.

This does the right thing:

;; in namespace user
(do (ns myns1)
    (defn myns1-fn [] nil)
    (in-ns 'user))

A new namespace myns1 is created containing one var myns1-fn. Now I can call (myns1/myns1-fn) and get 1.

However, the following does not work correctly:

;; in namespace user
(when-not (find-ns 'myns2)
  (do (ns myns2)
    (defn myns2-fn [] nil)
    (in-ns 'user)))

My intention is not to re-create the namespace myns2 in case it already exists. However, the result after the first evaluation (where myns2 doesn't exist yet) is that a new namespace myns2 is created, but the var myns2-fn is created in the user namespace (or whatever the current namespace is).

I know that `do` has some special casing to allow the first example. And the second example has an `if` at the top-level, so that's probably why it doesn't work. But it seems like a legit thing to do to test if a namespace exists, and if not, define it. E.g., you might have some optional dependency, and if it's not fulfilled, you just define the vars that you need yourself.



 Comments   
Comment by Nicola Mometto [ 28/Oct/14 6:15 AM ]

You can do what you are asking for by using intern rather than def

Comment by Alex Miller [ 28/Oct/14 9:02 AM ]

Something like this should work:

(when-not (find-ns 'myns2)
  (create-ns 'myns2)
  (intern 'myns2 'myns2-fn (fn [] "hello")))
Comment by Tassilo Horn [ 28/Oct/14 10:17 AM ]

Thanks Nicola and Alex. Using `intern` and `create-ns` is probably the better approach as it works in both cases.

But shouldn't that be somehow visible from the docs? Currently, `ns` says it changes the current value of `ns`, and `def` says it defines a var in the current namespace (`ns`). That leaves the impression that the second example is valid.

So maybe the docs of `def` and `ns` should contain a sentence like "If you want to create namespaces/Vars dynamically, prefer using `create-ns`/`intern` over `ns`/`def`."

Comment by Nicola Mometto [ 28/Oct/14 10:28 AM ]

Tassillo, I don't think ns is problematic here.
The issue is that def interns the var at compile time rather than at runtime and thus uses the compile time value of ns rather than the runtime one.

Comment by Tassilo Horn [ 28/Oct/14 2:48 PM ]

Thanks for the clarification, Nicola.





[CLJ-1569] transduce does not respect the init arity of transducers Created: 19/Oct/14  Updated: 20/Oct/14  Resolved: 20/Oct/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.7
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Daniel James Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: transducers


 Description   

Note: I initially raised this issue for discussion on the mailing list
https://groups.google.com/d/msg/clojure/uVKP4_0KMwQ/-oUJahvUarIJ

transduce and other transducible processes currently ignore the 'init' arity of transducers. The currently implementation of transduce takes the 'init' from the reducing function before being transformed by the transducer, rather the reducing function after being transformed.

The current implementation of transduce is equivalent to the following (simplified for exposition purposes):

Current implementation of transduce
(defn transduce
  ([xform f coll]
     (transduce xform f (f) coll))
  ([xform f init coll]
     (let [rf (xform f)]
       (rf (reduce rf init coll)))))

The arity 3 case uses (f) to construct the seed value of the reduction. The arity 4 case uses the explicitly provided seed, init.

I would like to propose an alternate implementation of transduce, one which makes use of the transducer when seeding the reduction.

Proposed implementation of transduce
(defn alt-transduce
  ([xform f coll]
     (let [rf (xform f)]
       (rf (reduce rf (rf) coll))))
  ([xform f init coll]
     (let [rf (xform
               (fn
                 ([] init)
                 ([result] (f result))
                 ([result input] (f result input))))]
       (rf (reduce rf (rf) coll)))))

Now, the arity 3 case uses (xform f) to construct the seed value of the reduction. The arity 4 case combines both f and init into a new reducing function that is given to xform. Both of these ensure that the init arity of the transducer is used.

As into is implemented in terms of transduce, it is also taken care of. However, sequence is separate, and would also have to be tweaked to respect the init arity.



 Comments   
Comment by Daniel James [ 19/Oct/14 1:24 PM ]

As a small addition, I just wanted to point out an example of where the current implementation raised curiosity:
https://groups.google.com/d/msg/clojure/M-13lRPfguc/IspgdpKDaGsJ

Comment by Alex Miller [ 20/Oct/14 9:12 AM ]

In transduce, the transducer is applied to the elements of the input and should not be entangled with the accumulation at all (either in initializing it or the act of accumulation). f is the final reducing function that deals with accumulation and initialization.

Comment by Daniel James [ 20/Oct/14 10:00 AM ]

Hi Alex,

I feel that you've misunderstood my proposal.

Could you explain how you consider

(defn init-with [x]
  (fn [rf]
    (fn
      ([] (rf (rf) x))
      ([result] (rf result))
      ([result input] (rf result input)))))

to be “entangled with the accumulation at all (either in initializing it or the act of accumulation).”

This seems like a completely legitimate transducer to me. It makes use of the init arity, while remaining oblivious to the accumulation.

Your explanation also seems to be at odds with

http://clojure.org/transducers

The inner function is defined with 3 arities used for different purposes:

  • Init (arity 0) - in most cases, this will just call the init arity on the nested transform xf, which will eventually call out to the transducing process to supply an initial value. It is also a place to establish the initial reducing state for the transducer.
Comment by Alex Miller [ 20/Oct/14 11:57 AM ]

By "entangling" I mean that in your alternate transduce you invoke the xform to obtain the initial value: ((xform f)) instead of (f). Transducers should not know about or be involved in the accumulating process.

The transducers page is in error and I will correct it (I wrote it; the error is mine).

Comment by Daniel James [ 20/Oct/14 3:25 PM ]

Ok, at the risk of belaboring the point (I have enough self-awareness to realized that I am probably about to do exactly that…) I feel that you are still missing something here.

Permit me to try one more time to explain my position.

Consider map

the map transducer
(defn map [f]
  (fn [rf]
    (fn
      ([] (rf))
      ([result] (rf result))
      ([result input] (rf result (f input))))))

It defines all three arities, init, step, and completion. It doesn’t have anything to do in init arity, and so the only thing it can do is “call the init arity on the nested transform rf, which will eventually call out to the transducing process.” (taken from your update to http://clojure.org/transducers)

Saying that transducers should not be involved in the accumulating process has the right spirit, but you are missing something. It is involved, but in a strictly constrained way. The transducer’s responsibility is to carefully thread the accumulator value around. Sure, it should not know what the value is, or what type it has, but it is still there. Every arity of map has access to it! In the init arity, map delegates to rf to construct it. In the completion arity, map has the result, but the only valid thing it can do with it is to pass it on to rf. Again, in the step arity, map has the result, and again the only legitimate thing it can do with it is to thread to through to rf.

Now consider the identity transducer:

the identity transducer
(def identity
  (fn [rf]
    ([] (rf))
    ([result] (rf result))
    ([result input] (rf result input))))

This is a transducer in its purest form. All it has to do is correctly thread the accumulation value around. It doesn’t and shouldn’t know any details of what that value is, nonetheless, it still has the responsibility of threading that value correctly.

In each arity the identity transducer does the ‘trivial’ thing. In my post to the mailing list, I illustrated three example of transducers that do something beyond the trivial thing in each of the three arities. (I’ll copy them here for completeness.)

non trivial threading of the accumulator in the init arity
(defn init-with
  [x]
  (fn [rf]
    (fn
      ([] (rf (rf) x))
      ([result] (rf result))
      ([result input]
         (rf result input)))))
non trivial threading of the accumulator in the completion arity
(defn complete-with
  [x]
  (fn [rf]
    (fn
      ([] (rf))
      ([result]
         (rf (rf result x)))
      ([result input]
         (rf result input)))))
non trivial threading of the accumulator in the step arity
(defn dupl
  []
  (fn [rf]
    (fn
      ([] (rf))
      ([result] (rf result))
      ([result input]
         (rf (rf result input)
             input)))))

I would consider all of these to be perfectly valid transducers. However, unless I’ve misunderstood, you appear to be taking issue with init-with. If so, I’m very curious as to why!

a closer look at the init arity of init-with
(defn init-with
  [x]
  (fn [rf]
    (fn
      ([] (rf (rf) x))
      ...

Rather than just delegating to (rf), it threads that value immediately into rf with (rf (rf) x). So I don’t agree at all that any of these, init-with, complete-with, or dupl, are “entangled” with the accumulation value or the accumulation process. They are completely oblivious to both its value and its type!

So, returning to transduce,

the first case of an alternate transduce
(defn alt-transduce
  ([xform f coll]
     (let [rf (xform f)]
       (rf (reduce rf (rf) coll))))
  ...

A valid transducer is one that threads the accumlation value correctly. Therefore, ((xform f)) is (f) threaded through xform. All the transducers in clojure.core have the trivial ([] (rf)), so ((xform f)) built from these core transducers degenerates into (identity (f)).
However, as transduce, into, and sequence never even invoke the init arity, it begs the question, why even require that transducers have that arity in the first place? Personally, I think that init arity is great as it enables a transducer such as init-with (while remaining stateless), but that requires transducible processes to actually make use of the init arity! Hence why I raised this issue.
It seems troubling to me that complete-with works perfectly fine in the current framework, yet init-with, its dual, does not.

I recognize that the various discussions around ‘typing transducers’ have made various approximations at elucidating the properties of transducers, but I feel strongly that the discussions around rank-2 polymorphism have some bearing on exactly this issue. In fact, it says rather a lot about correctly threading the accumulation value throught transducers without ever “entangling” it in the precise accumulation process of where a transducer is being used.

And on this, it appears that Rich Hickey agrees: “The rank-2 type in particular captures an important property.” (http://conscientiousprogrammer.com/blog/2014/08/07/understanding-cloure-transducers-through-types/#comment-1533318972) Maybe I’ve got him all wrong, but as of right now I’m pretty convinced I don’t. Still, I’m willing to be convinced otherwise

Comment by Alex Miller [ 20/Oct/14 10:03 PM ]

Rich asked me to decline the ticket because the init arity of the xform should not be involved in the reducing function accumulation.

Comment by Daniel James [ 20/Oct/14 10:34 PM ]

Ok, as you can guess I’m a little perplexed by that design choice, but I’ll accept it.

I’d appreciate any further insight you can offer on why this design choice has been taken.
Is the init arity simply a case of compatibility, despite it not being used? Is this a case of attempting to prevent the transducer writer from erroneously corrupting a transducible process? Is init-with actually actually considered to be an invalid transducer, and thus the only way to implement something equivalent would be as a stateful transducer?





[CLJ-1564] Sum/sub decimals operation bug Created: 15/Oct/14  Updated: 15/Oct/14  Resolved: 15/Oct/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Defect Priority: Critical
Reporter: Luca Gugole Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: math

Patch: Code

 Description   

The result of operation (+ 0.7 0.1) is 0.7999999999999999 and not 0.7

Other operations with the same behaviour:
(+ 0.11 0.1) => 0.21000000000000002
(+ 0.31 0.1) => 0.41000000000000003
(- 0.8 0.1) => 0.7000000000000001
(- 0.41 0.1) => 0.30999999999999994



 Comments   
Comment by Oliver Charles [ 15/Oct/14 6:44 AM ]

Uh, isn't this just normal floating point arithmetic?

Comment by Luca Gugole [ 15/Oct/14 7:32 AM ]

But the result of other operations ((+ 0.1 0.1), (+ 0.2 0.2), (+ 0.2 0.3) ...) has only one decimal place.
It's normal?
I have to perform a math round operation to obtain only one decimal place?

Comment by Jozef Wagner [ 15/Oct/14 7:41 AM ]

This is not a bug. Please read What Every Programmer Should Know About Floating-Point Arithmetic

Comment by Luca Gugole [ 15/Oct/14 7:51 AM ]

Sorry about my lack of knowledge on this subject.
Thank you for the answer.





[CLJ-1559] A function bound in let can only be used in a macro if it is parameterless Created: 09/Oct/14  Updated: 10/Oct/14  Resolved: 09/Oct/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6, Release 1.7
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Colin Smith Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

MacOS


Attachments: File stack.trace    

 Description   

This works:

(defn make-fn [] (fn [x] (+ 3 x)))

(defmacro m [x]
(let [a-function (make-fn)]
`(fn [z#]
(+ ~x (~a-function z#)))))

(prn ((m 1) 2))

;;;;;;;;;;;;;;;;;;

But this does not (adding a parameter to make-fn foils things):

(defn make-fn [y] (fn [x] (+ y x)))

(defmacro m [x]
(let [a-function (make-fn 3)]
`(fn [z#]
(+ ~x (~a-function z#)))))

(prn ((m 1) 2))

;;;;;;;;;;;;;;;;;;;

stack trace attached.



 Comments   
Comment by Alex Miller [ 09/Oct/14 11:51 PM ]

At a glance, you appear to be dropping the evaluated function object (a-function) inside the syntax quote, which is pretty much always a problem in how the macro is written.

Probably really want something like:

(defn make-fn [y] (fn [x] (+ y x)))
(defmacro m [x] 
  `(let [a-function# (make-fn 3)]
     (fn [z#] (+ ~x (a-function# z#)))))
(prn ((m 1) 2))
Comment by Alex Miller [ 09/Oct/14 11:53 PM ]

If you look at the expanded macro in your example:

user=> (pprint (clojure.walk/macroexpand-all '(prn ((m 1) 2))))
(prn
 ((fn*
   ([z__25__auto__]
    (clojure.core/+
     1
     (#<user$make_fn$fn__22 user$make_fn$fn__22@72995b29>
      z__25__auto__))))
  2))

Any time you see something like #<user$make_fn$fn_22 user$make_fn$fn_22@72995b29>, that's a good hint.

Comment by Colin Smith [ 10/Oct/14 1:21 AM ]

Thank you Alex. I had done the macro expansion.

I see my mistake: I am coming to Clojure from Scheme, where the result of (lambda ...) is a primitive value that I could expect to paste into the form produced by a macro. Now, I get the impression that (fn) is not required to produce quite that sort of thing.
Would you say that's the right way to look at it?

Thanks for looking at this so quickly! I am back on track.





[CLJ-1558] lazy-seq and seq return different values for (lazy-seq []) (seq []) Created: 09/Oct/14  Updated: 09/Oct/14  Resolved: 09/Oct/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Jeremy Betts Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

(lazy-seq [])
=> ()
(seq [])
=> nil

would expect both to return nil



 Comments   
Comment by Andy Fingerhut [ 09/Oct/14 10:02 AM ]

Jeremy, lazy-seq's documentation string says it: "returns a Seqable object that will invoke the body only the first time seq is called". Even (lazy-seq nil) does not return nil. seq's documentation string explicitly says that it will return nil for empty collections.

What leads you to expect both to return nil?

Comment by Alex Miller [ 09/Oct/14 10:12 AM ]

Working as expected per docs.

seq -> returns a sequence
lazy-seq -> returns a seqable (when seq is called on it, will return a sequence)

Comment by Jeremy Betts [ 09/Oct/14 10:38 AM ]

I listed as enhancement and not defect based on documentation.
lazy-seq:
"Takes a body of expressions that returns an ISeq or nil, and yields
a Seqable object that will invoke the body only the first time seq
is called, and will cache the result and return it on all subsequent
seq calls. See also - realized?"

it's not clearly stated what it should return for [] where as for seq, it clearly stated that it will return nil for [].

given the intent of lazy-seq is to make the same result as seq, except that its members are evaluated when called for and not upfront.

The current implementation forces code to be aware of if it's dealing with lazy or non lazy sequences. This is not ideal.

Once again, listed as feature enhancement, because of the less than ideal design and documentation. Listed as minor, as it's fairly easy to work around it.

-Jeremy

Comment by Jeremy Betts [ 09/Oct/14 10:41 AM ]

how do i reopen this as the answers to this are not well thought out.

Comment by Alex Miller [ 09/Oct/14 11:57 AM ]

Despite the similarity in naming, seq and lazy-seq have different purposes which I believe are adequately stated in their doc strings. Of particular note, the intent of lazy-seq is NOT to make a seq, but to make a seqable (conceptually similar to the difference between Iterator and Iterable in Java).

Sequences are a logical list. Empty sequences are represented by nil. seq produces a sequence from the input. Because it produces either nil or a sequence with at least one value, seq is often used in a condition or termination check when walking through a sequence.

lazy-seq is a tool that can be used to create lazy sequences from a function, but it delays that computation by returning a seqable (not a seq) so that computation will only be forced at the point where you start producing a seq from it.

Most sequence functions implicitly call seq on their input (thus producing seqs from seqables), so the difference between them can often be missed.

[] is a seqable. lazy-seq will itself call seq on the result of the generator function if it is not a lazy seq. So, you give [] to lazy-seq and it creates a seqable with a function that returns []. When you call seq on the seqable, the function is evaluated to a PersistentVector (not a lazy seq) and then seq is called on it, which produces a nil, which is returned.

I do not see how this affects callers. Because sequence functions implicitly call seq, all of the sequence functions will work with either and yield the same results. Explicit use of lazy-seq is relatively rare (it's most commonly used when a sequence is produced by repeated evaluation of a function).

You might find this page to be helpful: http://clojure.org/sequences

Comment by Jeremy Betts [ 09/Oct/14 1:06 PM ]

(if (lazy-seq []) "yes" "no")
=> "yes"
(if (seq []) "yes" "no")
=> "no"

The truth value of an empty seq and an empty lazy-seq is different.

I guess i'm still not understand why this would be a "bad" change to the behavior?

Comment by Andy Fingerhut [ 09/Oct/14 1:15 PM ]

Jeremy, a lot of Clojure code uses the return value of seq in the way you show in your example to decide whether there is more to a sequence to process.

I have never seen Clojure code use lazy-seq for any purpose other than to construct a lazy sequence and return it from a recursive function, to avoid blowing the stack.

(lazy-seq x) returns a truthy value for all values of x, even nil.

Comment by Jozef Wagner [ 09/Oct/14 1:30 PM ]

Jeremy, have look on a sequence if you do not want nil returned. And Andy had a good point. lazy-seq is a constructor of LazySeq type, and as such should not return nil. seq returns either nil or an object that implements ISeq interface, but does not prescribe any concrete type. the nil return value from seq is a feature and is a one of differences between how seq and sequence behaves.

Comment by Jeremy Betts [ 09/Oct/14 2:16 PM ]

Jozef Wagner's answer is good. 'sequence' is the equivalent to 'lazy-seq' This was a problem for me as the laziness of something could not be changed without the inadvertent changing of behavior. This is what i ran into and why i entered the issue.

I'd still argue that a document update would would be a good thing.

-Jeremy





[CLJ-1547] range cause OutOfMemoryError when start > end AND step is zero Created: 04/Oct/14  Updated: 04/Oct/14  Resolved: 04/Oct/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6, Release 1.7
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Édipo L Féderle Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

Mac OSX 10.9.4
java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)



 Description   

I am playing with range function and I tried the following args:

(range 10 4 0) ;=> OutOfMemoryError

I add a test on range code to check for this condition, but probably I dont do it right, one test fail and I dont know why. If this is really a bug and someone can help me with this patch I appreciate it.



 Comments   
Comment by Nicola Mometto [ 04/Oct/14 8:43 AM ]

Not a bug, the docstring is explicit about this: "When step is equal to 0, returns an infinite sequence of start."

Comment by Édipo L Féderle [ 04/Oct/14 8:49 AM ]

Oh yeah, my fault. I will close this "issue".

Thanks Nicola.

Comment by Édipo L Féderle [ 04/Oct/14 8:49 AM ]

not a bug





[CLJ-1540] Make main function to run when using on the fly compilation, not just ahead-of-time compilation Created: 29/Sep/14  Updated: 29/Sep/14  Resolved: 29/Sep/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: macdevign Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

From this doc
http://clojure.org/compilation

Clojure compiles all code you load on-the-fly into JVM bytecode, but sometimes it is advantageous to compile ahead-of-time (AOT). Some reasons to use AOT compilation are:
To generate named classes for use by Java among the reason

and only named classes can run off main function.

So if not using AOT, the main method will not be executed.

Hence the following main can only run in AOT using named classes.
(defn -main
(println "runme")))

Will that be possible to run the main function using on the fly compilation ?

Basically, it should work similarly to Java. If the clojure file has a main function then it should run the file if user select it to run (eg in IDE) regardless of mode of compilation.

For example, in IntelliJ ide, a clojure file (eg hello.clj) has the following code

(defn testme[]
(println "hello"))

(defn -main
(println "runme")
(testme))

if user choose "Run hello.clj" from Intellij, then it should execute the main function.

Will be great if this feature is consider in next release of clojure

thank



 Comments   
Comment by Alex Miller [ 29/Sep/14 12:49 PM ]

There are (already) a variety of ways to start a Clojure script or program and I believe what you request (and more) is already possible.

See: http://clojure.org/repl_and_main

An example command-line for your hello.clj example would be:

java -cp clojure.jar clojure.main -i hello.clj -e "(-main)"

but if you are only running this as a script you could embed the code to run your app at the end of the hello.clj script file and do:

java -cp clojure.jar clojure.main hello.clj
Comment by Kevin Downey [ 29/Sep/14 3:44 PM ]

checkout the `-m` option





[CLJ-1539] Allow Records to be imported "Normally" Created: 28/Sep/14  Updated: 28/Sep/14  Resolved: 28/Sep/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: David Williams Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

I know about records, and how they are compiled to Java classes, etc. The thing is, the import of a record type has an undocumented quirk, the need to turn dashes into underscore

(:require [my-fancy.namespace])
(:import [my_fancy.namespace MyRecord])

Granted this is trivial, but I just spent an hour or two tracking this down after some initial unsuccessful attempts to import a record between namespaces. IMHO this is not user friendly and could be smoothed out.



 Comments   
Comment by Alex Miller [ 28/Sep/14 10:42 PM ]

There are no plans to change this. Typically you don't need to import the record class at all, just require the ns and use the > and map> constructor functions. When you do import the class, you are doing so as a Java class, so it follows java class import rules.





[CLJ-1525] bean function returns mutable maps Created: 16/Sep/14  Updated: 22/Sep/14  Resolved: 22/Sep/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Simone Mosciatti Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

Linux



 Description   

Please take a look at this snippet.

user> (import 'java.util.Date)
java.util.Date
user> (def now (Date.))
#'user/now
user> now
#inst "2014-09-17T03:14:13.821-00:00"
user> (def bean-map (bean now))
#'user/bean-map
user> bean-map
{:day 3, :date 17, :time 1410923653821, :month 8, :seconds 13, :year 114, :class java.util.Date, :timezoneOffset -120, :hours 5, :minutes 14}
user> (.setMonth now 1)
nil
user> bean-map
{:day 1, :date 17, :time 1392610453821, :month 1, :seconds 13, :year 114, :class java.util.Date, :timezoneOffset -60, :hours 5, :minutes 14}

The same snippet here. https://gist.github.com/siscia/032bff669bbc6fb0fe57



 Comments   
Comment by Jozef Wagner [ 17/Sep/14 1:32 AM ]

It works as expected. bean fn returns a clojuresque abstraction on top of live bean. map-like abstraction returned from bean is intended to be 'mutable' in sense that it always return the latest value. Otherwise it is read only.

Comment by Simone Mosciatti [ 17/Sep/14 1:42 AM ]

Hi,

sorry, the documentation didn't mention the "mutable" part so I was expecting an immutable map as always.

Sorry, about that.

Greets

Comment by Alex Miller [ 22/Sep/14 9:38 AM ]

this is the expected behavior





[CLJ-1505] Sorry I have to enter this test bug Created: 15/Aug/14  Updated: 15/Aug/14  Resolved: 15/Aug/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Karen Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

Interacting with this site caused FireFox to freak out when populating a field in our app so I need to enter a bug here to figure out why. See http://dev.clojure.org/jira/browse/CLJ-1378 We get the same error message in one of our summary field. It is a FireFox bug so I'll update this when I am done. Apologies.






[CLJ-1500] Cache namespace env Created: 08/Aug/14  Updated: 08/Aug/14  Resolved: 08/Aug/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Nicola Mometto Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

See: https://github.com/clojure/tools.analyzer.js/blob/master/src/main/clojure/clojure/tools/analyzer/js.clj#L524-L548






[CLJ-1476] map-invert should use (empty m) instead of {} Created: 26/Jul/14  Updated: 27/Jul/14  Resolved: 27/Jul/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Gregory Schlomoff Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

clojure.set/map-invert should reduce with (empty m) instead of {} so that it returns a map of the same type as its argument.

This is a trivial change and I'm willing to submit a patch if nobody opposes.



 Comments   
Comment by Alex Miller [ 26/Jul/14 8:43 AM ]

I don't think that always makes sense. Say you had a map of string to integers with a custom comparator created by sorted-map-by. If you use empty, you'd still have a map with a custom comparator which you would pour integer keys into and would likely throw a ClassCastException.

What is the use case that led you to this ticket?

Comment by Gregory Schlomoff [ 26/Jul/14 9:14 AM ]

Hello Alex, thanks for commenting.

My use case is that I have a custom type that implements IPersistentMap. If I use map-invert over it, I get a regular map back, which is problematic because regular maps don't allow multiple values for the same key, unlike my multimap implementation, so I loose information.

(map-invert (my-multimap :a 1, :b 1))
=> {1 :b} ; lost the (1 :a) entry because regular maps don't allow duplicate keys

Maybe a solution would be to make a version of map-invert that takes a map to insert the inverted entries into?

I'm not adamant over this, if you think there is no elegant solution for this issue we can close it.

Comment by Alex Miller [ 27/Jul/14 7:28 AM ]

I don't think this enhancement makes sense as written - there are cases where it would be a breaking change for existing code.

I do think your specified problem makes sense though. One enhancement might be to have a variant of map-invert (different arity or map-invert-into that took an additional map target param).





[CLJ-1474] `reduced` docstring should be more explicit Created: 25/Jul/14  Updated: 27/Jul/14  Resolved: 25/Jul/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Jean Niklas L'orange Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: docstring


 Description   

The documentation for reduced is as follows:

Wraps x in a way such that a reduce will terminate with the value x

From what I gather, this does not specify whether the init value of a reduce could be a reduced value or not. As shown, the fact that the init value is a reduced value is ignored:

(reduce list (reduced 1) [2])
=> (#<Reduced@518a6aa: 1> 2)

The documentation should explicitly mention that a reduce call will not check if the initial value is reduced.



 Comments   
Comment by Alex Miller [ 25/Jul/14 9:09 AM ]

reduced creates a value that has special meaning as the output of invocation of the reducing function. Your example is about an input to that function. I don't see that this makes sense or needs documenting.

You can of course invent a situation where a (reduced 1) input is also the output but again, that seems like a pretty weird use case.

(reduce (fn [a v] a) (reduced 1) [2])
;; 1
Comment by Jean Niklas L'orange [ 25/Jul/14 12:10 PM ]

Right, that's my point. Nowhere in the documentation does it state that this does not apply to the initial value given to reduce. While you and I know this, I don't see how one can conclude this based on the current documentation.

Put differently, someone might wrongly assume that reduce is implemented as an optimised version of this:

(defn reduce [f init coll]
  (cond (reduced? init) (unreduced init)
        (empty? coll)    init
        :else           (recur f (f init (first coll))
                                 (rest coll))))

However, that's not the case, which I think is worth pointing out.

Comment by Alex Miller [ 25/Jul/14 5:01 PM ]

But it might apply to the initial value (as in my example where a reduced value is respected - note that doesn't return (reduced 1), just 1). Your suggested documentation change is talking about input values, but in my mind that leads to incorrect conclusions.

The only change that would make sense to me is clarifying where a "reduced" value is checked (on the result of applying the function passed to reduce). I think that's already implicit in the existing doc string myself. Since we have multiple implementations of "reduce", we have to tread carefully not to refer to explicitly to a particular one.

This use of a reduced initial value does not even make sense; why we would we confuse the docstring to warn about it?

Comment by Jean Niklas L'orange [ 27/Jul/14 7:20 AM ]

Ah, I get your point now, and I see how this would just create more confusion.

Thanks for the explanation.





[CLJ-1468] Add deep-merge and deep-merge-with Created: 18/Jul/14  Updated: 18/Jul/14  Resolved: 18/Jul/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Stuart Sierra Assignee: Unassigned
Resolution: Declined Votes: 1
Labels: None

Attachments: Text File CLJ-1468-deep-merge-01.patch    
Patch: Code and Test
Approval: Triaged

 Description   

When dealing with nested map structures, one often wants to merge two maps recursively.

The deep-merge-with function was originally written by Chris Houser for clojure.contrib.map-utils but was not maintained after clojure-contrib was split into separate modules.

deep-merge and deep-merge-with are widely copied, usually with the same implementation, in utility libraries. For example:



 Comments   
Comment by Rich Hickey [ 18/Jul/14 11:42 AM ]

Vague semantics and docs strings





[CLJ-1465] SubVector leaks memory by design (?) Created: 14/Jul/14  Updated: 14/Jul/14  Resolved: 14/Jul/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Szymon Witamborski Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: memory


 Description   

While reading through the code of SubVector class, I've noticed that the only thing that it does is creating a "subview" of an existing vector without doing anything to elements that are not accessible any more. Please correct me if I'm wrong but I think this leads to memory leaks in this scenario:

(let [a [1 2 3 4 5]
      b (subvec a 2 3)]
  b)
[3]

In this example we no longer have any reference to a once the (let...) expression returned. Elements of a that are no longer accessible will not be garbage collected until b is garbage collected because b still holds a reference to a (the v field in SubVector class). Ideally, these elements should be garbage collectible as soon as a is gone.



 Comments   
Comment by Alex Miller [ 14/Jul/14 2:40 PM ]

The subvec docstring says:

"Returns a persistent vector of the items in vector from start (inclusive) to end (exclusive). If end is not supplied, defaults to (count vector). This operation is O(1) and very fast, as the resulting vector shares structure with the original and no trimming is done."

The implementation is intentional to make this a constant-time operation. If you are willing to make the tradeoff re shared structure and object retention, this constant operation has better performance. In other words: working as intended.





[CLJ-1464] Incorrectly named parameter to fold function in reducers.clj Created: 12/Jul/14  Updated: 10/Sep/14  Resolved: 10/Sep/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Trivial
Reporter: Jason Jackson Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None

Attachments: Text File 0001-Rename-a-function-parameter-to-reflect-the-fold-func.patch    
Patch: Code
Approval: Triaged

 Description   

https://github.com/clojure/clojure/blob/master/src/clj/clojure/core/reducers.clj#L95
The 2-arity fold accepts reducef as parameter and then uses it as a combinef.
Instead it should accept combinef as parameter and then use it as a reducef, as every combine fn (monoid) is a reduce fn, but not every reduce fn is a combine fn (it's not associative).



 Comments   
Comment by Jason Jackson [ 12/Jul/14 2:58 PM ]

this is my first patch for clojure please double check everything. CA is done.

Comment by Andy Fingerhut [ 12/Jul/14 7:29 PM ]

Everything gets double checked whether it is your first patch or your 50th

At least as far as the format of the patch being correct, that it applies cleanly to the latest version of Clojure on the master branch, compiles and passes all tests cleanly, all of that is good.

Whether there is interest in taking your proposed change is to be decided by others. It may be some time before it is examined further.

Comment by Jozef Wagner [ 13/Jul/14 4:11 AM ]

This is not a defect. Quoting Rich, "If no combining fn is supplied, the reducing fn is used." (source)

There are three user supplied operations in fold: getting identity element (combinef :: -> T), reducing function (reducef :: T * E -> T) and combining function (combinef :: T * T -> T). For reduce, combining function is not needed but the rest two operations are needed. Thus reducing function (reducef) supplies identity element for reducers and only in folders the identity element is produced by combining function. In case where reducing fn is used for both reducing and combining, it must of course be associative and must handle objects of types T and E as a second argument.

Comment by Jason Jackson [ 14/Jul/14 12:14 AM ]

@Jozef I appreciate the feedback I still think my patch is correct, although I admit everyone's time is better spent not debating this small refactoring so feel free to close it.

One perspective to view my patch from is if we had protocols p/Monoid and p/Reducer. It's possible to reify any object that implements p/Monoid into p/Reducer, but not the other way around since not every p/Reducer is associative.

Comment by Jason Jackson [ 14/Jul/14 12:30 AM ]

From that perspective you could also say that in the 2-arity case the parameter "reducef" requires objects that implement both p/Monoid and p/Reducer, but in the 3-arity case the parameter "reducef" only requires p/Reducer

Comment by Jozef Wagner [ 14/Jul/14 1:38 AM ]

Note that reducef and combinef take different type of second argument, so not every combining function can be used as a reducing one. Your proposal is thus no better than the status quo. Consider following example:

(fold clojure.set/union conj [1 1 2 2 3 3 4 4])




[CLJ-1450] Add a variant of range that's inclusive with respect to its upper boundary Created: 19/Jun/14  Updated: 19/Jun/14  Resolved: 19/Jun/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Bozhidar Batsov Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

Such a variant of range might behave like this:

```
(irange 1 5)
;;=> (1 2 3 4 5)

(irange 1 2 5)
;;=> (1 3 5)
```

I'm suggesting this because often in practice we have to deal with inclusive ranges and having to add 1 to the upper boundary in such scenarios seems to reduce the clarity of the code. I guess something like this applies to some extend to lower boundary as well:

```
(erange 1 5)
;;=> (2 3 4)
```



 Comments   
Comment by Alex Miller [ 19/Jun/14 2:55 PM ]

We're not interested in adding these to core, thanks.





[CLJ-1448] Suggest alength in error message on attempt to access array length via .length Created: 19/Jun/14  Updated: 19/Jun/14  Resolved: 19/Jun/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: Colin Taylor Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: errormsgs

Attachments: Text File dot-length-recommend-alength.patch    
Patch: Code

 Description   

Problem:

Newcomers are easily confused by the inability to access <array>.length via (.length <array>).

Approach:

Append to invalid field access message, a suggestion to use alength for this specific case (class.isArray and field = "length")

user=> (.length (int-array 2))
IllegalArgumentException No matching field found: length for class [I, use alength function for array length


 Comments   
Comment by Alex Miller [ 19/Jun/14 2:56 PM ]

We don't have any plans to add anything this specific to the error check, thanks.





[CLJ-1440] Unable to exclude clojure.lang.Compiler using :refer-clojure Created: 06/Jun/14  Updated: 07/Jun/14  Resolved: 07/Jun/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Howard Lewis Ship Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: compiler, interop


 Description   
(ns io.aviso.twixt.js-minification
  "Provides support for JavaScript minification using the Google Closure compiler."
  (:refer-clojure :exclude [Compiler])
  (:import (com.google.javascript.jscomp CompilerOptions ClosureCodingConvention DiagnosticGroups CheckLevel
                                         SourceFile Result Compiler))
  (:require [clojure.java.io :as io]
            [io.aviso.twixt.utils :as utils]
            [io.aviso.tracker :as t]
            [clojure.string :as str]))

Results in:

clojure.lang.Compiler$CompilerException: java.lang.IllegalStateException: Compiler already refers to: class clojure.lang.Compiler in namespace: io.aviso.twixt.js-minification, compiling:(/Users/hlship/workspaces/annadale/twixt/src/io/aviso/twixt/js_minification.clj:1:1)
        java.lang.IllegalStateException: Compiler already refers to: class clojure.lang.Compiler in namespace: io.aviso.twixt.js-minification
                                     clojure.lang.Namespace.referenceClass                    Namespace.java:  140
                                        clojure.lang.Namespace.importClass                    Namespace.java:  158
                                        clojure.lang.Namespace.importClass                    Namespace.java:  164
                   io.aviso.twixt.js-minification/eval4104/loading--auto--               js_minification.clj:    1
                                   io.aviso.twixt.js-minification/eval4104               js_minification.clj:    1
                                                clojure.lang.Compiler.eval                     Compiler.java: 6703
                                                clojure.lang.Compiler.eval                     Compiler.java: 6692
                                                clojure.lang.Compiler.load                     Compiler.java: 7130
                                   io.aviso.twixt.js-minification/eval4100  form-init4106199735960171933.clj:    1
                                                clojure.lang.Compiler.eval                     Compiler.java: 6703
                                                clojure.lang.Compiler.eval                     Compiler.java: 6666
                                                         clojure.core/eval                          core.clj: 2927
                                      clojure.main/repl/read-eval-print/fn                          main.clj:  239
                                         clojure.main/repl/read-eval-print                          main.clj:  239
                                                      clojure.main/repl/fn                          main.clj:  257
                                                         clojure.main/repl                          main.clj:  257
                                                clojure.lang.RestFn.invoke                       RestFn.java: 1096
             clojure.tools.nrepl.middleware.interruptible-eval/evaluate/fn            interruptible_eval.clj:   56
                                            clojure.lang.AFn.applyToHelper                          AFn.java:  152
                                                  clojure.lang.AFn.applyTo                          AFn.java:  144
                                                        clojure.core/apply                          core.clj:  624
                                               clojure.core/with-bindings*                          core.clj: 1862
                                                clojure.lang.RestFn.invoke                       RestFn.java:  425
                clojure.tools.nrepl.middleware.interruptible-eval/evaluate            interruptible_eval.clj:   41
clojure.tools.nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn            interruptible_eval.clj:  171
                                                      clojure.core/comp/fn                          core.clj: 2402
             clojure.tools.nrepl.middleware.interruptible-eval/run-next/fn            interruptible_eval.clj:  138
                                                      clojure.lang.AFn.run                          AFn.java:   22
                         java.util.concurrent.ThreadPoolExecutor.runWorker           ThreadPoolExecutor.java: 1145
                        java.util.concurrent.ThreadPoolExecutor$Worker.run           ThreadPoolExecutor.java:  615
                                                      java.lang.Thread.run                       Thread.java:  724


 Comments   
Comment by Nicola Mometto [ 06/Jun/14 4:52 PM ]

refer and thus refer-clojure only works for Vars.
a workaround is:

(ns ..)
(ns-unmap *ns* 'Compiler)
(import 'com.google.javascript.jscomp.Compiler)
Comment by Alex Miller [ 07/Jun/14 11:34 AM ]

Ditto what Nicola said. Or just fully-qualify.





[CLJ-1426] "/" in keyword leads to unexpected behavior when calling `name` Created: 18/May/14  Updated: 21/May/14  Resolved: 21/May/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Darrell Hamilton Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

Because `clojure.lang.Keyword` delegates it's `getName` functionality to `clojure.lang.Symbol`, there is some unexpected behavior when calling `name` on a keyword that contains a "/" in it. For example:

(name (keyword "foo/bar"))
=> "bar"

This is due to `Symbol` stripping all namespace qualifiers and considering only the content trailing the "/" as part of the name.



 Comments   
Comment by Darrell Hamilton [ 20/May/14 9:29 PM ]

Totally misunderstood the behavior of namespaced keywords. this can be closed.

/derp





[CLJ-1404] clojure.core/vals returns nil on an empty map instead of an empty sequence Created: 14/Apr/14  Updated: 14/Apr/14  Resolved: 14/Apr/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Trivial
Reporter: Satshabad Khalsa Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

Is this a bug? maybe I just don't understand. The documentation says: Returns a sequence of the map's values. Is nil a sequence?

This caused an unexpected nil to propagate through a bunch of list processing stuff.



 Comments   
Comment by Alex Miller [ 14/Apr/14 10:54 PM ]

An empty sequence is represented by nil, so this is consistent. For example: (seq (range 0)) => nil





[CLJ-1397] exception testing broken over map Created: 01/Apr/14  Updated: 01/Apr/14  Resolved: 01/Apr/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Defect Priority: Major
Reporter: MG Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: test
Environment:

Linux ... 3.2.0-56-generic-pae #86-Ubuntu SMP ... i686 i686 i386 GNU/Linux



 Description   

Expected: Tests pass
Actual: Two tests fail
To reproduce, run the following test file:

(ns pe.test-test
(:require [clojure.test :refer :all]))
(defn throwexc [m] (throw (Exception. m)))
(defn throwass [m] (assert false m))
(defn nestexc [] (throwexc "exc"))
(defn nestass [] (throwass "ass"))
(defn nestmapexc [] (map throwexc '("a" "b" "c")))
(defn nestmapass [] (map throwass '("a" "b" "c")))
(deftest exceptions-and-assertions-test
(testing "throwing"
(is (thrown? Exception (throwexc "exc")))
(is (thrown? AssertionError (throwass "ass"))))
(testing "nesting"
(is (thrown? Exception (nestexc)))
(is (thrown? AssertionError (nestass))))
(testing "nesting over map"
(is (thrown? Exception (nestmapexc)))
(is (thrown? AssertionError (nestmapass)))))



 Comments   
Comment by MG [ 01/Apr/14 7:25 AM ]

Clarification: The two assertions in "nesting over map" fails, the other four assertions succeed.

Comment by Nicola Mometto [ 01/Apr/14 7:30 AM ]

map is lazy, the exception is never thrown because the sequence is never realized.
either wrap the map in a dorun or use a doseq instead of a map.
map should not be used for side-effecting





[CLJ-1396] Bad link Created: 01/Apr/14  Updated: 01/Apr/14  Resolved: 01/Apr/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Trivial
Reporter: MG Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

http://richhickey.github.io/clojure/



 Description   

http://richhickey.github.io/clojure/
The issue tracker link points to Assembla.



 Comments   
Comment by Nicola Mometto [ 01/Apr/14 7:31 AM ]

That site is deprecated and so is the repo that's hosting it.
This is the updated one http://clojure.github.io/clojure/

Comment by Alex Miller [ 01/Apr/14 7:45 AM ]

Nicola, I agree with your assessment here but only screeners should be closing tickets, thanks.

Comment by Nicola Mometto [ 01/Apr/14 7:50 AM ]

Alex, sorry, I didn't know this, I will refrain from doing so in the future.





[CLJ-1395] get should deref delay, refs atoms etc Created: 01/Apr/14  Updated: 01/Apr/14  Resolved: 01/Apr/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Gerrit Jansen van Vuuren Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

(get (delay {:a 1}) :a)
;; nil

(get {:a 1} :a)
;; 1

The above situation can happen easily and there is no way to refactor or check that all code doing gets is in fact doing deref before doing get. Given that everything is dynamic typing, changing a single value from a map to delay or ref can make large parts of the code fail silently on nil for gets.

get would be more consistent (with what is expected of it) if it was to check for refs, atoms and delays and do a deref.



 Comments   
Comment by Alex Miller [ 01/Apr/14 7:43 AM ]

I think this goes beyond what get should do. In regards to silent failure, that is covered by CLJ-1107 which would cause this to throw an exception instead.





[CLJ-1393] clojure.string/trim doesn't trim null character Created: 28/Mar/14  Updated: 28/Mar/14  Resolved: 28/Mar/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Ryan Fowler Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: string


 Description   

CLJ-935 changed clojure.string/trim to not trim all the characters less than or equal to \u0020 as Java does.

I noticed this because base64 uses null characters to pad the end of encoding blocks.

Clojure 1.6.0's trim leaves the null character in:
user=> (.length (clojure.string/trim "\u0000"))
1

java.lang.String's trim takes it out:
user=> (.length (.trim "\u0000"))
0

Here are the first 21 unicode characters and what Character/isWhitespace says about them.

(dotimes [n 0x20] (printf "
u%04x - %b\n" n (Character/isWhitespace n)))
\u0000 - false
\u0001 - false
\u0002 - false
\u0003 - false
\u0004 - false
\u0005 - false
\u0006 - false
\u0007 - false
\u0008 - false
\u0009 - true
\u000a - true
\u000b - true
\u000c - true
\u000d - true
\u000e - false
\u000f - false
\u0010 - false
\u0011 - false
\u0012 - false
\u0013 - false
\u0014 - false
\u0015 - false
\u0016 - false
\u0017 - false
\u0018 - false
\u0019 - false
\u001a - false
\u001b - false
\u001c - true
\u001d - true
\u001e - true
\u001f - true



 Comments   
Comment by Alex Miller [ 28/Mar/14 12:27 PM ]

The choice was made in CLJ-935 to consistently define whitespace as Character.isWhitespace() across trim, triml, and trimr. There are many possible ways to define "space" (at least two as we see here). If your trimming needs differ from the standard library, then you'll probably need to define your own functions to trim your data. You can still use Java interop to call String.trim() directly if that happens to match your needs.

Comment by Ryan Fowler [ 28/Mar/14 1:03 PM ]

Indeed, it's an easy workaround to use Java interop once you figure out what your problem is.

It's just unintuitive that the character generally used for string termination isn't trimmed by clojure.string/trim.





[CLJ-1377] java.lang.IllegalArgumentException: More than one matching method found on calling ExecutorService.submit from let instead of using Var. Created: 11/Mar/14  Updated: 12/Mar/14  Resolved: 11/Mar/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Roy Varghese Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

Example from Joy Of Clojure doesn't work when Executor service pool is used in (let )

https://groups.google.com/forum/#!msg/clojure/asEXM2uHyxw/aK4rrKOKs1YJ



 Comments   
Comment by Alex Miller [ 11/Mar/14 3:47 PM ]

In the let case, the pool will be tagged with the proper type so the ambiguity is detected.

In the def case, the pool will be seen as an object and the compiler is just deferring to reflection at runtime to figure it out. If you turn on warn-on-reflection, you'll see a reflection warning in this case. Reflection is just picking the first one that matches in that case. If you type hinted the def case, you'd see the same error.

I don't think there is a bug here.

Comment by Roy Varghese [ 11/Mar/14 5:08 PM ]

Actually, I did turn on warn-on-reflection, but didn't see any messages.

I think this creates an element of surprise and uncertainty.

(def A (let [x (java.util.concurrent.Executors/newFixedThreadPool 5)] x))

How would (.submit A ...) behave?

Comment by Alex Miller [ 11/Mar/14 11:15 PM ]

When I ran the prior example, I saw a reflection warning.

In your new example, I would expect x to be typed as a ThreadExecutorPool, A to be typed as an Object, and .submit to get called reflectively (successfully) and produce a reflection warning. It's effectively no different than the def example in the post.

What are you suggesting is the bug and what should happen? Reflector could throw an error when it finds multiple matches but that would certainly break code that is currently working like the example you gave, so I doubt we would consider such a change at this point. There really is an ambiguity here, so I think a type hint is required to make it work unambiguously in either case.

Comment by Roy Varghese [ 12/Mar/14 10:49 AM ]

The bug is that type hints are required in one case, and not required in the other case because of implementation details, unless its documented in the language that (def) and (let) hold different types of Vars.

I the example above, I would expect A and x to refer to the same object, and thus contain the type information. Or not. Without reading the implementation, either case seems possible.

Agree, its a breaking change, but that's a different consideration.

Comment by Roy Varghese [ 12/Mar/14 10:50 AM ]

BTW..trying to fix with hints is what led to CLJ-1378.

Comment by Alex Miller [ 12/Mar/14 11:39 AM ]

x is locally bound to an object (there is no Var here) - the type information is on the local binding, inferred from the type of the expression. In the compiled form, the let expression does know the return type of the evaluated let (if there were multiple branches, there might be many possible return types). The def creates a Var that holds the result of evaluating the let. At compilation time, the type of the result of the let is unknown so is assumed to be Object.

So, x is a local binding and A is a Var. Even if they both refer to the same object, they do so in different contexts using different information. The type hinting and binding behavior in let is described on the special forms page http://clojure.org/special_forms. Remember too that Clojure is a dynamic language - while the Var A might hold a ThreadPoolExecutor instance now, it might hold something else later.

CLJ-1378 is useful - that's phrased more as a problem we can solve and there's a reasonable patch there.

Comment by Alex Miller [ 12/Mar/14 11:55 AM ]

"there is no Var here" == "there is no Var at this point"
"the let expression does know the return type" should have been "does NOT know"





[CLJ-1370] ((println)) should throw CompilerException instead of NPE? Created: 06/Mar/14  Updated: 06/Mar/14  Resolved: 06/Mar/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: The Alchemist Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: bug


 Description   

How to Reproduce

=> ((println))

NullPointerException   hello.core/eval4117 (NO_SOURCE_FILE:1)

What's Wrong?

I might be completely wrong, in which case don't hesitate to close this defect, but I wish this would throw a CompilerException with an IllegalArgumentException, just like ((nil)):

=> ((nil))
CompilerException java.lang.IllegalArgumentException: Can't call nil, compiling:(NO_SOURCE_PATH:1:2)


 Comments   
Comment by Alex Miller [ 06/Mar/14 12:37 PM ]

There is no compilation error here. The error occurs during evaluation.

user> (defn x [] ((println)))  ;; compiles just fine
#'user/x
user> (x)   ;; fails in evaluation
NullPointerException   user/x (NO_SOURCE_FILE:1)

The error is thrown when trying to evaluate (nil) where NullPointerException is a perfectly valid error.





[CLJ-1334] Improve performance of the bean function with caching Created: 30/Jan/14  Updated: 31/Jan/14  Resolved: 31/Jan/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Ron Pressler Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: performance


 Description   

The bean function is a very useful Java interop feature that provides a read-only view of a Java Bean as a Clojure map.
As it stands, the function performs introspection on the bean's class whenever the function is called. We can, however, cache the mapping from keywords to getters using JDK 7's handy ClassValue. The proposed function will look like this:

(def ^:private ^java.lang.ClassValue bean-class-value
(proxy [java.lang.ClassValue]
[]
(computeValue [c]
(reduce1 (fn [m ^java.beans.PropertyDescriptor pd]
(let [name (. pd (getName))
method (. pd (getReadMethod))
type (.getPropertyType pd)]
(if (and method (zero? (alength (. method (getParameterTypes)))))
(assoc m (keyword name) (fn [x] (clojure.lang.Reflector/prepRet type (. method (invoke x nil)))))
m)))
{}
(seq (.. java.beans.Introspector
(getBeanInfo c)
(getPropertyDescriptors)))))))

(defn bean
"Takes a Java object and returns a read-only implementation of the
map abstraction based upon its JavaBean properties."
{:added "1.0"}
[^Object x]
(let [c (. x (getClass))
pmap (.get bean-class-value c)
v (fn [k] ((pmap k) x))
snapshot (fn []
(reduce1 (fn [m e]
(assoc m (key e) ((val e) x)))
{} (seq pmap)))]
(proxy [clojure.lang.APersistentMap]
[]
(containsKey [k] (contains? pmap k))
(entryAt [k] (when (contains? pmap k) (new clojure.lang.MapEntry k (v k))))
(valAt ([k] (when (contains? pmap k) (v k)))
([k default] (if (contains? pmap k) (v k) default)))
(cons [m] (conj (snapshot) m))
(count [] (count pmap))
(assoc [k v] (assoc (snapshot) k v))
(without [k] (dissoc (snapshot) k))
(seq [] ((fn thisfn [plseq]
(lazy-seq
(when-let [pseq (seq plseq)]
(cons (new clojure.lang.MapEntry (first pseq) (v (first pseq)))
(thisfn (rest pseq)))))) (keys pmap))))))



 Comments   
Comment by Jozef Wagner [ 30/Jan/14 9:25 AM ]

associated discussion

Comment by Alex Miller [ 31/Jan/14 8:45 AM ]

Curious if anyone is using this inside production code? I use it at the REPL when exploring Java stuff sometimes but have never used it inside my actual code.

Comment by Stuart Halloway [ 31/Jan/14 12:28 PM ]

This is a cool idea, but doesn't need to be in core. How about https://github.com/clojure/java.data ?

Comment by Ron Pressler [ 31/Jan/14 12:48 PM ]

This might be good for java.data, and I'm certainly not saying it should be in the core except for the fact that it already is. This is a proposal for a performance improvement of a core function.





[CLJ-1320] min-key assumes numbers, not comparables. Created: 09/Jan/14  Updated: 09/Jan/14  Resolved: 09/Jan/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.2, Release 1.3, Release 1.4, Release 1.5, Release 1.6
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Pierre-Yves Ritschard Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None

Attachments: File min-key.diff    
Patch: Code

 Description   

The min-key function assumes the key-fn will yield a number and thus uses the '<' operator to compare results.
There are cases where one might want to use min-key with comparables instead.

While (first (sort-by key-fn seq)) could also be used, it feels more natural for min-key to use comparables.



 Comments   
Comment by Pierre-Yves Ritschard [ 09/Jan/14 3:18 PM ]

As discussed on the .L, since compare is slower it makes more sense to keep min-key as-is.





[CLJ-1312] clojure.string/split on empty string includes empty string in results Created: 21/Dec/13  Updated: 07/Sep/14  Resolved: 21/Dec/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Russell Dunphy Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: string


 Description   

Splitting a string using clojure.string/split with an empty regex includes the empty string in the results - is this expected behaviour?

Example:

Unable to find source-code formatter for language: clojure. Available languages are: javascript, sql, xhtml, actionscript, none, html, xml, java
user=> (clojure.string/split "abc" #"")
["" "a" "b" "c"]


 Comments   
Comment by Alex Miller [ 21/Dec/13 8:05 AM ]

Yes, I think so. This is a case where Clojure defers to the host (Java) for behavior. I think the way to interpret this is that the empty pattern matches all strings. Split checks left to right whether there is a next chunk of string that matches the pattern. The empty pattern matches at the beginning to a string of length 0. Something like that.

Comment by Mark Engelberg [ 07/Sep/14 12:27 PM ]

This bug is a real problem, because it works differently on Windows than on Linux. On Windows, clojure.string/split behaves exactly as you'd expect:

user=> (clojure.string/split "abc" #"")
["a" "b" "c"]

Only on Linux do you get the strange behavior where the empty string shows up at the beginning of the list.

I recently had a student that got burned by this in some webserver code that relied on splitting using the empty regex. It performed flawlessly on her local Windows machine, but mysteriously broke when she uploaded the uberwar to the cloud. The bug was very difficult to track down.

If this were a bug on both Windows and Linux, at least you could plan around it. But right now, it's an obstacle to Clojure's capability of running consistently across platforms.

Comment by Mark Engelberg [ 07/Sep/14 12:40 PM ]

Upon further research, I've found that this is not a Windows/Linux issue, rather it's a difference between Java 7 and Java 8. On Java 8, splitting with the empty string no longer produces a sequence that begins with an empty string.

As you said before, this is just a gotcha relating to Java, not a Clojure issue.





[CLJ-1310] some-> behaves differently than -> when used with macros Created: 19/Dec/13  Updated: 19/Dec/13  Resolved: 19/Dec/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Chris Perkins Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

I stumbled across a behavior of some-> when used with macros, and I'm wondering whether it's expected.

I started with something like this:

(some-> value
foo
bar
quux)

Then I realized that quux might throw an exception, which I want to ignore, so had the possibly misguided idea to do this:

(defmacro catch->nil [& body]
`(try ~@body (catch Exception _# nil)))

(some-> value
foo
bar
quux
catch->nil)

My mental model of some-> is that it should end up wrapping the whole expression in a try-catch, as > does, but that does not happen. some> expands into a `let` instead of a deeply-nested form, so the exception is not caught.

Certainly easy to work around, now that I know about it, but I thought perhaps this was not intended.



 Comments   
Comment by Chris Perkins [ 19/Dec/13 7:34 PM ]

After a little reflection, I realize that my mental model of some-> as "thread-first plus magic fairy-dust" is fatally flawed. I withdraw my objections. Please disregard.

Comment by Alex Miller [ 19/Dec/13 7:50 PM ]

withdrawn by submitter





[CLJ-1303] Remove (apparently) vestigial forward-defs of unquote and unquote-splicing Created: 05/Dec/13  Updated: 01/Feb/14  Resolved: 31/Jan/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: David Rupp Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: enhancement

Attachments: File generalize-unquote.diff    
Patch: Code

 Description   

clojure/core.clj contains forward defs of unquote and unquote-splicing that seem no longer to be necessary. The pull request at https://github.com/clojure/clojure/pull/45 removes this dead code (also attaching a git diff file). Existing tests pass; no new test code necessary.



 Comments   
Comment by Alex Miller [ 05/Dec/13 9:23 PM ]

FYI for future reference, Clojure doesn't accept pull requests. Thanks for the report though!

Comment by David Rupp [ 05/Dec/13 9:31 PM ]

I noticed. That's why I created the JIRA.

Comment by Andy Fingerhut [ 07/Dec/13 10:25 AM ]

David, I do not have any comment on whether this patch will be accepted or not based on the changes it makes, but patches do need to be in a particular format, including the author's name. See instructions for how to create a patch in this format here: http://dev.clojure.org/display/community/Developing+Patches

Comment by David Rupp [ 07/Dec/13 11:26 AM ]

Submitting properly-formatted patch.

Comment by David Rupp [ 09/Dec/13 7:49 AM ]

Replaced references to clojure.core/unquote and .../unquote-splicing,
which are unbound.

The UNQUOTE and UNQUOTE-SPLICING Symbols in LispReader don't really
refer to anything in clojure.core any longer. They're created and
elided by the reader when it encounters their respective (reader)
macro chars.

Comment by Stuart Halloway [ 31/Jan/14 3:26 PM ]

The patch attached here is poorly-suited for screening. It does more than what it says, (e.g. deleting the def of META) without explaining why.

It also removes things that are commented out. Pretty clear that the BDFL likes having those things stick around.

Comment by David Rupp [ 01/Feb/14 6:57 PM ]

META is not used anywhere. I will explain better next time.

Also, DEREF_BANG has been commented out since 2007 (commit 139ddd146f2a272b7ddda397f54b501ff499c643). Figured it was pretty safe to get rid of at this point. My bad.





[CLJ-1294] (vec (range)) causes REPL to hang (infinite loop?) Created: 11/Nov/13  Updated: 11/Nov/13  Resolved: 11/Nov/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Rene Semmelrath Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

LightTable and CoutnerClockWise
Windows7



 Description   

I just typed

(vec (range))

in LightTable and it stop working while CPU went to 100%
the same behavior is in Eclipse/Couterclockwise REPL



 Comments   
Comment by Andy Fingerhut [ 11/Nov/13 5:39 PM ]

Rene, this is expected to cause an infinite loop. (range) returns a lazy infinite sequence of integers. vec tries to cause the entire infinite sequence to be realized so it can put all elements into a vector. This is not a bug. You asked for an infinite loop, and you got one

Comment by Alex Miller [ 11/Nov/13 6:10 PM ]

(range) will yield an infinite sequence. vec will walk the sequence, conj'ing each item onto the vector ... which will do bad things.

While Clojure works well with infinite sequences (an abstraction), the collections like vector support only a finite number of elements.





[CLJ-1287] Change select-keys to return same type of map as it is given Created: 01/Nov/13  Updated: 14/Feb/14  Resolved: 14/Feb/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Andy Fingerhut Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None

Attachments: File clj-1287-1.diff     File clj-1287-3.diff    
Patch: Code and Test

 Description   

select-keys always returns a map built up from {}. This will sometimes not be the same type of map as the one given as the first arg, e.g. if the first arg is a sorted-map, the returned map will not be. There are situations where it would be nice if it preserved the kind of map it was given, e.g. the developer wishes to preserve the sorting order of the keys.

Discussion thread on Clojure group: https://groups.google.com/forum/#!topic/clojure/l_V1N1nRF-c



 Comments   
Comment by Andy Fingerhut [ 01/Nov/13 9:36 AM ]

clj-1287-1.diff changes the starting set {} to (empty map) in select-keys, and adds tests for the new behavior. The only reason select-keys is moved later in core.clj is to move it after the definition of function 'empty'. Before this patch 'select-keys' is defined before 'declare', even, so we cannot simply put a '(declare empty)' before select-keys.

Comment by Alex Miller [ 01/Nov/13 12:58 PM ]

What happens with records? Does this introduce a new failure case there (due to lack of empty support in records)?

Comment by Andy Fingerhut [ 01/Nov/13 5:43 PM ]

I had not thought about records when making the first patch. It does cause select-keys to fail if given a record, whereas without the patch select-keys works fine on records. clj-1287-2.diff is similar to the earlier patch, but if its argument is a record, it still returns a correct value based upon building up an unsorted map starting from {}. If its argument is not a record, it assumes empty will work on it and uses (empty map) to start with.

Comment by Andy Fingerhut [ 14/Feb/14 12:11 PM ]

Patch clj-1287-3.diff is identical to the earlier clj-1287-2.diff described in an earlier comment, except it updates some diff context lines so that it applies cleanly to the latest Clojure master as of today.

Comment by Alex Miller [ 14/Feb/14 1:14 PM ]

We do not wish to make this change.





[CLJ-1276] Can't make a dispatch map containing forward-declared fns Created: 09/Oct/13  Updated: 18/Apr/14  Resolved: 18/Apr/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Alex Coventry Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None

Attachments: File unbound-eg.tgz    

 Description   

If from (ns tst2) you try to call tst1/c, which calls tst1/f via dispatch map which was defined when tst1/f was forward declared, you get an "unbound fn" error. E.g.

user=> (dorun (map eval 
                   '[(ns tst1) 
                     (declare f) 
                     (def d {:k f}) 
                     (defn c [] ((d :k)))
                     (defn f [] :success)
                     (ns tst2 (:require [tst1]))
                     (tst1/c)]))

IllegalStateException Attempting to call unbound fn: #'tst1/f  clojure.lang.Var$Unbound.throwArity (Var.java:43)
tst2=> (clojure.repl/pst *e)
IllegalStateException Attempting to call unbound fn: #'tst1/f
	clojure.lang.Var$Unbound.throwArity (Var.java:43)
	tst1/c (NO_SOURCE_FILE:5)
	tst2/eval25 (NO_SOURCE_FILE:8)
	clojure.lang.Compiler.eval (Compiler.java:6642)
	clojure.lang.Compiler.eval (Compiler.java:6605)
	clojure.core/eval (core.clj:2883)
	clojure.core/map/fn--4222 (core.clj:2513)
	clojure.lang.LazySeq.sval (LazySeq.java:40)
	clojure.lang.LazySeq.seq (LazySeq.java:49)
	clojure.lang.RT.seq (RT.java:484)
	clojure.core/seq (core.clj:133)
	clojure.core/dorun (core.clj:2811)


 Comments   
Comment by Alex Coventry [ 09/Oct/13 10:43 PM ]

TEttinger pointed out on IRC that the forms in the example run without error if you wrap them in a (do) block. Here is an example using files. Relevant code is in src/unbound_eg/tst[12].clj. Example output shown below.

http://clojure-log.n01se.net/date/2013-10-09.html#23:52

lap% lein repl
nREPL server started on port 50125 on host 127.0.0.1
REPL-y 0.2.1
Clojure 1.5.1
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)

user=> (require '[unbound-eg.tst2 :as t2])

IllegalStateException Attempting to call unbound fn: #'unbound-eg.tst1/f clojure.lang.Var$Unbound.throwArity (Var.java:43)
user=> (pst)
IllegalStateException Attempting to call unbound fn: #'unbound-eg.tst1/f
clojure.lang.Var$Unbound.throwArity (Var.java:43)
unbound-eg.tst1/c (tst1.clj:4)
unbound-eg.tst2/eval2233 (tst2.clj:3)
clojure.lang.Compiler.eval (Compiler.java:6619)
clojure.lang.Compiler.load (Compiler.java:7064)
clojure.lang.RT.loadResourceScript (RT.java:370)
clojure.lang.RT.loadResourceScript (RT.java:361)
clojure.lang.RT.load (RT.java:440)
clojure.lang.RT.load (RT.java:411)
clojure.core/load/fn--5018 (core.clj:5530)
clojure.core/load (core.clj:5529)
clojure.core/load-one (core.clj:5336)
nil

Comment by Kevin Downey [ 18/Apr/14 12:23 AM ]

this is just a fact of clojure's compilation model and how vars work.

a var is a little mutable cell

(declare foo) declares that a mutable cell exists with the name foo, it doesn't contain a value

foo then gets the value of the mutable cell (which has none)

(defn foo [] 1) then sets the value of the cell named foo to the function created from (fn [] 1)

Comment by Alex Miller [ 18/Apr/14 7:29 AM ]

I agree with Kevin - this is expected behavior.





[CLJ-1269] RFC: Anonymous functions interaction with -> and ->> threading macros Created: 28/Sep/13  Updated: 09/Dec/13  Resolved: 09/Dec/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Michael O. Church Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

This is more of a starting point for discussion than a feature request. It'd be easy to write and submit the patch, but I want to ask if it's a good idea, since it would alter the semantics of two core macros, '> and '>>; and if it is a good idea, what considerations need to be balanced.

For threading macros, I'd like to special-case forms that begin with 'fn and 'fn*. It's often useful (but maybe a bad idea; that's why I'd like to start the discussion) to use the threading macros in conjunction with anonymous functions in addition to forms, like so (contrived example):

(defn sigmoid [x] (-> x 
                      - 
                      Math/exp 
                      (+ 1) 
                      #(/ 1 %)))

This won't compile; #(/ 1 %) expands to the form

(fn* [p1__1389#] (/ 1 p1__1389#))

modulo gensym, of course. The threading macro, not treating fn* and fn specially, alters that to:

(fn* (clojure.core/-> (clojure.core/-> (clojure.core/-> x -) Math/exp) (+ 1)) [p1__1417#] (/ 1 p1__1417#))

which is a fn* with a non-symbol (illegal label) before its binding vector, raising an error.

Is this worth "fixing", or are the benefits to small to justify the added complexity of a special case in the ->, ->> threading macros?



 Comments   
Comment by Michael O. Church [ 29/Sep/13 8:52 AM ]

Thanks Alex!

Comment by Gary Fredericks [ 09/Dec/13 7:53 AM ]

Just one of the special cases you'd want to consider is when fn does not mean clojure.core/fn, which is certainly realistic.

Comment by Michael O. Church [ 09/Dec/13 10:03 AM ]

Yes, I realize that.

Looking at the ticket again, I retract my support of this change.

Here's why: (1) that "fix" would alter the semantics of the threading macros, which would break existing code, and (2) there's a really easy way to get anonymous functions into threading macros: just surround the

#(...)
expression with an extra set of parentheses.

I retract my request for this feature. It's easy enough to do this: instead of,

(-> x f #(g h %))

it's this:

(-> x f (#(g h %)))

Saving 2 characters, like so, is not worth a breaking change IMO.

Comment by Alex Miller [ 09/Dec/13 10:15 AM ]

Retracted by submitter





[CLJ-1267] Reader Bug for making vector of numbers Created: 26/Sep/13  Updated: 26/Sep/13  Resolved: 26/Sep/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Amin Razavi Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: bug
Environment:

Windows 8 , Core i7



 Description   

When Trying To Make a Vector of Numbers Like 01 04 ... it's OK!
=> (vector 04)
; [4]
But When Trying To Make a Vector of "09" It Says :
NumberFormatException Invalid Number: 09



 Comments   
Comment by Alex Miller [ 26/Sep/13 10:56 AM ]

Numbers with a leading 0 are read as octal (valid digits = 0-7). Example:

> 0100
64

So, this is the expected behavior.

Comment by Amin Razavi [ 26/Sep/13 7:49 PM ]

shame on me , sorry.





[CLJ-1265] various clojure.core functions with ^:static metadata are missing doc strings Created: 23/Sep/13  Updated: 05/Feb/14  Resolved: 05/Feb/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.6
Fix Version/s: None

Type: Defect Priority: Trivial
Reporter: Jozef Wagner Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

Several functions defined with legacy ^:static metadata are not shown in API documentation. Examples are chunk-cons or await1. This defect probably originates in autodoc.



 Comments   
Comment by Tom Faulhaber [ 23/Sep/13 9:25 AM ]

These functions have no doc strings. Autodoc doesn't include Vars without documentation by design.

I'll leave it to others to decide if the functions should have doc strings or not. If they are meant for general use, I would say that the answer is "yes."

Comment by Alex Miller [ 05/Feb/14 12:33 PM ]

The autodoc behavior is intentional. The omission of docstrings is intentional (these are internal functions).





[CLJ-1262] Set equality broken with BigInteger Created: 13/Sep/13  Updated: 13/Sep/13  Resolved: 13/Sep/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Gary Fredericks Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

The CLJ-1106 bug is still present when using BigInteger:

(let [n1 -5, n2 (BigInteger. "-5")]
  [(= n1 n2) (= #{n1} #{n2}) (= [n1] [n2])])
;; => [true false true]

Andy Fingerhut pointed out that this may be out of scope in the same way as CLJ-1036.



 Comments   
Comment by Alex Miller [ 13/Sep/13 1:14 PM ]

Yes, Rich considers hash/= consistency out of scope for BigInteger.





[CLJ-1260] ConcurrentModificationException thrown during action dispatching after commit in LockingTransaction.run() Created: 12/Sep/13  Updated: 21/Jan/14  Resolved: 21/Jan/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.4, Release 1.5, Release 1.6
Fix Version/s: Release 1.6

Type: Defect Priority: Major
Reporter: Brandon Ibach Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: STM
Environment:

Discovered on Ubuntu 12.04 with Oracle JDK 1.7.0_25 running Clojure 1.4. Test case produced on Windows 8 with Oracle JDK 1.7.0_09 running Clojure 1.4 and Clojure 1.5.1. Analysis seems to indicate that OS and Java version are not critical. Clojure 1.6 pre-release code has not been tested, but since clojure.lang.LockingTransaction has not changed since Clojure 1.4, it seems likely the defect is still present.


Attachments: File clj-1260.diff     File clj-1260-fixws.diff     Java Source File STMAgentInitBug.java    
Patch: Code
Approval: Vetted

 Description   

Summary

Using the Clojure 1.4 library strictly from Java code, a simple transaction dispatches an action to an Agent. When called from a simple driver, such as a unit test, where there is no interaction with the Clojure library/runtime (specifically, clojure.lang.RT), a ConcurrentModificationException is thrown from inside LockingTransaction.run() while it is iterating through the actions list, dispatching each action to its Agent after committing the transaction.

While the circumstances under which this occurs are probably fairly rare and a simple workaround exists (see final paragraph), thus the "Minor" priority, it seems like it would not be very complicated to fix LockingTransaction to handle the actions list more safely.

Analysis

Based on some debugging, here's what seems to be happening:

  1. Transaction A is run, dispatching action Z, which gets added, via LockingTransaction.enqueue(), to the actions list, which is a java.util.ArrayList<Agent.Action>.
  2. Transaction A completes and is successfully committed.
  3. LockingTransaction.run() does post-commit cleanup, freeing locks and putting a stop() to transaction A, which nulls the transaction's Info object reference.
  4. Notifications are sent and we start iterating the list of actions to be dispatched.
  5. The run() method calls Agent.dispatchAction(). Because the thread's transaction object is no longer considered to be "running" (due to the Info object being null) and no action is being processed on the thread (so its nested vector is null), the action is enqueue()-ed with the Agent.
  6. As part of the enqueue() process, the action is cons()-ed onto the Agent's ActionQueue. Here's where the unique circumstances come into play.
    1. At this point, we haven't really interacted with the Clojure runtime, specifically the clojure.lang.RT class, so its initiation machinery kicks in.
    2. Down in the depths, it executes transaction B to add a library to its list of loaded libraries.
    3. The still-existing-but-not-running thread-local transaction object fires up, runs and commits, with its existing, intact actions list, still containing action Z, enqueued during transaction A, which has not yet finished its post-commit process.
    4. The post-commit process for transaction B runs, including a nested attempt to dispatch action Z, again, which succeeds.
    5. The actions list is cleared before exiting the run() method.
  7. Upon returning way back up the stack to our not-quite-finished-post-processing transaction A, we continue iterating the now-cleared actions list, which promptly throws the ConcurrentModificationException.

A quick perusal of the LockingTransaction code shows that the only interaction with the actions list is adding an item to it in the LockingTransaction.enqueue() method, iterating it in the post-processing section of run() and clearing it in the finally clause of that section, so it's easy to see how a transaction started by any of the action-dispatching machinery would cause problems. Any such activity in the actions themselves would not be an issue, since they'd occur on other threads, but the dispatch stuff all runs on the same thread. The few moving parts that occur in this code seem fairly safe, as long as the runtime, clojure.lang.RT, is already initialized, but if that occurs during this phase, all bets appear to be off.

Test Case

The attached Java class can be compiled and run with just the Clojure 1.4 JAR on the class path. With the change described near the end of the file (comment one line and uncomment another), the Clojure 1.5.1 JAR can be used, instead, producing the same result.

A single Agent named count is created, holding an Integer value of 1. A transaction is run which dispatches an action (referred to as Z in the above description) that will increment the value of count to 2. Following this, another action is dispatched to count to enable monitoring the completion of the incrementing action. Lastly, the final value of count is printed before the application exits.

Running the class with no command-line arguments produces the above-mentioned exception and prints an incorrect final result, due to action Z being run a second time as described in step 6.4. Running with any command-line argument triggers a simple workaround that just references a static value from the clojure.lang.RT class, which invokes the class initialization before anything else happens, such that the exception is not thrown and the correct result is produced.

Patch: clj-1260-fixws.diff

Screened by:



 Comments   
Comment by Alex Miller [ 12/Sep/13 3:29 PM ]

Rich asked me to move this one to Vetted/Release 1.6 when it came in.

Comment by Alex Miller [ 12/Sep/13 3:31 PM ]

FYI: submitter does not have a CA

Comment by Christophe Grand [ 18/Oct/13 4:09 AM ]

Would a patch as simple as triggering the load of RT from the static init of LockingTransaction be ok? (assuming the analysis is correct)

Comment by Guillermo Winkler [ 18/Oct/13 1:07 PM ]

The ConcurrentModificationException is raised because the list of `actions` protocol is being violated.

Last clojure version happens in this loop in LockingTransaction.run(Callable) line: 361

for(Agent.Action action : actions)

{ Agent.dispatchAction(action); }

}

When RT hasn't been initialized before, first time it's used is in PersistentQueue's cons RT.list(o)

public PersistentQueue cons(Object o){ if(f == null) //empty return new PersistentQueue(meta(), cnt + 1, RT.list(o), null); else return new PersistentQueue(meta(), cnt + 1, f, (r != null ? r : PersistentVector.EMPTY).cons(o)); }

With the following call stack.

RT.doInit() line: 447
RT.<clinit>() line: 329
PersistentQueue.cons(Object) line: 127
PersistentQueue.cons(Object) line: 24
Agent.enqueue(Agent$Action) line: 264
Agent.dispatchAction(Agent$Action) line: 255
LockingTransaction.run(Callable) line: 369
LockingTransaction.runInTransaction(Callable) line: 231
STMAgentInitBug.main(String[]) line: 26

Problem is RT initialization triggers a new runInTransaction for new class loading (protocols in this callstack)

Thread [main] (Suspended (breakpoint at line 361 in LockingTransaction))
LockingTransaction.run(Callable) line: 361
LockingTransaction.runInTransaction(Callable) line: 231
protocols__init.load() line: 9
protocols__init.<clinit>() line: not available
Class<T>.forName0(String, boolean, ClassLoader) line: not available [native method]
Class<T>.forName(String, boolean, ClassLoader) line: 247
RT.loadClassForName(String) line: 2099
RT.load(String, boolean) line: 430
RT.load(String) line: 411
core.clj line: 5546
core.clj line: 5545
core$load(RestFn).invoke(Object) line: 408
core__init.load() line: 6174
core__init.<clinit>() line: not available
Class<T>.forName0(String, boolean, ClassLoader) line: not available [native method]
Class<T>.forName(String, boolean, ClassLoader) line: 247
RT.loadClassForName(String) line: 2099
RT.load(String, boolean) line: 430
RT.load(String) line: 411
RT.doInit() line: 447
RT.<clinit>() line: 329
PersistentQueue.cons(Object) line: 127
PersistentQueue.cons(Object) line: 24
Agent.enqueue(Agent$Action) line: 264
Agent.dispatchAction(Agent$Action) line: 255
LockingTransaction.run(Callable) line: 369
LockingTransaction.runInTransaction(Callable) line: 231
STMAgentInitBug.main(String[]) line: 26

So LockingTransaction:run depends indeed on RT to be loaded, since the method re-enters the function if loading is triggered from the inside.

Maybe actions:

final ArrayList<Agent.Action> actions = new ArrayList<Agent.Action>();

Should be better protected to prevent enqueuing during the dispatch loop?

Comment by Brandon Ibach [ 18/Oct/13 2:02 PM ]

The additional detail provided in the last comment is correct and matches what I observed. However, protecting the "actions" list against enqueuing isn't really the issue, since this problem would occur even if the "nested" transaction didn't involve any actions. The problem is that committing a transaction clears the "actions" list.

I think the suggestion to trigger initialization of RT in the static initializer of LockingTransaction would address this issue, though in a somewhat roundabout way. A more direct approach might be to make a temporary copy of the contents of the "actions" list prior to iterating it. Obviously, the latter would make extra work on every transaction commit, so it may not be desirable. I don't know what impact the former approach would have, other than the long-term effect of it being non-obvious to a later observer why that code is needed.

I haven't thought this through completely or done any tests, so my reasoning may be wrong, but one more argument for the approach of making a copy of the "actions" list is that a Ref notification/watch could run a transaction, which, being on the same thread, would also clear the "actions" list. This case wouldn't cause the exception, since the iteration of the list would not have started, yet, but it would cause actions enqueued by the "outer" transaction to not be dispatched.

Comment by Guillermo Winkler [ 18/Oct/13 2:26 PM ]

You're right, problem is not on enqueue are inner transactions clearing the list.

Anyway the protection can be a smarter way of iteration.

Wouldn't a possible solution be treating the action list as a Queue? Pop'in each action would also clear only that action.

Comment by Guillermo Winkler [ 18/Oct/13 2:57 PM ]

Attached patch seems to solve the problem in a cleaner way.

Comment by Andy Fingerhut [ 19/Oct/13 5:32 PM ]

Patch clj-1260-fixws.diff is identical to Guillermo's clj-1260.diff, except it eliminates warnings when applying the patch that were due to trailing white space.

Comment by Stuart Sierra [ 17/Jan/14 1:27 PM ]

Here's my understanding of what happens:

1. User's Java code calls LockingTransaction.runInTransaction.
2. In the transaction's Callable, user calls Agent.dispatch.
3. LockingTransaction adds the agent action to its actions list.
4. The transaction commits.
5. LockingTransaction begins iterating over actions and dispatching them.
6. Agent.dispatchAction checks to see if there is a running transaction, which there is not.
7. Agent.dispatchAction line 255 calls Agent.enqueue.
8. Agent.enqueue line 264 calls PersistentQueue.cons.
9. PersistentQueue.cons line 127 calls RT.list, triggering initization of RT.
10. RT's static initializer calls doInit.
11. doInit loads core.clj.
12. core.clj loads other files which contain ns declarations.
13. ns expands to code which commutes loaded-libs in a transaction.
14. The new transaction gets the same ThreadLocal LockingTransaction.
15. The new transaction executes and clears actions.
16. Back up the stack in the original transaction, LockingTransaction tries to continue iterating over actions and throws ConcurrentModificationException.

In short, this situation can only occur when the mere act of
enqueueing agent actions, not executing them, can create another
transaction on the same thread. This can happen when clojure.lang.RT
has not been initialized.

This would never occur in a Clojure program because RT is already
initialized when the Clojure program starts, and none of the Java code
involved in enqueueing agent actions will create new transactions.

The workaround for Java is trivial: just make sure clojure.lang.RT is
initialized before using any other Clojure classes.

However, the patch clj-1260-fixws.diff is a small and safe change. Its
author, Guillermo Winkler, has a CA.

The approach is to treat the actions list in LockingTransaction
as a queue, popping actions off one at a time, and never to
explicitly clear the queue.

The more important question is if/when RT should be initialized
automatically.

Comment by Guillermo Winkler [ 17/Jan/14 1:46 PM ]

Solving this problem by initializing RT feels to me like complecting two things not necessarily related, if PersistentQueue stops using RT, relationship disappears and you may still have the bug.

Anyway RT could be initialized safely so anyone that may depend on it finds it already there, avoiding potential clashes on initialization.

Comment by Alex Miller [ 17/Jan/14 1:49 PM ]

And following up on that, Clojure 1.6 has a new public Java API in clojure.java.api.Clojure. Loading that class or using any method on the class will serve to load clojure.lang.RT as a side effect.

Comment by Guillermo Winkler [ 21/Jan/14 9:11 AM ]

Alex, do you want a patch for the safe RT initialization here? Or do you prefer to handle it using a different ticket?

Comment by Alex Miller [ 21/Jan/14 9:32 AM ]

When you are using Clojure from Java, it is expected that you should properly initialize the Clojure runtime by (at least) loading the RT class (for Clojure <1.6) or the Clojure class (for Clojure >= 1.6).





[CLJ-1258] (apply and [false true]) gives CompilerException Created: 08/Sep/13  Updated: 09/Sep/13  Resolved: 09/Sep/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.4, Release 1.5
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Cynthia Qiu Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: bug
Environment:

Ubuntu 13.04. I run 1.4.0 by "apt-get install", and 1.5.1 by "java -cp clojure-1.5.1.jar clojure.main".



 Description   

user=> (apply and [false true])
CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/and, compiling:(NO_SOURCE_PATH:1)
user=> (apply and (list false true))
CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/and, compiling:(NO_SOURCE_PATH:2)



 Comments   
Comment by Cynthia Qiu [ 08/Sep/13 10:18 PM ]

I got it. "and" is not a function but a special form. Sorry for that.

Comment by Andy Fingerhut [ 08/Sep/13 11:57 PM ]

Minor comment on yours: Clojure and other Lisps often distinguish between "special forms" and macros. I may be missing some of the distinction, but I am pretty sure the main part is that special forms are usually built into the implementation of Lisp, whereas macros are typically defined by the user via defmacro.

In any case, neither special forms nor macros may be used with apply, only functions.

Comment by Alex Miller [ 09/Sep/13 1:26 AM ]

As per Andy's comment, this is expected behavior when trying to apply to macros.





[CLJ-1252] Clojure reader (incorrectly) accepts keywords starting with a number Created: 04/Sep/13  Updated: 31/Oct/13  Resolved: 31/Oct/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: Release 1.6

Type: Defect Priority: Minor
Reporter: Alex Miller Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: reader

Attachments: Text File numkeyword.patch    
Patch: Code and Test
Approval: Screened

 Description   

The reader page at http://clojure.org/reader states that symbols (and keywords) cannot start with a number and the regex used in LispReader (and EdnReader) also has this intention. But:

user> :5
:5
user> (class *1)
clojure.lang.Keyword

Cause: The pattern for keywords is: "[:]?([\D&&[^/]].*/)?(/|[\D&&[^/]][^/]*)". The intention of the [\D&&[^/]] is to accept all non-digits except /. However, if the : matches and 5 does not, the regex will backtrack and unmatch the :, instead matching it in the non-digit charset. The whole match is sent on in the code and the : is stripped later.

Solution: Prevent back-tracking for the first : match by using the possessive quantifier ?+ instead of ?. Once the first : is matched, it will not backtrack to it. (This is also faster.) The patch makes this change in LispReader and EdnReader, updates a couple tests that were using number keywords, and adds a new negative test to check that :5 isn't read.

Patch: numkeyword.patch

Screened by: Alex Miller



 Comments   
Comment by Andy Fingerhut [ 05/Sep/13 5:25 PM ]

Given how far this one is along now, perhaps CLJ-1003 should be marked as a duplicate of this one?

Comment by Alex Miller [ 31/Oct/13 9:39 PM ]

Because this broke existing code (several lib projects like java.jdbc), we have rolled this back. Will follow up with an alternate ticket to address this in some other way.





[CLJ-1249] Warning when a record field with the same name as a function exists for it Created: 26/Aug/13  Updated: 30/Dec/14  Resolved: 31/Jan/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.4, Release 1.5
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Benjamin Peter Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: errormsgs
Environment:

Linux, clojure jar or leiningen repl



 Description   

Hi,

I had the following problem which took me much longer than it should have. I accidentally had a record's field with the same name as one of the functions from a protocol. When I tried to call the function from within the record I got totally weird behavior and didn't find it, until I removed every piece of code when I found the name conflict.

I wish clojure would warn me in such a case. (Disregarding any naming conventions that could have saved me.)

Following a small example to reproduce the problem:

(defprotocol HasPets
  (dogs [this])
  (cats [this])
  (octopus [this])
  (cute-ones [this]))

; Here the field "dog" is added with the same name as the protocol
(defrecord Petshop [dogs] 
  HasPets
  (dogs [this]
    [:pluto :bethoven])
  (cats [this]
    [:tom])
  (octopus [this]
    [:henry])
  (cute-ones [this]
    ; Here it was intended to call the function "dogs", instead the
    ; field is used.
    (concat (dogs this) (cats this))))

(def dogs-in-stock nil)

(let [petshop (->Petshop dogs-in-stock)]
  (println "Dogs for sale:" (dogs petshop))
  (println "All cute animals: " (cute-ones petshop)))

Results in:

clojure core.clj
Dogs for sale: [:pluto :bethoven]
Exception in thread "main" java.lang.NullPointerException
        at user.Petshop.cute_ones(core.clj:20)
        at user$eval84.invoke(core.clj:26)
        at clojure.lang.Compiler.eval(Compiler.java:6514)
        at clojure.lang.Compiler.load(Compiler.java:6955)
        at clojure.lang.Compiler.loadFile(Compiler.java:6915)
        at clojure.main$load_script.invoke(main.clj:283)
        at clojure.main$script_opt.invoke(main.clj:343)
        at clojure.main$main.doInvoke(main.clj:427)
        at clojure.lang.RestFn.invoke(RestFn.java:408)
        at clojure.lang.Var.invoke(Var.java:415)
        at clojure.lang.AFn.applyToHelper(AFn.java:161)
        at clojure.lang.Var.applyTo(Var.java:532)
        at clojure.main.main(main.java:37)

Expected warning:

Warning: the protocol function "dog" from "HasPets" conflicts with the equally named record field of "Petshop"

Without dog as a record's field:

clojure core.clj
Dogs for sale: [:pluto :bethoven]
All cute animals:  (:pluto :bethoven :tom)

Thanks for your help.

Ben.



 Comments   
Comment by Alex Miller [ 26/Aug/13 1:20 PM ]

Thanks for the report.

It seems like there is a scoping issue here where dogs is bound to the field and there is also a context for it being referred to as a function. It's possible that this should really be treated as a compiler bug and not a warning message problem - that requires some more detective work. Since there is only one function dogs (the field name is a function only in keyword form - :dogs), it seems unambiguous what should be done here.

In the meanwhile, presumably a workaround would be to use extend-protocol, etc to attach the protocol to the record outside the record definition.

Comment by Gary Fredericks [ 09/Dec/13 8:24 AM ]

Alex I can't see a lack of ambiguity here. I read your comment as saying that because dogs is in the call position we can deduce that it's meant to refer to the function rather than the field. But we can't assume that a field is not an IFn or intended to be used as one, so I can't make sense of that.

Another workaround should be using a fully qualified reference to the protocol function.

My expectation as a user of defrecord and deftype has always been that ambiguous references always refer to the fields, as if there were a let around each function body. So I've done this kind of thing intentionally I think. I don't know what that means about whether or not it should be a warning.

Should warnings for this kind of thing be accompanied by a way to suppress individual instances of the warning? E.g., a ^:no-warn metadata somewhere?

Comment by Stuart Halloway [ 31/Jan/14 2:41 PM ]

It is correct and legal code to have a record or type field shadow a var name, and as Gary mentions, the var is still reachable via a qualified name.

This might be a good warning for a linter like https://github.com/jonase/eastwood, if it is not present already.

Comment by Andy Fingerhut [ 31/Jan/14 2:55 PM ]

The Eastwood linter currently has no warning for this situation, but I have created an issue on its Github page to record the enhancement idea: https://github.com/jonase/eastwood/issues/55

Comment by Benjamin Peter [ 31/Jan/14 3:26 PM ]

Okay, thanks guys.

Comment by Andy Fingerhut [ 25/Dec/14 12:15 PM ]

I started looking at implementing this in Eastwood today, only to discover that the :local-shadows-var linter implemented in an earlier release on Nov 4 2014 already catches this case and warns about it, among other things. The latest release also works fine for catching this, too.

Comment by Benjamin Peter [ 30/Dec/14 3:10 PM ]

Thanks!

Tried it now and got a warning - didn't use eastwood before and tbh would expect it to be a part of the default clojure runtime.

Comment by Benjamin Peter [ 30/Dec/14 3:11 PM ]

Output for the example:

src/petshop/core.clj:21:13: local-shadows-var: local: dogs invoked as function shadows var: #'petshop.core/dogs




[CLJ-1244] :prefix is ignored when trying to gen-class with custom methods Created: 14/Aug/13  Updated: 16/Aug/13  Resolved: 16/Aug/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Daniel Kwiecinski Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: AOT, gen-class


 Description   

I'm trying to generate several classes defined in one namespace:

(ns aot.core)

(gen-class
:name aot.core.ClassA
:prefix "classA-")

(gen-class
:name aot.core.ClassB
:prefix "classB-")

(defn classA-toString
[this]
"I'm an A.")

(defn classB-toString
[this]
"I'm a B.")

After AOT I can see that

(.toString (ClassA.))

doesn't produce "I'm an A." string but rather uses method from the superclass >> "aot.core.ClassA@33ba4e15"

If on other hand I do:

(ns aot.core)

(gen-class
:name aot.core.ClassA
:prefix "classA-")

(gen-class
:name aot.core.ClassB
:prefix "classB-")

(defn -toString
[this]
"I'm an A.")

(defn -toString
[this]
"I'm a B.")

then both

(.toString (ClassA.))

and

(.toString (ClassB.))

obviously give "I'm a B." as there is only one -toString really defined.

Is it a bug? Am I doing something wrong? How can I make clojure respect :prefix option.



 Comments   
Comment by Daniel Kwiecinski [ 15/Aug/13 5:42 AM ]

Please close the ticket. I have copied an example from a blog post which had wrong keyword.
Instead of :prefix it had :prefix. Notice that fi in :prefix is single character (see: fi fi )

Comment by Alex Miller [ 16/Aug/13 8:59 AM ]

Closed per request





[CLJ-1227] Definline functions do not work as higher-order functions when AOT compiled Created: 27/Jun/13  Updated: 22/Jan/14  Resolved: 21/Jan/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Defect Priority: Blocker
Reporter: Colin Fleming Assignee: Unassigned
Resolution: Declined Votes: 1
Labels: aot
Environment:

OSX 10.8, Linux


Attachments: Text File 0001-CLJ-1227-Fix-definline-in-AOT-scenarios.patch     Zip Archive aot-test.zip    
Patch: Code and Test

 Description   

See discussion on Clojure group: https://groups.google.com/d/topic/clojure/v0ipoiP8X1o/discussion

Functions defined with definline appear to misbehave when AOT compiled and used with higher-order functions - it seems like the macro function is stored instead of the expansion. I've attached a small test project here reproducing the issue. It can be run with:

lein compile
lein uberjar
java -jar target/aot-test-0.1.0-SNAPSHOT-standalone.jar

The relevant part of the test namespace is:

(definline java-list? [element]
  `(instance? List ~element))

(defn -main [& args]
  (println (java-list? 2))
  (println ((var-get #'java-list?) 2))
  (println (filter java-list? [1 2 3]))
  (println (map java-list? [1 2 3])))

The output produced is:

false
(clojure.core/instance? java.util.List 2)
(1 2 3)
((clojure.core/instance? java.util.List 1) (clojure.core/instance? java.util.List 2) (clojure.core/instance? java.util.List 3))


 Comments   
Comment by Tassilo Horn [ 14/Jan/14 9:15 AM ]

I've just fallen into the very same trap. This is definitively a blocker as it means that AOT-compiled code will probably not work correctly if there's a definline in any dependency (transitively).

Comment by Tassilo Horn [ 14/Jan/14 9:57 AM ]

BTW, the problem also applies to the definlines defined in clojure.core such as ints, longs, doubles, etc.

;; This NS is AOT-compiled
(ns aot-test.core
  (:gen-class))

(defn -main [& args]
  (let [ary (make-array Integer/TYPE 5)]
    (println (apply ints [ary]))))

The output is:

% lein uberjar && java -jar target/aot-test-0.1.0-SNAPSHOT-standalone.jar
Compiling aot-test.core
Compiling aot-test.core
Created /home/horn/tmp/aot-test/target/aot-test-0.1.0-SNAPSHOT.jar
Created /home/horn/tmp/aot-test/target/aot-test-0.1.0-SNAPSHOT-standalone.jar
(. clojure.lang.Numbers clojure.core/ints #<int[] [I@39b65439>)
Comment by Tassilo Horn [ 15/Jan/14 3:48 AM ]

I debugged a bit further. What made me wonder is why standard clojure functions with :inline metadata work correctly in AOT-scenarios whereas definlines which expand to normal functions with :inline metadata do not.

The bug can be fixed by adding the :inline metadata immediately in the defn form in the expansion instead of providing it after the defn form using alter-meta!. Here's a demo example:

(ns aot-test.core
  (:gen-class))

;; (definline n? [x]
;;   `(clojure.lang.Util/identical ~x nil))
;;
;; It expands into the following which doesn't work in AOT-scenarios, e.g.,
;; (apply n? [nil]) returns (clojure.lang.Util/identical nil nil) rather than
;; true.
(do
  (clojure.core/defn n? [x] (clojure.lang.Util/identical x nil))
  (clojure.core/alter-meta!
    #'n?
    clojure.core/assoc
    :inline
    (clojure.core/fn n? [x]
      (clojure.core/seq
        (clojure.core/concat
          (clojure.core/list 'clojure.lang.Util/identical)
          (clojure.core/list x)
          (clojure.core/list 'nil)))))
  #'n?)

;; If the expansion would look like this, i.e., the metadata is added directly
;; instead of with alter-meta!, then it works fine in AOT-scenarios.
(do
  (clojure.core/defn nl?
    {:inline (clojure.core/fn fn? [x]
                                 (clojure.core/seq
                                  (clojure.core/concat
                                   (clojure.core/list 'clojure.lang.Util/identical)
                                   (clojure.core/list x)
                                   (clojure.core/list 'nil))))}
    [x] (clojure.lang.Util/identical x nil)))

(defn -main [& args]
  (println "n?")
  (println (meta #'n?))       ;=> {:inline #<core$n_QMARK_ aot_test.core$n_QMARK_@78ffb648>, :ns #<Namespace aot-test.core>, :name n?, :arglists ([x]), :column 3, :line 8, :file aot_test/core.clj}
  (println (apply n? [nil]))  ;=> (clojure.lang.Util/identical nil nil)  BROKEN!!!
  (println (apply n? [1]))    ;=> (clojure.lang.Util/identical 1 nil)    BROKEN!!!
  (println (n? nil))          ;=> true
  (println (n? 1))            ;=> false

  (println "nl?")
  (println (meta #'nl?))      ;=> {:ns #<Namespace aot-test.core>, :name nl?, :file aot_test/core.clj, :column 3, :line 22, :arglists ([x]), :inline #<core$fn_QMARK_ aot_test.core$fn_QMARK_@3b7541a>}
  (println (apply nl? [nil])) ;=> true
  (println (apply nl? [1]))   ;=> false
  (println (nl? nil))         ;=> true
  (println (nl? 1)))          ;=> false
Comment by Tassilo Horn [ 15/Jan/14 4:56 AM ]

Here's a patch fixing the issue by making definline expand only to a defn form where the :inline metadata is added immediately instead of providing it afterwards with alter-meta!.

I also added a deftest in test_clojure/macros.clj which checks for the correctness of the expansions.

Although this patch fixes the problem, it should be somehow/somewhere documented why the former approach didn't work in AOT-scenarios.

Comment by Alex Miller [ 21/Jan/14 9:36 AM ]

definline should be considered to be like defmacro in that it is not a function and cannot be used as a HOF. Additionally, definline is considered to be an experimental feature and Rich would like to discourage its use as the hope is to remove it in the future. The desired replacement is something like common lisp compiler macros that could allow the compiler to detect special situations and optimize the result but leave behind a function invocation for the case where no special behavior is available.

I am declining the ticket based on the info above and per Rich's request.

Comment by Colin Fleming [ 21/Jan/14 2:20 PM ]

This is a little disappointing since there's really no alternative right now, and I'm assuming that this sort of advanced optimisation is a ways off. If this is the plan, I'd definitely recommend marking definline as deprecated and making clear in the docstring that it shouldn't be relied on to return a function. Currently it states: "like defmacro, except defines a named function...", and based on this ticket that is clearly people's expectation.

Comment by Alex Miller [ 21/Jan/14 4:20 PM ]

Sorry about that. I will now split some definitional hairs by saying that definline is marked as "experimental" to indicate it may or may not even become a feature whereas "deprecation" indicates that it was a feature which you should no longer use. I think in this case they serve the same functional intent which is to warn you away from relying on it as part of the language.

Comment by Colin Fleming [ 21/Jan/14 5:28 PM ]

Fair enough, although it's been experimental for five major releases now. If we're convinced it's a failed experiment (and if it can't be relied on to create a function, it pretty much is since you might as well use a macro) I'd argue that deprecation is justified and sends a stronger signal that it doesn't actually work as intended. But either way, I'm certainly convinced now

Comment by Tassilo Horn [ 22/Jan/14 2:58 AM ]

Alex, definline's intention is to be considered like defmacro in case of (my-definline x) where it saves one function call, but to be callable as a normal function in higher-order scenarios like (map my-definline [x y z]). Therefore, it expands to a normal defn form with :inline metadata which is a macro that's used by the compiler.

Wether it should be removed in the future is a separate issue. It is there right now, and people use it. The consequence of this bug is that you cannot trust AOT-compiled code, because there might be some dependency that uses definline. Additionally, all clojure.core definlines (booleans, bytes, chars, shorts, floats, ints, doubles, longs) are broken when applied as HOF, because clojure itself is always distributed in AOT-compiled form.

Really, it would be grossly negligent to release Clojure 1.6 knowing of this bug.

I've written a more detailed mail to the clojure-dev list:

https://groups.google.com/d/msg/clojure-dev/UeLNJzp7UiI/UCyVvYLfHWMJ

Comment by Tassilo Horn [ 22/Jan/14 3:35 PM ]

The root cause of this issue is CLJ-1330 as investigated by Nicola Mometto in the thread cited above: http://dev.clojure.org/jira/browse/CLJ-1330
So fixing the latter will fix this one, too.





[CLJ-1215] Mention where to position docstring when using pre/postconditions on the Special Forms page Created: 07/Jun/13  Updated: 03/Sep/13  Resolved: 03/Sep/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Jakub Holy Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: documentation


 Description   

The description of pre- and post-conditions doesn't mention where docstring should be when using them. Placing it wrong will lead to the conditions to be ignored.

At http://clojure.org/Special%20Forms--(fn%20name?%20[params*%20]%20condition-map?%20exprs*), change

(fn name? [params* ] condition-map? exprs*)

to

(fn name? [params* ] condition-map? docstring? exprs*)

or at least mention it in the description or use it in the example.

Thank you!



 Comments   
Comment by Alex Miller [ 03/Sep/13 8:59 AM ]

The fn special form does not take a docstring so this modification is not valid. fn takes docstrings via meta.

The defn macro does take a docstring but it is placed prior to the attr-map, not after the condition map. The defn docstring does mention that the docstring will be added to the var metadata for the fn (not on the fn itself).





[CLJ-1214] Compiler runs out of memory on a small snippet of code Created: 31/May/13  Updated: 18/Apr/14  Resolved: 18/Apr/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Praki Prakash Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: compiler
Environment:

Linux 3.2.0-39-generic


Attachments: File fubar.clj    

 Description   

Clojure compiler runs out of memory when loading the attached file. Transcript below.

$ java -cp ~/.m2/repository/org/clojure/clojure/1.5.1/clojure-1.5.1.jar:. clojure.main
Clojure 1.5.1
user=> (load "fubar")
OutOfMemoryError GC overhead limit exceeded  [trace missing]
user=> 

The file contents are:

  (ns fu.bar)

  (defn foo[l] (concat (drop-last l) (repeat (last l))))

  (def ^:const bar (foo [#(print "") #(println ";")]))

  bar

If I remove the metadata on bar, it works. Removal of namespace seems to fix it as well. Pretty strange.

Although I realize this code is not quite kosher, it would be nice to have the compiler deal with it.



 Comments   
Comment by Andy Fingerhut [ 01/Jun/13 7:40 PM ]

If you really do have 'bar' on a line by itself at the end of file fubar.clj, it seems you are asking it to evaluate the value of bar, which by the definitions is an infinite list, and will of course exhaust all available memory if you attempt to evaluate it.

It seems to me the more odd thing is not that it runs out of memory as shown, but that it does not run out of memory when you remove the metadata on bar.

What is the purpose of having 'bar' on a line by itself at the end of the file?

If I try this but remove 'bar' as the last line of the file, loading the file causes no errors regardless of whether there is metadata on bar's definition or not. It is strange that doing (load "fubar") followed by (first fu.bar/bar) seems to go into an infinite loop if the :const is there on bar, but quickly returns the correct answer if the metadata is removed.

Comment by Praki Prakash [ 01/Jun/13 8:40 PM ]

This code snippet is a minimal test case to show that the compiler runs out of memory. What I meant by "it works" was that the compiler doesn't run out of memory and successfully loads the file (or in my real code base, the namespace is compiled).

In my code, I use bar (or whatever the real thing is) as source of sequence of functions. The sole reference to bar is needed to trigger this issue. I believe that bar is not being fully evaluated here and thus no infinite loop. If I try to print it, yes, it will ultimately fail.

Comment by Praki Prakash [ 01/Jun/13 9:04 PM ]

Having thought about this a bit more, it seems to me that when bar is annotated with const, the compiler is trying to evaluate the associated expression which exhausts the heap? I have never looked at the compiler source and thus not sure if this is what is happening. If it is, then it seems like one should be really careful when adding metadata.

That still leaves the other question about the namespace requirement to cause memory exhaustion. I quite distinctly recall having to add the namespace when trying to come up with minimal test case to reproduce the bug.

If you think this is really user error, I would accept it

Comment by Andy Fingerhut [ 02/Jun/13 4:56 AM ]

It is not just any old metadata that causes this issue, only :const metadata. I tried testing with :const replaced with :dynamic and :private, and there was no problem.

This might shed some light on the issue: https://github.com/clojure/clojure/blob/master/changes.md#215-const-defs

It appears that ^:const is causing the compiler to evaluate the value at compile time. The value in your example is unbounded, so that can never complete.

Comment by Kevin Downey [ 17/Apr/14 10:39 PM ]

the problem is for complex objects :const results in the pr-str of the object being embedded in the bytecode, a pr-str of an infinite seq is going to blow the heap. I think the limits on the usage of :const are not well defined and instead of falling back on pr-str it should throw a compilation error for constants that are not jvm primitves or strings

Comment by Alex Miller [ 17/Apr/14 10:46 PM ]

There is support for handling a variety of other useful cases (core Clojure collections for example) as constant objects. And it is useful to allow code that is not constant but evaluates to a constant result (for creating data tables, etc). In the face of that, I'm not sure it's possible to bound this usefully without solving the halting problem. I'm tempted to just put this issue in the category of "don't do that".

Comment by Alex Miller [ 18/Apr/14 7:08 AM ]

After sleeping on it, I don't think this is worth working on (if there is anything that could even be done).





[CLJ-1213] consistency with def and Unbound Created: 29/May/13  Updated: 03/Sep/13  Resolved: 03/Sep/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Trevor Wennblom Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

In this example I'd expect `b` to return `Unbound` for consistency.

Clojure 1.5.1
user=> (def a "MyA")
#'user/a
user=> (def a "MyA2")
#'user/a
user=> (def b "MyB")
#'user/b
user=> (def b) ;; unbound b
#'user/b
user=> (def c) ;; unbound c
#'user/c
user=> a
"MyA2"
user=> b
"MyB"
user=> c
#<Unbound Unbound: #'user/c>


 Comments   
Comment by Alex Miller [ 03/Sep/13 9:27 AM ]

The docstring for def states that the init? function is optional and that in the case where it is omitted, the root binding is unaffected.





[CLJ-1211] Protocol call sites emit many unused fields and bytecodes Created: 25/May/13  Updated: 25/May/13  Resolved: 25/May/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Ghadi Shayban Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None

Attachments: File protocol-sites.diff    
Patch: Code

 Description   

Three unused instance member fields are emitted by emitProto() in the compiler - seems that at some point it was for inline caching of protocol implementations, but it looks like that's all handled by MethodImplCache now.

This patch eliminates it, and brings down protocol heavy classes like the new ManyToManyChannel in core.async from 120+ fields down to 23 fields, mostly Var caches.

There should be a lot less bytecode in such classes now, and less memory overhead.



 Comments   
Comment by Ghadi Shayban [ 25/May/13 10:49 AM ]

Needs work





[CLJ-1203] Fallback to hash-based comparison for non-Comparables in Util.compare() Created: 17/Apr/13  Updated: 29/Apr/13  Resolved: 29/Apr/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Tassilo Horn Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: enhancement, patch

Attachments: Text File 0001-Add-hasheq-based-fallback-to-Util.compare.patch    
Patch: Code

 Description   

I oftentimes use sorted collections, and my comparator functions usually look like that:

(fn [a b]
  (let [x (compare-according-to-my-use-case a b)]
    (if (zero? x)
       (compare a b)
       x)))

That is, I define the sorting order depending on the requirements of my use-case, and if that doesn't suffice to make a distinction, I simply fall back to the standard `compare` function in order to get a stable ordering anyhow. I think that's a widely used idiom, e.g., also used in "Clojure Programming" (for example page 109).

The problem with this approach is that several data structures don't implement Comparable, and thus aren't applicable to `compare` (you'll get a ClassCastException). Examples are maps, records, deftypes, and sequences.

The patch I'm going to attach extends `Util.compare()` with a fallback clause that performs a `hasheq()`-based comparison. This results in a meaningless but at least stable sorting order which suffices for use-cases like the one shown above.



 Comments   
Comment by Andy Fingerhut [ 18/Apr/13 9:01 PM ]

Patch 0001-Add-hasheq-based-fallback-to-Util.compare.patch dated Apr 17 2013 applies cleanly to latest master, but causes several unit tests in data_structures.clj to fail. These are the kinds of things you would expect to fail with the change made in the patch, because the failing tests expect an exception to be thrown when comparing objects that don't implement Comparable, and with this patch's changes they no longer do. If this patch's change is desired, those tests should probably be removed.

Comment by Tassilo Horn [ 19/Apr/13 2:34 AM ]

Thanks Andy, I can't believe I've forgotten to re-run the tests.

Anyway, I'm attaching a new version of the patch that deletes the few sorted-set and sorted-set-by invocations that check that an exception is thrown when creating sorted sets containing non-Comparables.

Comment by Tassilo Horn [ 19/Apr/13 2:35 AM ]

New version of the patch.

Comment by Andy Fingerhut [ 26/Apr/13 2:47 PM ]

Tassilo, you say that one of your use cases is sorted collections. Note that any compare function that returns 0 for two values will cause sorted sets and maps to treat the two compared values as equal, and at most one of them will get into the ordered set/map, the second treated as a duplicate, even though the values are not equal. See https://github.com/jafingerhut/thalia/blob/master/doc/other-topics/comparators.md#comparators-for-sorted-sets-and-maps-are-easy-to-get-wrong for an example (not based on your modified compare, but on a comparator that returns 0 for non-equal items).

With your proposed change to compare, this occurrence would become very dependent upon the hash function used. Probably quite rare, but it would crop up from time to time, and could potentially be very difficult to detect and track down the source.

Comment by Tassilo Horn [ 29/Apr/13 2:29 AM ]

Hi Andy, you are right. It's possible to add an explicit equals()-check in cases the hashcodes are the same, but I think there's nothing you can do in the hashcodes-equal-but-objects-are-not case. That is, there's no way to ensure the rule sgn(compare(x, y)) == -sgn(compare(y, x)), the transitivity rule, and the compare(x, y)==0 ==> sgn(compare(x, z))==sgn(compare(y, z)) for all z rule.

I'm closing that ticket.





[CLJ-1194] Typo in core.reducers Created: 08/Apr/13  Updated: 09/Apr/13  Resolved: 09/Apr/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Dmitry Groshev Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

As far as I can say, there is a typo in core.reducers (and therefore core.reducers/monoid is unusable in 1.5.1):

https://github.com/clojure/clojure/blob/master/src/clj/clojure/core/reducers.clj#L321

(fn m <-- this
    ([] (ctor))
    ([a b] (op a b))))

Should I submit a patch to fix this?



 Comments   
Comment by Ghadi Shayban [ 08/Apr/13 3:09 PM ]

I guess you didn't try to actually use the function to see if it is actually broken...

m is not a argument vector, those are below in the function clauses.

Comment by Dmitry Groshev [ 08/Apr/13 3:26 PM ]

I did, but as it turns out the error was somewhere else and I can't reproduce it within a "clean" environment. Sorry for this hasty ticket.

Comment by Andy Fingerhut [ 08/Apr/13 11:31 PM ]

Dmitry, do you think it is OK to close this ticket as declined, meaning no change will be made in response to it? I can do that for you, if you wish.

Comment by Dmitry Groshev [ 09/Apr/13 4:49 AM ]

Andy, I'll close it myself if you don't mind. I would done it earlier, but didn't have sufficient rights in JIRA.





[CLJ-1182] Regexp are never equal Created: 12/Mar/13  Updated: 11/Apr/14  Resolved: 05/Sep/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Christian Fortin Assignee: Omer Iqbal
Resolution: Declined Votes: 0
Labels: None

Attachments: File fix-CLJ-1182.diff    
Patch: Code
Approval: Triaged

 Description   

The following (= #"asd" #"asd") will return false in CLJ, even if they are the same.

Consequently, everything with a regexp in it (lists, vectors, maps...) will never be equal.

It seems to have been fixed for CLJS, but not for CLJ.
https://github.com/clojure/clojurescript/commit/e35c3a57472fa62ae41591418a73794dc8ac6dde



 Comments   
Comment by Omer Iqbal [ 12/Mar/13 4:08 PM ]

added an implementation for the equiv method if both args are java.util.regex.Pattern

Comment by Andy Fingerhut [ 12/Mar/13 5:54 PM ]

Omer, could you also include in your patch a few test cases? At least one that validates that two regex's that should be equal, are equal, and another that two regex's that should be different, are non-equal. Preferably the first of those tests should fail with the existing Clojure code, and pass with your changes.

Comment by Omer Iqbal [ 13/Mar/13 5:39 AM ]

I updated the patch with some tests. Hope I added them in the correct file. I also changed the implementation a bit, by instead of adding another implementation of equiv with a different signature, checking the type of the Object in the equiv method with signature (Object k1, Object k2).
For the sake of consistency I also added an EquivPred implementation, though I'm not entirely sure when its used.

Comment by Andy Fingerhut [ 13/Mar/13 1:04 PM ]

All comments here refer to the patch named fix-CLJ-1182.diff dated Mar 13, 2013.

The location for the new tests looks reasonable. However, note that your new patch has your old changes plus some new ones, not just the new ones. In particular, the new signature for equiv is still in your latest patch. You should start from a clean pull of the latest Clojure master and make only the changes you want when creating a patch, not build on top of previous changes you have made.

Also, there are several whitespace-only changes in your patch that should not be included.

Comment by Omer Iqbal [ 13/Mar/13 1:39 PM ]

I uploaded a clean patch, removing the whitespace diff and only adding the latest changes. Thanks for clarifying the workflow!
Just to clarify, this refers to the patch named fix-CLJ-1182.diff dated Mar 13 1:34 PM

Comment by Stuart Halloway [ 29/Mar/13 5:46 AM ]

I am recategorizing this as an enhancement, because if this is a bug it is a bug in Java – the Java Patterns class documents being immutable, but apparently does not implement .equals.

Other recent "make Clojure more complicated to work around problems in Java" patches have been rejected, and I suspect this one will be too, because it might impact the performance of equality everywhere.

Comment by Stuart Halloway [ 12/Apr/13 9:04 AM ]

At first pass, Rich and I both believe that, as regex equality is undecidable, that Java made the right choice in using identity for equality, that this ticket should be declined, and the ClojureScript should revert to match.

But leaving this ticket open for now so that ClojureScript dev can weigh in.

Comment by Michael Drogalis [ 12/Apr/13 9:32 AM ]

What do you mean when you say "undecidable"?

Comment by Alexander Redington [ 12/Apr/13 10:03 AM ]

If Regex instances were interned by the reader, but still used identity for equality, then code like

(= #"abc" #"abc")

would return true, but it wouldn't diverge in the definition of equality for regular expressions between Java and Clojure.

Comment by Fogus [ 12/Apr/13 10:13 AM ]

Undecidable means that for any given regular expression, there is no single way to write it. For example #"[a]" #"a" both match the same strings, but are they the same? Maybe. But how can we decide if /any/ given regular expression matches all of the same strings as any other? The answer is, you can't. Java does provide a Pattern#pattern method that returns the string that was used to build it, but I'm not sure if that could/should be used as a basis for equality given the potential perf hit.

Comment by Herwig Hochleitner [ 12/Apr/13 10:31 AM ]

I posted in Stu's thread: https://groups.google.com/d/topic/clojure-dev/OTPNJQbPtds/discussion
TL;DR: Disagree with undecidability, agree with reverting to identity based equality

Comment by Michael Drogalis [ 12/Apr/13 10:32 AM ]

That makes sense to me. Thanks Fogus.

Comment by Herwig Hochleitner [ 12/Apr/13 9:42 PM ]

From my post to the ml thread, it might not be entirely clear, why I don't think we should implement equality for host regexes:

It would involve parsing and would leave a lot of room for errors and platform-idiosycracies to leak. And it would be different for every platform.

As Alexander said, I also think this ticket could be resolved by interning regex literals, akin to keywords. That, however, would warrant a design page first, because there are tradeoffs to be made about how far the interning should go.

Comment by Rich Hickey [ 13/Apr/13 8:51 AM ]

Why are we spending time on this? Where is the problem statement? Does someone actually need this for a real world purpose not solved by using regex strings as keys?

Comment by Michael Drogalis [ 13/Apr/13 9:13 PM ]

It was prompted as a matter of consistency, which I think is valid. I can't think of a good reason to use regex's as keys though.

Comment by Trevor Hartman [ 11/Apr/14 11:13 AM ]

This issue surfaced as a bug in my code, e.g.: (get {#"^named$" 1} #"^named$") ;=> nil ; surprise!





[CLJ-1179] distinct? does not accept zero arguments Created: 09/Mar/13  Updated: 04/Jan/14  Resolved: 12/Apr/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.4, Release 1.5
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Jean Niklas L'orange Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: bug

Attachments: Text File clj-1179-distinct-zero-arguments.txt    
Patch: Code

 Description   

distinct? cannot be invoked with zero arguments. When using the pattern (apply distinct? x), this is bothersome as you have to check whether x is empty or not. It is also logical that distinct? should return true if no arguments are given, since there are no duplicates.

What (small set of) steps will reproduce the problem?

user=> (apply distinct? [])
ArityException Wrong number of args (0) passed to: core$distinct-QMARK-  clojure.lang.AFn.throwArity (AFn.java:437)

What is the expected output? What do you see instead?

I would expect distinct? to return true whenever given zero arguments.

What version are you using?

This was tested under Clojure 1.4 and Clojure 1.5.



 Comments   
Comment by Jean Niklas L'orange [ 09/Mar/13 6:08 AM ]

Attached the straightforward patch which solves this issue.

Comment by Devin Walters [ 04/Jan/14 1:32 PM ]

Is there a reason this was closed without a comment?

Comment by Alex Miller [ 04/Jan/14 2:12 PM ]

Rich declined it, implying that it was not a change he wanted. Not sure of the reason.





[CLJ-1178] Requiring the same ns doesn't throw an exception Created: 07/Mar/13  Updated: 29/Mar/13  Resolved: 29/Mar/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Trivial
Reporter: Michael Drogalis Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

The compiler will happily allow requiring the same ns twice. I can't see any reason you'd intentionally do this.

(ns program
  (:require [program.a :as a]
            [program.a :as b])

This caused some confusion for a while as to why b wasn't producing the expected functionality. Just a simple mistake that I think can be caught at compile time.



 Comments   
Comment by Stuart Halloway [ 29/Mar/13 5:57 AM ]

The example shows valid Clojure code.





[CLJ-1170] conj-ing x on equal values should produce equal results Created: 23/Feb/13  Updated: 01/Mar/13  Resolved: 01/Mar/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.4
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Irakli Gozalishvili Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

I've recently have run into a WHAT behavior here is an example:

```clojure
(def head 1)
(def tail [2 3])

(= tail (rest (cons head tail))) ; true

;; Types don't really match but close enough I guess
(type tail) ; clojure.lang.PersistentVector
(vector? tail) ; true
(type (rest (cons head tail))) ; clojure.lang.PersistentVector$ChunkedSeq
(vector? (rest (cons head tail))) ; false

;; Bet then it get's ugly (I would expect them to be equal)
(= (conj tail :x) (conj (rest (cons head tail)) :x)) ; false

;; Because
(conj tail :x) ; [2 3 :x]
(conj (rest (cons head tail)) :x) ;(:x 2 3)
```

This brings me to a pretty surprising behavior, which is conj-ing
equal values produce non-equal results:

```clojure
(= '(2 3) [2 3]) ; true
(= (conj '(2 3) 1) (conj [2 3] 1))
```

I think conj should either produce equal results or list and vectors with
same elements should not be equal. That would also resolve a previous
problem, although intuitively I would expect `(rest (cons x y))` to
return `y` back.



 Comments   
Comment by Andy Fingerhut [ 24/Feb/13 10:46 AM ]

Irakli, it is an explicitly documented feature that conj puts new items in different places for lists (at the beginning) and vectors (at the end). rest is explicitly documented to call seq on its argument. See their doc strings.

I don't know if it is explicitly documented, or just long-standing practice, that vectors and seqs with the the same sequence of values in them are equal. I think that a lot of existing code would break if Clojure changed so those were not equal.





[CLJ-1166] Range function accumulates minor errors when called on floating-point numbers Created: 19/Feb/13  Updated: 29/Mar/13  Resolved: 01/Mar/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Defect Priority: Trivial
Reporter: Stephen Nelson Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

Due to range's incremental computation minor errors introduced by floating point arithmetic accumulate, becoming more noticeable in long ranges and causing unexpected behaviour.

Compare the output of the following:

=> (range 0.0 10.0 0.1)
(0.0 0.1 0.2 0.30000000000000004 0.4 0.5 0.6 0.7 0.7999999999999999 0.8999999999999999 0.9999999999999999 1.0999999999999999 1.2 1.3 1.4000000000000001 1.5000000000000002 1.6000000000000003 1.7000000000000004 1.8000000000000005 1.9000000000000006 2.0000000000000004 2.1000000000000005 2.2000000000000006 2.3000000000000007 2.400000000000001 2.500000000000001 2.600000000000001 2.700000000000001 2.800000000000001 2.9000000000000012 3.0000000000000013 3.1000000000000014 3.2000000000000015 3.3000000000000016 3.4000000000000017 3.5000000000000018 3.600000000000002 3.700000000000002 3.800000000000002 3.900000000000002 4.000000000000002 4.100000000000001 4.200000000000001 4.300000000000001 4.4 4.5 4.6 4.699999999999999 4.799999999999999 4.899999999999999 4.999999999999998 5.099999999999998 5.1999999999999975 5.299999999999997 5.399999999999997 5.4999999999999964 5.599999999999996 5.699999999999996 5.799999999999995 5.899999999999995 5.999999999999995 6.099999999999994 6.199999999999994 6.299999999999994 6.399999999999993 6.499999999999993 6.5999999999999925 6.699999999999992 6.799999999999992 6.8999999999999915 6.999999999999991 7.099999999999991 7.19999999999999 7.29999999999999 7.39999999999999 7.499999999999989 7.599999999999989 7.699999999999989 7.799999999999988 7.899999999999988 7.999999999999988 8.099999999999987 8.199999999999987 8.299999999999986 8.399999999999986 8.499999999999986 8.599999999999985 8.699999999999985 8.799999999999985 8.899999999999984 8.999999999999984 9.099999999999984 9.199999999999983 9.299999999999983 9.399999999999983 9.499999999999982 9.599999999999982 9.699999999999982 9.799999999999981 9.89999999999998 9.99999999999998)

=> (defn range' [start end step] (map #(+ start (* % step)) (range 0 (/ (- end start) step) 1)))
=> (range' 0.0 10.0 0.1)
(0.0 0.1 0.2 0.30000000000000004 0.4 0.5 0.6000000000000001 0.7000000000000001 0.8 0.9 1.0 1.1 1.2000000000000002 1.3 1.4000000000000001 1.5 1.6 1.7000000000000002 1.8 1.9000000000000001 2.0 2.1 2.2 2.3000000000000003 2.4000000000000004 2.5 2.6 2.7 2.8000000000000003 2.9000000000000004 3.0 3.1 3.2 3.3000000000000003 3.4000000000000004 3.5 3.6 3.7 3.8000000000000003 3.9000000000000004 4.0 4.1000000000000005 4.2 4.3 4.4 4.5 4.6000000000000005 4.7 4.800000000000001 4.9 5.0 5.1000000000000005 5.2 5.300000000000001 5.4 5.5 5.6000000000000005 5.7 5.800000000000001 5.9 6.0 6.1000000000000005 6.2 6.300000000000001 6.4 6.5 6.6000000000000005 6.7 6.800000000000001 6.9 7.0 7.1000000000000005 7.2 7.300000000000001 7.4 7.5 7.6000000000000005 7.7 7.800000000000001 7.9 8.0 8.1 8.200000000000001 8.3 8.4 8.5 8.6 8.700000000000001 8.8 8.9 9.0 9.1 9.200000000000001 9.3 9.4 9.5 9.600000000000001 9.700000000000001 9.8 9.9)



 Comments   
Comment by Stephen Nelson [ 19/Feb/13 3:06 PM ]

=> (last (range 0.0 10000000.0 0.1))
9999999.98112945
=> (last (range' 0.0 10000000.0 0.1))
9999999.9

Comment by Stuart Halloway [ 01/Mar/13 10:08 AM ]

Range is incremental by design, and that is how floats work. Something with the desired behavior would need to be a different fn with a different name.

Comment by Stephen Nelson [ 03/Mar/13 2:38 PM ]

"Returns a lazy seq of nums from start (inclusive) to end (exclusive), by step"

What specifically about that wording specifically suggests that the implementation will use naive increment-and-recurse behaviour? My reading is that the function will return a lazy sequence of numbers from start to end separated by step, not separated by 'almost step'.

This implementation leads to unexpected behaviour with bounds:

=> (count (range 0 100 1))
100
=> (count (range 0 10 0.1))
101

http://www.ima.umn.edu/~arnold/455.f96/disasters.html

Comment by Timothy Pratley [ 29/Mar/13 5:09 PM ]

range could avoid this issue cleanly by converting floats to bigdecimals (let me know if you think this is a good idea?)

I ran into this problem recently, and have to say it was pretty ugly. This is how I avoided the issue:

(defn rangef
"Returns a sequence of n numbers from start to end inclusive."
[start end n]
(for [i (range 0 n)]
(+ start (* i (/ (- end start) (dec n))))))

Hope that helps any disillusioned float users out there, or just pass in BigDecimals to range instead of floats... I would go so far as to say using floats with range as it stands is almost always going to end in tears (or worse as Stephen describes ).

Comment by Timothy Pratley [ 29/Mar/13 5:10 PM ]

[and just to be clear if it is considered an error, it would be nice if range explicitly forbade it]





[CLJ-1156] clojure.walk/stringifiy-keys does not stringify non-keyword keys Created: 03/Feb/13  Updated: 01/Mar/13  Resolved: 04/Feb/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.4
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Joel Kuiper Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

The doc says "Recursively transforms all map keys from keywords to strings." however only those keys that pass keyword? get transformed to string. This leaves other keys such as java.Long as-is.

A simple fix would be

(defn stringify-keys*
"Recursively transforms all map keys from keywords to strings."
[m]
(let [f (fn [[k v]] (if (keyword? k) [(name k) v] [(str k) v]))]
;; only apply to maps
(postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m)))



 Comments   
Comment by Andy Fingerhut [ 03/Feb/13 11:20 PM ]

It appears from the doc string that this function does exactly what it claims it will do, without any changes.

Comment by Joel Kuiper [ 04/Feb/13 4:29 AM ]

You're right.
Somehow I parsed the doc string wrongly. My sincere apologies! Can be marked invalid.

Comment by Andy Fingerhut [ 04/Feb/13 9:30 AM ]

Closing as declined, since submitter agrees that code behavior and documentation match.





[CLJ-1155] Suppress tracebacks from clojure.core Created: 01/Feb/13  Updated: 29/Mar/13  Resolved: 29/Mar/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Wilfred Hughes Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: enhancement

Attachments: Text File suppress_tracebacks.patch    
Patch: Code

 Description   

It would be really nice if we could hide the Java traceback from the compiler when it's not relevant. When there's no Java interop, it's not useful. I can't see any case where we want the tracebacks from the compiler referencing clojure.core.

Here's how a syntax error traceback looks at the moment on trunk:

$ more dodgy-map.clj
(defn dodgy-map []
  {:1 :2 :3})
$ java -cp target/clojure-1.5.0-master-SNAPSHOT.jar clojure.main dodgy-map.clj
Exception in thread "main" java.lang.RuntimeException: Map literal must contain an even number of forms, compiling:(/home/wilfred/src/clojure/dodgy-map.clj:2:13)
	at clojure.lang.Compiler.load(Compiler.java:7070)
	at clojure.lang.Compiler.loadFile(Compiler.java:7020)
	at clojure.main$load_script.invoke(main.clj:286)
	at clojure.main$script_opt.invoke(main.clj:348)
	at clojure.main$main$fn__6682.invoke(main.clj:432)
	at clojure.main$main.doInvoke(main.clj:429)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.lang.Var.invoke(Var.java:415)
	at clojure.lang.AFn.applyToHelper(AFn.java:161)
	at clojure.lang.Var.applyTo(Var.java:532)
	at clojure.main.main(main.java:37)
Caused by: java.lang.RuntimeException: Map literal must contain an even number of forms
	at clojure.lang.Util.runtimeException(Util.java:219)
	at clojure.lang.LispReader$MapReader.invoke(LispReader.java:1090)
	at clojure.lang.LispReader.readDelimitedList(LispReader.java:1145)
	at clojure.lang.LispReader$ListReader.invoke(LispReader.java:979)
	at clojure.lang.LispReader.read(LispReader.java:182)
	at clojure.lang.Compiler.load(Compiler.java:7058)
	... 10 more

With my patch, this is simplified to:

$ java -cp target/clojure-1.5.0-master-SNAPSHOT.jar clojure.main dodgy-map.clj
java.lang.RuntimeException: Map literal must contain an even number of forms, compiling:(/home/wilfred/src/clojure/dodgy-map.clj:2:13)

Another example: here's how name errors appear on trunk:

$ more i-dont-exist.clj
(defn no-such-variable []
  i-dont-exist)
$ java -cp target/clojure-1.5.0-master-SNAPSHOT.jar clojure.main i-dont-exist.clj
Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol: i-dont-exist in this context, compiling:(/home/wilfred/src/clojure/i-dont-exist.clj:1:1)
	at clojure.lang.Compiler.analyze(Compiler.java:6380)
	at clojure.lang.Compiler.analyze(Compiler.java:6322)
	at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5708)
	at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5139)
	at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3751)
	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6558)
	at clojure.lang.Compiler.analyze(Compiler.java:6361)
	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6548)
	at clojure.lang.Compiler.analyze(Compiler.java:6361)
	at clojure.lang.Compiler.access$100(Compiler.java:37)
	at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:529)
	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6560)
	at clojure.lang.Compiler.analyze(Compiler.java:6361)
	at clojure.lang.Compiler.analyze(Compiler.java:6322)
	at clojure.lang.Compiler.eval(Compiler.java:6623)
	at clojure.lang.Compiler.load(Compiler.java:7063)
	at clojure.lang.Compiler.loadFile(Compiler.java:7020)
	at clojure.main$load_script.invoke(main.clj:286)
	at clojure.main$script_opt.invoke(main.clj:348)
	at clojure.main$main$fn__6682.invoke(main.clj:432)
	at clojure.main$main.doInvoke(main.clj:429)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.lang.Var.invoke(Var.java:415)
	at clojure.lang.AFn.applyToHelper(AFn.java:161)
	at clojure.lang.Var.applyTo(Var.java:532)
	at clojure.main.main(main.java:37)
Caused by: java.lang.RuntimeException: Unable to resolve symbol: i-dont-exist in this context
	at clojure.lang.Util.runtimeException(Util.java:219)
	at clojure.lang.Compiler.resolveIn(Compiler.java:6874)
	at clojure.lang.Compiler.resolve(Compiler.java:6818)
	at clojure.lang.Compiler.analyzeSymbol(Compiler.java:6779)
	at clojure.lang.Compiler.analyze(Compiler.java:6343)
	... 25 more

With patch:

$ java -cp target/clojure-1.5.0-master-SNAPSHOT.jar clojure.main i-dont-exist.clj
java.lang.RuntimeException: Unable to resolve symbol: i-dont-exist in this context, compiling:(/home/wilfred/src/clojure/i-dont-exist.clj:1:1)

I'm not familiar with the compiler internals, but I've attached a tentative patch. Undoubtedly it isn't perfect. For one, it would be nicer to say 'Syntax error' rather than 'java.lang.RuntimeException'. All the tests pass with this change.

Relevant mailing list discussion: https://groups.google.com/forum/?fromgroups=#!searchin/clojure/wilfred/clojure/M5NlEW7HJ_c/joUY6mo6Rd8J

Please let me know what you think. This would make my life easier when developing.



 Comments   
Comment by Stuart Halloway [ 29/Mar/13 6:06 AM ]

It is easy for tools that consume Clojure to hide stack traces for those who do not want to see them. If Clojure itself eats stack traces, it is impossible for those of us who do want to see them to get them back.

Please do this kind of work in tool (if at all) and make it optional for users.





[CLJ-1153] Change *read-eval* default value to false Created: 30/Jan/13  Updated: 01/Mar/13  Resolved: 09/Feb/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.3, Release 1.4, Release 1.5
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Andy Fingerhut Assignee: Unassigned
Resolution: Declined Votes: 33
Labels: None

Attachments: Text File clj-1153-patch-v2.txt     Text File CLJ-1185.patch    
Patch: Code

 Description   

Discussion on the security implications of read-eval defaulting to true here: https://groups.google.com/forum/?fromgroups=#!topic/clojure/qUk-bM0JSGc

I'm not sure whether the unit test that needs read-eval true in order to pass is a sign of lots of other code that would break if read-eval defaulted to false.



 Comments   
Comment by Phil Hagelberg [ 31/Jan/13 11:55 AM ]

It's worth noting that there was a breakin to rubygems.org over the weekend that was caused by what amounts to this same issue, but with YAML: https://news.ycombinator.com/item?id=5141138

The current default is both dangerous and undocumented; this needs to change.

Comment by Soren Macbeth [ 31/Jan/13 12:33 PM ]

Seconded!

Comment by Mike Anderson [ 01/Feb/13 12:52 AM ]

Thirded.

For what it's worth, on the topic of breaking changes I'd much rather my old code break than continue to work with an unnoticed security hole.

Comment by Stuart Halloway [ 01/Feb/13 7:21 AM ]

Fourthed. I hope folks will pitch in and help deal with any breakage.

Comment by Chas Emerick [ 01/Feb/13 12:57 PM ]

New patch attached, {{CLJ-1185.patch}}.

This patch eliminates the use of *print-dup* in the compiler entirely. read-string continues to be used to support values that can only be represented via tagged reader literals; I don't think there's any way around that, since the mapping between particular data readers and values' types are buried in individual print-method implementations.

All tests pass (including cases like (eval (list + 1 2 3)) as discussed in the ML thread referenced in the issue description), and a variety of sanity checks around evaluation and compilation tooling (e.g. AOT, nREPL, introspection utilities in Leiningen/Reply/Counterclockwise) all work as expected.

Of course, if this is applied, then any usage of read over trusted content containing #= forms will need to be done with *read-eval* bound to true.

To aid in testing, a Clojure build (1.5.0-RC4) + this patch is available here:

[com.cemerick/clojure "1.5.0-SNAPSHOT"]

Note that you'll have to exclude the standard Clojure dependency from your project in order for this one to take precedence; you can do this by adding

:exclusions [org.clojure/clojure]

to your project.clj.

Comment by Paul Stadig [ 01/Feb/13 2:49 PM ]

I ran the Sonian test base against this patch. I wouldn't say our test cases are comprehensive, but they're not trivial. We talk to databases through JDBC, and we deal with lots of different data types (BigInts, Strings, Dates, and such).

I had to make a few small changes to our code base, because we rely pretty heavily on print-dup to serialize non-user originated data. We have to add corresponding binding blocks when reading to set read-eval to true. Other than that, the tests all passed.

+1

Comment by Chas Emerick [ 01/Feb/13 4:28 PM ]

Thanks to all that have tested the patch! Looks like we've made some progress. I'm going to post to the main Clojure ML now and hopefully get more yay/nay votes.

Comment by Andy Fingerhut [ 02/Feb/13 11:05 AM ]

clj-1153-patch-v2.txt dated Feb 2 2013 is functionally identical to Chas Emerick's CLJ-1185.patch dated Feb 1 2013, and no retesting is needed by anyone because of it.

The only change I have made to his patch is: the doc string for read-eval now says its default value is false.

Comment by Andy Fingerhut [ 02/Feb/13 11:06 AM ]

Also removed my original didn't-fix-enough-things patch from Jan 30 2013.

Comment by Tim McCormack [ 02/Feb/13 3:22 PM ]

I'm bumping the Priority field from its default value to "Major" to reflect recent events. (I personally feel "blocker" would be more appropriate, or at least "critical", but I don't want to step on any toes.)

Comment by Rich Hickey [ 04/Feb/13 7:55 PM ]

https://github.com/clojure/clojure/commit/974a64c06917861b7557fd73154254195b2de548

Comment by Rich Hickey [ 09/Feb/13 9:17 AM ]

This ticket is an excellent example of a terrible ticket.

1) It does not lead with a problem statement. The title takes the form akin to "I want X". It proposes a tactic.

2) The description is woefully inadequate. Here too, no problem statement. Descriptions should point to any discussions, but discussions are long and rambling, and no substitute for a succinct problem statement in the description. Descriptions need to be maintained, with the current strategy and name of best patch.

3) No resolution strategy. Just patches attached. How is a reviewer supposed to assess your patch if you don't even bother stating what the problem is and what your approach will be in fixing it, how that approach does fix it, and what if any tradeoffs are being made?

4) The change being requested would be a breaking change. That should be made extremely clear in the description, and doubles the threshold for quality of motivation and implementation.

5) Any breaking change would have to carefully enumerate what would break and when, what the migration strategy would be etc.

6) The patch breaks the compiler. If you don't understand how the compiler works, and why features are there, you shouldn't submit patches that alter it. The only assessments made in comments are 'it works for me', which, while useful anecdotes, are insufficient.

While the ticket itself was bad, the uncritical rallying behind it was more troubling. This is not how Clojure was built, and will not be how it is maintained.

In the end, the ticket proposed a tactic, and that tactic has been rejected. Read safety has been addressed by other means.





[CLJ-1139] Compiler exception while compiling swank/commands/basic.clj Created: 23/Dec/12  Updated: 09/Feb/13  Resolved: 09/Feb/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Brian Rowe Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:
  • Clojure: 1.5.0-RC1
  • Java: Java 1.7.0_05 Java HotSpot(TM) 64-Bit Server VM
  • Leiningen: 2.0.0-preview10
  • lein-swank: 1.4.4
  • lein-ritz: 0.6.0

Attachments: Text File tmp.txt    

 Description   

Current Behavior:

When attempting to start a swank server, the clojure compiler throws a CompilerException, and the process terminates.

Expected Behavior:

A swank server is successfully started.

Steps to reproduce (terminal session attached):

1. lein new tmp
2. Edit the project.clj to require clojure version 1.5.0-RC1
4. cd tmp
3. lein swank



 Comments   
Comment by Brian Rowe [ 23/Dec/12 4:58 AM ]

I suppose I should add that I'm using Mac OS X 10.8.2

Comment by Andy Fingerhut [ 24/Dec/12 9:27 AM ]

Have you noticed that swank-clojure [1] is deprecated, i.e. no longer under active development, and the developer recommends that you use nrepl.el [2] instead?

[1] https://github.com/technomancy/swank-clojure
[2] https://github.com/kingtim/nrepl.el

Comment by Andy Fingerhut [ 26/Dec/12 8:55 AM ]

It also appears that someone has created an update to lein-swank (to version 1.4.5) that works with Clojure 1.5.0-RC1:

https://groups.google.com/forum/#!topic/clojure/CAiajyDWJJg

(in particular Toby Crawley's post on Dec 26 2012)

Comment by Brian Rowe [ 08/Feb/13 8:03 PM ]

Yes, this can be closed.

Comment by Andy Fingerhut [ 09/Feb/13 2:20 AM ]

Submitter agrees this issue was resolved by changes in other software outside of Clojure.





[CLJ-1124] for-as Created: 10/Dec/12  Updated: 18/Apr/14  Resolved: 18/Apr/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Yongqian Li Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

A common pattern in programming is building up some data structure step by step:

In Python:

x = {0: 1}
for item in stuff:
    x[item] = item * x.get(item - 1, 0)

etc.

In an imperative for loop this is easy since we have easy access to the "current" data structure being built up.

I propose the addition of a function for-as similar to as-> except the value of the last loop iteration is bound to the name.

So we can write the above as:

(last (for-as [x {0 1}]
        [item stuff]
  (assoc x item (* item (get x (- item 1) 0)))))

An (un-optimized) implementation might be something like:

(defmacro reduce-for [[res init] for-seq-exprs body-expr]
  `(reduce #(%2 %1) ~init
    (for ~for-seq-exprs
      (fn [~res]
        ~body-expr))))

Note: reduce-for does not return a seq, instead it returns the result of the last loop body iteration.



 Comments   
Comment by Kevin Downey [ 18/Apr/14 1:30 AM ]

this is not super clear to me, but it seems like a request for a `for` like macro for reduce.

(reduce (fn [x item] (assoc x item (* item (get x (- item 1) 0)))) {0 1} stuff)
Comment by Alex Miller [ 18/Apr/14 7:18 AM ]

This case seems adequately handled by reduce or loop/recur. I don't think the proposal is compelling enough to consider adding to core.





[CLJ-1115] multi arity into Created: 25/Nov/12  Updated: 25/Mar/15  Resolved: 25/Mar/15

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: Yongqian Li Assignee: Unassigned
Resolution: Declined Votes: 1
Labels: None

Attachments: File multi-arity-into.diff    
Patch: Code and Test

 Description   

Any reason why into isn't multi arity?

(into to & froms) => (reduce into to froms)

(into #{} [3 3 4] [2 1] ["a"]) looks better than (reduce into #{} [[3 3 4] [2 1] ["a"]])



 Comments   
Comment by Timothy Baldridge [ 27/Nov/12 11:25 AM ]

Seems to be a valid enhancement. I can't see any issues we'd have with it. Vetted.

Comment by Timothy Baldridge [ 29/Nov/12 2:06 PM ]

Added patch & test. This patch retains the old performance characteristics of into in the case that there is only one collection argument. For example: (into [] [1 2 3]) .

Since the multi-arity version will be slightly slower, I opted to provide it as a second body instead of unifying both into a single body. If someone has a problem with this, I can rewrite the patch. At least this way, into won't get slower.

Comment by Rich Hickey [ 09/Dec/12 7:39 AM ]

This is a good example of an idea for an enhancement I haven't approved, and thus is not yet vetted.

Comment by Yongqian Li [ 05/Feb/14 1:16 AM ]

What's the plan for this bug?

Comment by Alex Miller [ 05/Feb/14 11:27 AM ]

@Yongqian This ticket is one of several hundred open enhancements right now. It is hard to predict when it will be considered. Voting (or encouraging others to vote) on an issue will raise it's priority. The list at http://dev.clojure.org/display/community/Screening+Tickets indicates how we prioritize triage.

Comment by Andy Fingerhut [ 06/Aug/14 2:12 PM ]

Patch multi-arity-into.diff dated Nov 29 2012 no longer applied cleanly to latest Clojure master due to commits made earlier today. Those changes add another arity to the function clojure.core/into, so the multi-arity generalization of into seems unlikely to be compatible with those changes.

Comment by Nicola Mometto [ 25/Mar/15 3:33 PM ]

This is probably out of the question now that into has an additional arity for transducers

Comment by Alex Miller [ 25/Mar/15 3:41 PM ]

That is true. Also, you can use the cat transducer to do something like this:

(into #{} cat [[3 3 4] [2 1] ["a"]])




[CLJ-1100] Reader literals cannot contain periods Created: 02/Nov/12  Updated: 12/Sep/14  Resolved: 12/Sep/14

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: Release 1.7

Type: Defect Priority: Minor
Reporter: Kevin Lynagh Assignee: Unassigned
Resolution: Declined Votes: 1
Labels: reader

Attachments: Text File CLJ-1100-reader-tags-with-periods.patch     Text File clj-1100-v2.patch    
Patch: Code and Test
Approval: Incomplete

 Description   

The reader tries to read a record instead of a literal if the tag contains periods.

user> (binding [*data-readers* {'foo/bar #'identity}] (read-string "#foo/bar 1"))
1
user> (binding [*data-readers* {'foo/bar.x #'identity}] (read-string "#foo/bar.x 1"))
ClassNotFoundException foo/bar.x  java.lang.Class.forName0 (Class.java:-2)

Summary of reader forms:

Kind Example Constraint Status
Record #user.Foo[1] record class name OK
Class #java.lang.String["abc"] class name OK
Clojure reader tag #uuid "c48d7d6e-f3bb-425a-abc5-44bd014a511d" not a class name, no "/" OK
Library reader tag #my/card "5H" not a class name, has "/" OK
  #my.ns/card "5H" not a class name, has "/" OK
  #my/playing.card "5H" not a class name, has "/" BROKEN - read as record

Note: reader tags should not be allowed to override the record reader.

Cause: In LispReader, CtorReader.invoke() decides between record and tagged literal based on whether the tag has a ".".

Proposed: Change the discriminator in CtorReader by doing more string inspection:

  • If name has a "/" -> readTagged (not a legal class name)
  • If name has no "/" or "." -> readTagged (records must have qualified names)
  • Else -> readRecord (also covers Java classes)

Tradeoffs: Clojure-defined data reader tags must not contain periods. Not possible to read a Java class with no package. Avoids unnecessary class loading/construction for all tags.

Patch: CLJ-1100-v2.patch

Screened by: Alex Miller

Alternatives considered:

Using class checks:

  • Attempt readRecord (also covers Java classes)
  • If failed, attempt readTagged

Tradeoffs: Clojure tags could not override Java/record constructors - not sure that's something we'd ever want to do, but this would cut that off. This alternative may attempt classloading when it would not have before.



 Comments   
Comment by Steve Miner [ 06/Nov/12 9:41 AM ]

The suggested patch (clj-1100-reader-literal-periods.patch) will break reading records when *default-data-reader-fn* is set. Try adding a test like this:

(deftest tags-containing-periods-with-default
      ;; we need a predefined record for this test so we (mis)use clojure.reflect.Field for convenience
      (let [v "#clojure.reflect.Field{:name \"fake\" :type :fake :declaring-class \"Fake\" :flags nil}"]
        (binding [*default-data-reader-fn* nil]
          (is (= (read-string v) #clojure.reflect.Field{:name "fake" :type :fake :declaring-class "Fake" :flags nil})))
        (binding [*default-data-reader-fn* (fn [tag val] (assoc val :meaning 42))]
          (is (= (read-string v) #clojure.reflect.Field{:name "fake" :type :fake :declaring-class "Fake" :flags nil})))))
Comment by Rich Hickey [ 29/Nov/12 9:36 AM ]

The problem assessment is ok, but the resolution approach may not be. What happens should be based not upon what is in data-readers but whether or not the name names a class.

Is the intent here to allow readers to circumvent records? I'm not in favor of that.

Comment by Steve Miner [ 29/Nov/12 4:01 PM ]

New patch following Rich's comments. The decision to read a record is now based on the symbol containing periods and not having a namespace. Otherwise, it is considered a data reader tag. User
defined tags are required to be qualified but they may now have periods in the name. Tests added to show that
data readers cannot override record classes. Note: Clojure-defined data reader tags may be unqualified, but they should not contain periods in order to avoid confusion with record classes.

Comment by Steve Miner [ 29/Nov/12 4:17 PM ]

I deleted my old patch and some comments referring to it to avoid confusion.

In Clojure 1.5 beta 1, # followed by a qualified symbol with a period in the name is considered a record and causes an exception for the missing record class. With the patch, only non-qualified symbols containing periods are considered records. That allows user-defined qualified symbols with periods in their names to be used as data reader tags.

Comment by Andy Fingerhut [ 07/Feb/13 9:05 AM ]

clj-1100-periods-in-data-reader-tags-patch-v2.txt dated Feb 7 2013 is identical to CLJ-1100-periods-in-data-reader-tags.patch dated Nov 29 2012, except it applies cleanly to latest master. The only change appears to be in some white space in the context lines.

Comment by Andy Fingerhut [ 07/Feb/13 12:53 PM ]

I've removed clj-1100-periods-in-data-reader-tags-patch-v2.txt mentioned in the previous comment, because I learned that CLJ-1100-periods-in-data-reader-tags.patch dated Nov 29 2012 applies cleanly to latest master and passes all tests if you use this command to apply it.

% git am --keep-cr -s --ignore-whitespace < CLJ-1100-periods-in-data-reader-tags.patch

I've already updated the JIRA workflow and screening patches wiki pages to mention this --ignore-whitespace option.

Comment by Andy Fingerhut [ 13/Feb/13 11:31 AM ]

Both of the current patches, CLJ-1100-periods-in-data-reader-tags.patch dated Nov 29 2012, and clj-1100-reader-literal-periods.patch dated Nov 6 2012, fail to apply cleanly to latest master (1.5.0-RC15) as of today, although they did last week. Given all of the changes around read / read-string and edn recently, they should probably be evaluated by their authors to see how they should be updated.

Comment by Steve Miner [ 14/Feb/13 12:23 PM ]

I deleted my patch: CLJ-1100-periods-in-data-reader-tags.patch. clj-1100-reader-literal-periods.patch is clearly wrong, but the original author or an administrator has to delete that.

Comment by Kevin Lynagh [ 14/Feb/13 1:28 PM ]

I cannot figure out how to remove my attachment (clj-1100-reader-literal-periods.patch) in JIRA.

Comment by Steve Miner [ 14/Feb/13 1:43 PM ]

Downarrow (popup) menu to the right of the "Attachments" section. Choose "manager attachments".

Comment by Kevin Lynagh [ 14/Feb/13 2:02 PM ]

Great, thanks Steve. Are you going to take another pass at this issue, or should I give it a go?

Comment by Steve Miner [ 14/Feb/13 3:04 PM ]

Kevin, I'm not planning to work on this right now as 1.5 is pretty much done. It might be worthwhile discussing the issue a bit on the dev mailing list before working on a patch, but that's up to you. I think my approach was correct, although now changes would have to be applied to both LispReader and EdnReader.

Comment by Alex Miller [ 09/Apr/14 10:29 AM ]

Updated description based on my understanding.

Comment by Steve Miner [ 22/Apr/14 3:30 PM ]

I will resurrect my old patch and update it for the changes since 1.5.

Comment by Steve Miner [ 28/Apr/14 8:21 AM ]

Added patch to allow reader tags to have periods, but only with a namespace. Added tests to confirm that it works, but does not allow overriding a record name with a data-reader.

Comment by Steve Miner [ 28/Apr/14 8:51 AM ]

The patch implements Alex's alternative 1. It's purely lexical. A tag symbol without a namespace and containing periods is handled as a record (Java class). Otherwise, it's a data-reader tag. Of course, unqualified symbols without periods are still data-reader tags.

IMHO, a Java class without a package is a pathological case which Clojure doesn't need to worry about. This patch follows the convention that Java classes are named by unqualified symbols containing dots.

I did try alternative 2, testing for an actual class, but the implementation was more complicated. Also, it would open the possibility of breaking working code by adding a record or Java class that accidentally collided with an unqualified dotted tag that had previously worked fine. It's better to follow a simple rule that unqualified dotted symbols always refer to classes. Maybe the class doesn't actually exist, but that doesn't mean the symbol might be a data-literal tag.

Comment by Alex Miller [ 13/May/14 4:49 PM ]

Added clj-1100-v2.patch - identical, just removes whitespace to simplify change.

Comment by Rich Hickey [ 29/Aug/14 9:16 AM ]

I think we should disallow this rather than enable it. We don't generally support foo/bar.x

Comment by Nicola Mometto [ 29/Aug/14 9:27 AM ]

I created http://dev.clojure.org/jira/browse/CLJ-1516 with a patch that throws an exception on `(def foo.bar)`

Comment by Alex Miller [ 12/Sep/14 4:45 PM ]

Declined per Rich's comment and replaced with alternative on CLJ-1516





[CLJ-1089] clojure.java.io/copy interprets read count of 0 as eos Created: 22/Oct/12  Updated: 22/Oct/12  Resolved: 22/Oct/12

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Herwig Hochleitner Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None

Attachments: Text File 0001-CLJ-1089-clojure.java.io-do-copy-methods-determine-e.patch    

 Description   

According to the interface http://docs.oracle.com/javase/6/docs/api/java/io/InputStream.html#read()
InputStream.read() family of methods return -1 when the end of stream is reached.

do-copy methods currently use a test: (pos? size) to determine whether eos is reached. This mostly works, but the specification is pretty clear in that InputStream implementations are allowed to return reads of zero bytes before returning more bytes.

##EDIT changed title of ticket from "clojure.java.io/copy should test for -1 instead of 0 for end of stream"



 Comments   
Comment by Herwig Hochleitner [ 22/Oct/12 3:40 PM ]

Attached patch changes do-copy methods to test for -1

Comment by Andy Fingerhut [ 22/Oct/12 4:56 PM ]

Herwig, can you elaborate on "the specification is pretty clear in that InputStream implementations are allowed to return reads of zero bytes before returning more bytes"?

I ask because in the very InputStream documentation page you link to, it seems to explicitly say the opposite of what you claim: "If no byte is available because the stream is at the end of the file, the value -1 is returned; otherwise, at least one byte is read and stored into b."

Comment by Herwig Hochleitner [ 22/Oct/12 4:57 PM ]

I reread the spec for InputStream.read and it clearly says

"If no byte is available because the stream is at the end of the file, the value -1 is returned; otherwise, at least one byte is read and stored into b."

The reason I originally thought of this as an issue was a misbehaving ServletInputStream from Jetty.

I closed the issue as declined. Sorry for the noise!





[CLJ-1067] Fix error message inconsistencies in Symbol and Keyword Created: 14/Sep/12  Updated: 01/Mar/13  Resolved: 17/Sep/12

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: Christoffer Sawicki Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None

Attachments: Text File Make-Keyword-extend-AFn-just-like-Symbol.patch    

 Description   

1. There are some ugly and unnecessary – but harmless – inconsistencies between Symbol and Keyword:

(.run 'foo);    => ArityException Wrong number of args (0) passed to: Symbol  clojure.lang.AFn.throwArity (AFn.java:437)
(.run :foo);    => UnsupportedOperationException   clojure.lang.Keyword.run (Keyword.java:97)
(.call 'foo);   => ArityException Wrong number of args (0) passed to: Symbol  clojure.lang.AFn.throwArity (AFn.java:437)
(.call :foo);   => IllegalArgumentException Wrong number of args passed to keyword: :foo  clojure.lang.Keyword.throwArity (Keyword.java:88)
(.invoke 'foo); => ArityException Wrong number of args (0) passed to: Symbol  clojure.lang.AFn.throwArity (AFn.java:437)
(.invoke :foo); => IllegalArgumentException Wrong number of args passed to keyword: :foo  clojure.lang.Keyword.throwArity (Keyword.java:88)

2. Keyword.java contains a lot of code that has already been factored out to AFn.java.

I propose that Keyword is modified to extend AFn to resolve the above issues.



 Comments   
Comment by Stuart Halloway [ 17/Sep/12 7:03 AM ]

At first glance, it appears that there could be some code sharing here. But the attached patch changes the semantics of run, which is a non-starter.

Comment by Christoffer Sawicki [ 17/Sep/12 7:19 AM ]

The only thing that changes is the type of thrown exception.

Current call tree:

Keyword.run() -> throw new UnsupportedOperationException()

Call tree with patch applied:

Keyword.run() -> AFn.run() -> AFn.invoke() -> AFn.throwArity(0) -> throw new ArityException(...)

(I.e. Keyword.run() always throws an exception, with and without my patch.)





[CLJ-1054] Syntax quoted form produces a sequence, not a list Created: 31/Aug/12  Updated: 18/Sep/12  Resolved: 18/Sep/12

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.4
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Andrei Zhlobich Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

Syntax quote returns clojure.lang.Cons instead of IPersistenList.
But simple quote always returns list.

(list? '(1))     => true
(list? '(1 2 3)) => true
(list? `(1))     => true
(list? `(1 2 3)) => false


 Comments   
Comment by Stuart Halloway [ 18/Sep/12 6:42 AM ]

It is unusual in Clojure to expect/rely on concrete list? checks, particularly given the prevalence of seq?

If the behavior documented here is causing problems, please discuss use case on mailing list, and then we can open a ticket.





[CLJ-1051] Recursive function raises "call unbound fn" exception Created: 27/Aug/12  Updated: 01/Mar/13  Resolved: 09/Nov/12

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.4
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Armando Blancas Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

OSX


Attachments: File expr.clj    

 Description   

I've tried to reduce the code to the minimum that will reproduce the problem. This is a parser combinator library that uses the "list of successes" method. The test is a simple expression for adding one-digit integers with support for parens; sample input might be "1+(2+3)+4".

Having declared the parsers (see attached file), the expression parser is this:

(declare expr)

(def factor
  (choice (between (match \() (match \)) expr)
	  integer))

(def expr
  (bind factor
       (fn [t]
	 (choice (bind (match \+) (fn [_] (bind expr (fn [e] (result (+ t e))))))
	         (result t)))))

With the above, I get this error:

Clojure 1.4.0
user=> (load-file "expr.clj")
#'user/expr
user=> (run expr "(3)")      
IllegalStateException Attempting to call unbound fn: #'user/expr  clojure.lang.Var$Unbound.throwArity (Var.java:43)

I can, however, avoid this error if I code the (factor) function by expanding the code of the parser (between):

(declare expr)

(def factor*
  (choice (bind (match \() (fn [_]
          (bind expr       (fn [e]
	  (bind (match \)) (fn [_] (result e)))))))
	  integer))

(def expr
  (bind factor*
       (fn [t]
	 (choice (bind (match \+) (fn [_] (bind expr (fn [e] (result (+ t e))))))
	         (result t)))))

And now I can do:

Clojure 1.4.0
user=> (load-file "expr.clj")
#'user/expr
user=> (run expr "(3)")      
3
user=> (run expr "1+(2+3)+(4+5)")
15

The ability to reuse parser and add conveniences like (between) is key for this style of parsing.



 Comments   
Comment by Kevin Downey [ 27/Aug/12 6:03 PM ]

this is not a bug in clojure.

declare creates an unbound var then your def tries to use the value of the var before you have given it a value.

declare does not let you use a value of a var before you have given it one (via def or whatever).

Comment by Kevin Downey [ 27/Aug/12 6:05 PM ]

meta comment:
I would close this as "Declined", but I am not sure if that is kosher for me to do.

Comment by Armando Blancas [ 27/Aug/12 10:28 PM ]

Thanks for looking into this.

Just want to point out that as far as the declare and the use of expr as a forward reference, the second scenario I've presented (with factor*) uses (declare) the same way, yet it works: the var "expr" in (factor*) ends up pointing to the root value set later, but before it runs.

Seems to me similar to this case, where f is defined in terms of itself and it works fine, having the var "f" obtained its root binding after the def form runs:

user=> (def f (fn [n] (if (< n 1) 1 (* n (f (- n 1))))))
#'user/f
user=> (f 6)
720

Given that I've got a usage that works, I would suspect that there's something about the first case that prevents the root binding to be visible to the declared var.

Comment by Kevin Downey [ 28/Aug/12 3:25 AM ]

the formatting of the second case makes it hard to read, but it looks like expr is referenced inside a function, so the var #'expr will not be derefed until the function is run.

Comment by Armando Blancas [ 28/Aug/12 12:32 PM ]

Though the difference isn't quite apparent to me, I kind of grasp the idea that the var may be in one case deref'ed earlier in one case than the other because calls to (bind) are eager and in the case of the additional call to (between) the var is inside the function. I'll ask the board for advice on this and this ticket can be closed. Thanks.

Comment by Stuart Sierra [ 09/Nov/12 8:51 AM ]

Closed based on discussion in comments.





[CLJ-1050] Remove a lock in the common case of deref of delay Created: 26/Aug/12  Updated: 18/Sep/12  Resolved: 18/Sep/12

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.4
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: Nicolas Oury Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: enhancement, patch, performance

Attachments: Text File 0001-No-lock-in-the-common-path-for-delays.patch    

 Description   

Currently, when deref is called in Delay.java, a lock on the Delay is always acquired.
This is wasteful as most of the time you just want to read the val.

The attached patch changes this behaviour to the following:

  • val is initialised to a known secret value. (During its constructor so it is visible from any thread).
  • When deref is called, val is checked to the known secret value.
  • If it is not the secret value, then it has to be the value computed by the function and we return it.
  • If it is the secret value, then we lock this object and revert to the current behaviour.

This is faster than what is done currently and can be very much faster if there is contention on the delay.



 Comments   
Comment by Nicolas Oury [ 27/Aug/12 2:37 AM ]

Please close and reject. The patch is not working if val has non final fields.





[CLJ-1049] Make reducer/folder support reduce-kv Created: 22/Aug/12  Updated: 17/Aug/13  Resolved: 17/Aug/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Tom Jack Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None

Attachments: File 0001-reduce-kv-transformations.diff    
Patch: Code

 Description   

Currently, although rfn makes an effort to support reduce-kv, it is wasted effort since the return values of reducer and folder don't satisfy IKVReduce.

I have a working patch for this, it's quite small. I have printed a CA but not sent it, so I won't reveal the patch yet...

This also applies to ClojureScript.



 Comments   
Comment by Tom Jack [ 15/Sep/12 12:47 AM ]

Hmm.. it's not quite as simple as I thought. My first patch simply had reducer/folder implement IKVReduce with `(clojure.core.protocols/kv-reduce coll (xf f1) init)`, but for map and mapcat, this results in strange behavior (reduce-kv reducefs being called with only 2 args).

Patch 0001 includes modifications to map and mapcat so that the reduce-kv reducef will always be called with 3 args. The previous implementation of mapcat also had the converse problem: during non-kv reduce, if the mapcat fn returned a map, the reducef would be called with 3 args since maps reduce with reduce-kv.

The patch gives behavior like:

user> (->> {1 {2 3 4 5} 6 {7 8 9 10}}
        (r/mapcat #(r/map + %2))
        (reduce-kv #(conj %1 [%2 %3]) []))
[[2 5] [4 9] [7 15] [9 19]]
user> (->> [{2 3 4 5} {7 8 9 10}]
        (r/mapcat identity)
        (r/reduce conj []))
[[2 3] [4 5] [7 8] [9 10]]
Comment by Tom Jack [ 23/Sep/12 8:34 PM ]

Would like to discuss these changes (and auto-kv for maps) on clojure-dev, but my membership is still pending. My CA has been received. Anyone know who to contact to get my membership approved?

Comment by Andy Fingerhut [ 14/Aug/13 7:47 PM ]

Tom, your patch 0001-reduce-kv-transformations.diff dated Sep 14 2012 no longer applies cleanly to the latest master, because patch lazy-rmapcat2.diff for ticket CLJ-1160 was committed to Clojure master on Aug 14 2013, and they both modify some of the same code. I haven't tried to determine whether their changes are harmonious with each other or not. I'd recommend taking a look.

Comment by Tom Jack [ 14/Aug/13 8:17 PM ]

I later realized that there are more issues with my goal (of supporting reduce-kv for the reducer combinators). I think I worked out the way I'd want things to be, but it would've involve backwards-incompatible changes to the way maps reduce. Short of that, the best thing I can think to do is probably just to not support reduce-kv at all (coincidentally, this is exactly what clojure.core.reducers does! . So as far as I'm concerned this issue is resolved. My patch certainly should not be applied, at least...

Comment by Alex Miller [ 17/Aug/13 3:16 PM ]

Closed per comment





[CLJ-1043] Unordered literals does not preserve left-to-right evaluation of arguments Created: 16/Aug/12  Updated: 25/Mar/15  Resolved: 25/Mar/15

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.4
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Brandon Bloom Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

Given: (defn f [x] (println x) x)

#{(f 2) (f 1)}

Prints:

1
2

But expected would be:

2
1

This issue is related to CLJS-288



 Comments   
Comment by Andy Fingerhut [ 23/Sep/12 6:01 PM ]

I have the same question as David Nolen for CLJS-288: Is this a bug, or just behavior you didn't expect?

It seems that vectors preserve the order of evaluation, so if you really want to control evaluation order you could use something like (set [(f 2) (f 1)]) or (set (map f [2 1])).

Comment by Brandon Bloom [ 23/Sep/12 7:38 PM ]

I'd consider the expected default behavior of any syntax or macro to evaluate each sub-form once each, from left to right. Conditional, repeated, or out-of-order evaluation should be documented as deviations from that norm. If you buy that, then this is either a code or a documentation bug. My vote is for code bug.

Comment by Nicola Mometto [ 25/Mar/15 5:05 PM ]

I don't think it's possible to preserve left-to-right evaluation of args on unordered literals, the original order will be lost during read-time, the compiler has no way to know about it.

Comment by Alex Miller [ 25/Mar/15 5:40 PM ]

Sets are unordered.

Comment by Brandon Bloom [ 25/Mar/15 8:22 PM ]

Sometime over the past two years, I've come around to the perspective that this is expected behavior. However, I still maintain that this should be documented somewhere!

On this page: http://clojure.org/evaluation

This paragraph:

Vectors, Sets and Maps yield vectors and (hash) sets and maps whose contents are the evaluated values of the objects they contain. The same is true of metadata maps. If the vector or map has metadata, the evaluated metadata map will become the metadata of the resulting value.

I'd propose inserting a sentence like:

Contents are evaluated sequentially in vectors, but in an unspecified order for sets and maps.

Comment by Alex Miller [ 25/Mar/15 9:11 PM ]

I added a comment to that page.

Comment by Brandon Bloom [ 25/Mar/15 9:19 PM ]

Awesome, thanks!

Small typo: "Vectors elements" should be "Vector elements".





[CLJ-1042] [PATCH] Allow negative substring indices for (subs) Created: 14/Aug/12  Updated: 19/Sep/12  Resolved: 17/Sep/12

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Ian Eure Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: enhancement, patch

Attachments: Text File clj-1042-negative-indices-patch3.txt     Text File negative-subs.patch    
Patch: Code and Test

 Description   

This adds Python-style negative string indices for (subs), e.g.:

(subs "foo bar" -3) ;; -> "bar"



 Comments   
Comment by Andy Fingerhut [ 16/Aug/12 7:17 PM ]

Ian, thanks for the patch. It is Rich Hickey's policy only to consider applying patches to Clojure from those who have signed a Clojure contributor agreement: http://clojure.org/contributing

Were you interested in doing so, or perhaps it is already in progress?

Comment by Ian Eure [ 20/Aug/12 11:44 AM ]

I wasn't aware that this was necessary. I'm mailing the form in.

Comment by Andy Fingerhut [ 27/Aug/12 7:56 PM ]

Patch clj-1042-negative-subs-patch2.txt dated Aug 27 2012 is identical to Ian Eure's negative-subs.patch, except it is in the desired git format.

Ian, for future reference on creating patches in the desired format, see the instructions under the heading "Development" on this page: http://dev.clojure.org/display/design/JIRA+workflow

Comment by Ian Eure [ 28/Aug/12 11:47 AM ]

Thanks, will do.

Comment by Steve Miner [ 04/Sep/12 3:53 PM ]

If Clojure decides to support Python-style negative indices, you should also consider adding support to subvec.

Comment by Ian Eure [ 06/Sep/12 12:17 PM ]

Patch extended to support negative indices on (subvec) as well.

Comment by Adrian Bendel [ 07/Sep/12 8:01 AM ]

The arg to rindex should probably be tagged with ^clojure.lang.Counted instead of ^String now.

Comment by Steve Miner [ 07/Sep/12 1:31 PM ]

Regarding the previous comment, String is a Java class so it isn't a clojure.lang.Counted. Is the type hint necessary? Maybe it should be on the call rather than the defn.

Ignoring the type hinting, I'll suggest a slightly simpler way to implement the rindex logic:

(defn rindex [coll i]
(if (neg? i) (+ (count coll) i) i))

In any case, I'm not sure rindex should be public even if you want the subs and subvec enhancements. Someone needs to make the case for adding a new function to core.

The Pythonic negative index is a debatable feature since it's pretty easy to implement for yourself if you want it.

Comment by Adrian Bendel [ 07/Sep/12 11:05 PM ]

Sorry, the type hint on rindex args isn't necessary at all. Just looked up in the source, calling count should never be reflective, since (count ..) emits calls to clojure.lang.RT/count.

Your solution looks good.

Comment by Stuart Halloway [ 17/Sep/12 7:07 AM ]

Negative indices were considered and rejected a long time ago. (I am merely conveying information--I have no strong opinion on this one.)

Comment by Andy Fingerhut [ 17/Sep/12 12:07 PM ]

Note: If some people really like negative index behavior as in Perl or Python, it is straightforward to create a library of functions in a different namespace, perhaps with different names, that can do it. Perhaps a "pythonisms" library?

Comment by Ian Eure [ 18/Sep/12 12:31 PM ]

Would this be accepted as part of clojure.string instead? I considered putting it there, but thought it would be confusing to have multiple substring functions in different namespaces.

This is very helpful in practice, and I'd really like to see at least the (subs) stuff in Clojure.

Comment by Andy Fingerhut [ 18/Sep/12 2:52 PM ]

Disclaimer: I'm no Clojure/core member, so can't speak authoritatively on whether something would or would not be accepted into clojure.string.

However, given that clojure.string is distributed with clojure.core, my guess is it would not be accepted. You'd be able to get things like this out for you and others as a separate library distributed on Clojars. That would also make it easy to include other Python-like things that you don't find in Clojure already.

Comment by Ian Eure [ 18/Sep/12 4:02 PM ]

This isn't about "python-like things," this is about a useful feature. Lots of languages support this: Perl, PHP, Ruby, Python, JavaScript, to name a few. Are you really suggesting that I should create a whole package for a version of a function in clojure.core with slightly different semantics? That's insane.

Anyway, I'm done wasting my time trying to navigate this hopelessly broken process. Maybe it would have been accepted if I included yet another way to interoperate with Java types.

Comment by Michael Klishin [ 18/Sep/12 5:09 PM ]

Stuart, do you remember why specifically negative indexes were rejected? Developing a separate library for a minor improvement to an existing function sounds unreasonable.

Comment by Carlos Cunha [ 18/Sep/12 5:10 PM ]

some explanation about this topic was given by Rich Hickey himself here: http://news.ycombinator.com/item?id=2053908

citation:
"...Yes, there is a backlog from when it was just me, and it will take a while to whittle down. We have finite resources and have to prioritize. I can assure you we have more important things to concentrate on than your negative index substring enhancement, and are doing so. You'll just have to be patient. Or, if you insist, I'll just reject it now because a) IMO it's goofy, b) you can make your own function that works that way c) we don't get a free ride from j.l.String, d) it begs the question of negative indices elsewhere..."

i've been following this thread hoping this feature would be included. but whatever the reason was for the rejection, i'm sure it was thoughtful. great thanks for this wonderful language, and thanks Ian Eure for his effort.

Comment by Steve Miner [ 18/Sep/12 5:25 PM ]

That HN link eventually leads back to CLJ-688 which was rejected.

Comment by Stuart Halloway [ 19/Sep/12 12:03 PM ]

Michael: A proposal for negative indexes would need to be systematic in considering implications for all functions that have index arguments.

Ian: Clojure is driven by design, not incremental piling of features.

All: clojure.string is incomplete in more important and fundamental ways than negative indexes. This sucks now, and will suck worse as more code is written in different dialects. I find myself wishing string was a contrib, so we could iterate faster.

Comment by Andy Fingerhut [ 19/Sep/12 1:34 PM ]

Stuart: Any specific proposals for how you'd like to see clojure.string improve? If it can be made a contrib, that would be cool, but understood if that would be considered too breaking of a change. Even if it isn't made a contrib, having tickets for improvement ideas you are willing to see means patches might get written, and they'll get in some time.





[CLJ-1036] hash is inconsistent with = for some BigInteger and floating point values Created: 02/Aug/12  Updated: 23/Jan/15  Resolved: 05/Sep/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.4, Release 1.5
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Paul Stadig Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None

Attachments: Text File clj-1036-hasheq-for-biginteger-patch-v4.txt    
Patch: Code and Test
Approval: Triaged

 Description   

hash is documented to be consistent with = but Util/hasheq returns different hash values for some pairs of numbers that are =

user> (apply = [-1 -1N (biginteger -1)])
true
user> (map hash [-1 -1N (biginteger -1)])
(0 0 -1)

user> (apply = [(Float. 1e9) (Double. 1e9)])
true
user> (map hash [(Float. 1e9) (Double. 1e9)])
(1315859240 1104006501)

Consequences include incorrect behavior for hash-maps containing keys that are =, but have different hash values:

;; Incorrect return value with multiple keys = to each other
user> (assoc (hash-map -1N :should-be-replaced) (biginteger -1) :new-val)
{-1N :should-be-replaced, -1 :new-val}

;; array-map gives correct value, since it uses =, not hash
user> (assoc (array-map -1N :should-be-replaced) (biginteger -1) :new-val)
{-1N :new-val}

Patch: clj-1036-hasheq-for-biginteger-patch-v4.txt

Approach:

The only BigInteger values that have inconsistent hash values should be those in the range of a long. BigInteger and BigInt values outside the range of a long already both return BigInteger.hashCode().

All integer values will return consistent hash codes if we add a new case to Numbers.hasheq(Number) for BigIntegers that lie in the range of a long, returning the same hash that such a long value does.

For floating point values, the patch makes their hashes consistent by converting floats to doubles and then hashing.

One alternate approach would be to convert all double values to floats and hash float values only. However, this throws away half of the bits of the double value before hashing, leading to many undesirable hash collisions between different double values.



 Comments   
Comment by Paul Stadig [ 02/Aug/12 9:55 AM ]

Also, the biginteger function has metadata saying that it has been added since 1.0, but it was actually added in 1.3. The bigint function has metadata saying that it has been added since 1.3, but it has been added since 1.0.

I think during the work to implement BigInt someone renamed the existing bigint function (which used to return a BigInteger) to biginteger, and the metadata got carried with it, then a new bigint function was added with :since 1.3 metadata even though that function name has existed since 1.0.

Comment by Andy Fingerhut [ 26/Sep/12 11:59 AM ]

clj-1036-hasheq-for-biginteger-patch-v1.txt dated Sep 26 2012 makes BigInteger's return equal hash values for values considered equal by =.

It does the same for Float and Double types, which before returned different hash values for values considered equal by =

I went ahead and changed the :added metadata on bigint and biginteger, although I can see that without my change, the person who did that may have meant for the :added to go with the behavior of the function, not with the name. Paul's suggested change that I have in the patch is for the :added metadata to go with the name, not the function behavior. It is easy to remove that part of the patch if that change is not desired.

Comment by Rich Hickey [ 13/Nov/12 3:29 PM ]

You can't just consider only the lower long of bigints. Also, what's the rationale for the float stuff?

Comment by Andy Fingerhut [ 13/Nov/12 9:44 PM ]

clj-1036-hasheq-for-biginteger-patch-v2.txt dated Nov 13 2012 is identical to clj-1036-hasheq-for-biginteger-patch-v1.txt except that it addresses Rich's comment that for BigInt's and BigInteger values that don't fit in a long, their entire value must be hashed.

The rationale for the changes to hasheq for Float and Double types is the same as the rationale for the change for BigInteger: without that change, Float and Double types that are = can have different hasheq values.

Comment by Paul Stadig [ 14/Nov/12 5:18 AM ]

Although you are correct that Double and Float are =, but have different hashes:

user=> (apply = [(Double. -1.0) (Float. -1.0)])
true
user=> (map hash [(Double. -1.0) (Float. -1.0)])
(-1074790400 -1082130432)

I could not get the same errant behavior out of PHM:

user=> (assoc clojure.lang.PersistentHashMap/EMPTY (Float. -1.0) :oops! (Double. -1.0) :one)
{-1.0 :one}

I haven't taken the time to investigate exactly what is happening here, but either way I think this ticket is very specifically about BigInteger and the Float/Double issue could be explored in another ticket.

Comment by Andy Fingerhut [ 14/Nov/12 10:08 AM ]

I can open another ticket for the Float/Double issue if that is what people would prefer.

I think what is happening in the test case you give, Paul, is that the hash values for (Float. -1.0) and (Double. -1.0) happen to be the same in their least significant 20 bits, and PHM isn't using the upper bits where the hash values differ.

Clojure 1.5.0-beta without patch:
user=> (map #(format "%x" %) (map hash [(Float. -1.0) (Double. -1.0)]))
("bf800000" "bff00000")

There are other Float/Double values where this lucky accident doesn't happen, e.g.

Clojure 1.5.0-beta1 without patch:

user=> (= (Float. 1e9) (Double. 1e9))
true
user=> (map hash [(Float. 1e9) (Double. 1e9)])
(1315859240 1104006501)
user=> (assoc clojure.lang.PersistentHashMap/EMPTY (Float. 1e9) :oops! (Double. 1e9) :one)

{1.0E9 :one, 1.0E9 :oops!}

With 1.5.0-beta1 plus patch clj-1036-hasheq-for-biginteger-patch-v2.txt:

user=> (= (Float. 1e9) (Double. 1e9))
true
user=> (map hash [(Float. 1e9) (Double. 1e9)])
(1315859240 1315859240)
user=> (assoc clojure.lang.PersistentHashMap/EMPTY (Float. 1e9) :oops! (Double. 1e9) :one)

{1.0E9 :one}
Comment by Andy Fingerhut [ 01/Jan/13 11:30 AM ]

Presumptuously changing status from Not Approved to Vetted, since patch clj-1036-hasheq-for-biginteger-patch-v2.txt should address the reasons that Rich marked the previous patch as Not Approved. Changing it to Vetted on the assumption that if Stuart Halloway marked the previous patch as Screened, the ticket itself is good enough to be Vetted.

Comment by Rich Hickey [ 12/Apr/13 8:48 AM ]

Patches and tickets need to be better than this. Talks about BigInteger, changes hash for doubles. Lists problem but not approach, need to trawl through comments and code to see what's going on, etc.

Comment by Andy Fingerhut [ 07/Aug/13 6:49 PM ]

Updated summary to mention floating point types, and completely revamped description so that it should be self-contained, without having to read any comments.

Comment by Andy Fingerhut [ 08/Aug/13 3:51 PM ]

Add new patch clj-1036-hasheq-for-biginteger-patch-v4.txt dated Aug 8 2013 that handles floating point hashes better. Description will be updated to match.

Comment by Rich Hickey [ 05/Sep/13 8:27 AM ]

It is out of scope for Clojure to fix this for Java types Float/Double/BigInteger

Comment by Andy Fingerhut [ 29/Jan/14 3:05 PM ]

It seems to have become in scope to fix this for Java type BigInteger with this commit: https://github.com/clojure/clojure/commit/96e72517615cd2ccdb4fdbbeb6ffba5ad99dbdac

Comment by Michael Gardner [ 23/Jan/15 8:58 AM ]

What about making = always return false for float/double comparisons? It would technically be a breaking change, but only for those who are doing a Bad Thing that doesn't reliably work in the first place.

Comment by Alex Miller [ 23/Jan/15 9:17 AM ]

I think it would be best to work this on a new ticket.





[CLJ-1035] Remove the need to use ":import" of a record Created: 29/Jul/12  Updated: 10/Aug/12  Resolved: 10/Aug/12

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.4
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Warren Lynn Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

Right now if I need to use a record defined in another name space, I need to do this:

(ns myproj.test.xyz
(:use [myproj.xyz])
(:import [myproj.xyz MyRecord])

Hope we can remove the need of ":import" clause.



 Comments   
Comment by Stuart Halloway [ 10/Aug/12 12:44 PM ]

Hi Warren,

Importing a Java class and using a record are two logically distinct ideas, hence two separate steps in your code. Note that using a namespace makes the defrecord constructor fns (e.g. >MyRecord and map>MyRecord) available without a second step.

Please discuss ideas on the mailing list before using JIRA to make suggestions.

Cheers

Comment by Warren Lynn [ 10/Aug/12 2:19 PM ]

Thanks for giving it a thought.

I think it is conceptually simple/consistent to say "if you use a namespace, then all the public symbols in that namespace is available without namespace qualification". It is unnecessary to remind people "Hey, record is an actually a Java class so the rules do not apply". I think it is the right choice for Clojure to integrate closely with the host language, but it is not the objective to expose the host details when not needed. If you say "this is a compromise due to some implementation consideration", then I can understand. But I disagree with the rationale you mentioned.





[CLJ-1028] (compile) crashes with NullPointerException if public function 'load' is defined Created: 20/Jul/12  Updated: 20/Jul/12  Resolved: 20/Jul/12

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.4
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Ben Kelly Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: Compiler, bug
Environment:

Linux, OpenJDK 1.6.0 64bit


Attachments: File stack-trace    

 Description   

When performing AOT compilation, if the namespace being compiled or one of the namespaces :required by it defines a public function named 'load', the compiler will crash with a NullPointerException.

The following code demonstrates this:

(ns ca.ancilla.kessler.core (:gen-class)) (defn load [x] x) (defn -main [& args] 0)

When run directly, with 'clojure -m ca.ancilla.kessler.core' or 'clojure ca/ancilla/kessler/core.clj', it runs as expected. When loaded with 'clojure -i' and (compile)d, however, or when automatically compiled by 'lein run', it results in a NullPointerException (the complete stack trace is attached).

This occurs whether or not 'load' or actually called. It does not, however, occur if 'load' is private.



 Comments   
Comment by Ben Kelly [ 20/Jul/12 12:43 PM ]

If you add (:refer-clojure :exclude [load]) to the (ns), it works fine:

(ns ca.ancilla.kessler.core (:refer-clojure :exclude [load]) (:gen-class))
(defn load [x] x)
(defn -main [& args] 0)

Thanks to llasram on IRC for discovering this.

Comment by Stuart Halloway [ 20/Jul/12 4:35 PM ]

You should not replace functions in clojure.core. This is left legal (with a loud CONSOLE warning) for compatibility, but programs that do it are in error.

Comment by Ben Kelly [ 20/Jul/12 10:06 PM ]

So, just to make sure that I have this right, then...

If I want to create a namespace with a public function that shares a name with a function in clojure.core, the only supported way of doing this is to (:refer-clojure :exclude [list of all such functions])?

If so, it would be nice if the warning were replaced with an error, rather than having the compiler emit an error and then crash.





[CLJ-1025] Enable support for \x.. escaped characters. Created: 13/Jul/12  Updated: 19/Oct/12  Resolved: 19/Oct/12

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.4
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Dave Sann Assignee: Unassigned
Resolution: Declined Votes: 1
Labels: None
Environment:

All


Attachments: Text File 0001-adding-support-for-x-escape-characters.patch    
Patch: Code and Test

 Description   

see: https://groups.google.com/d/topic/clojure/Kl3WVtEE3FY/discussion

\x.. characters (which are the same as \u00.. characters) are produced by some systems. in particular clojurescript

Inability to read these characters hinders data interchange

After a quick look, I believe this capability can be easily introduced by adding a case to this
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LispReader.java#L445 function.
Mirroring 'u' case and reading only 2 chars.



 Comments   
Comment by Andy Fingerhut [ 19/Jul/12 11:46 AM ]

Thanks for the patch, Dave. It is Rich Hickey's policy only to include code in Clojure written by those who have signed a Contributor Agreement (CA). See here for more details: http://clojure.org/contributing Have you signed one, or were considering it?

Comment by Andy Fingerhut [ 19/Jul/12 3:57 PM ]

Can someone find some documentation or spec somewhere that defines this \x.. format?

It is definitely different than the \x{...} syntax that exists in Perl, which permits one to insert an arbitrary Unicode character code point into a string (note: even supplementary ones that don't fit into a single UTF-16 code unit, as Java's and Clojure's \u.... is restricted to). http://perldoc.perl.org/perlunicode.html#Effects-of-Character-Semantics

Comment by Dave Sann [ 22/Jul/12 2:19 AM ]

http://es5.github.com/x7.html#x7.8.4

Comment by Dave Sann [ 31/Jul/12 4:35 AM ]

I am happy to sign the CA in principle. Just need to read and understand any implications for me.

Comment by Dave Sann [ 27/Aug/12 3:31 AM ]

CA will be with you shortly.

Comment by Dave Sann [ 16/Oct/12 3:11 AM ]

Can this go into 1.5?

Comment by Chas Emerick [ 19/Oct/12 8:10 AM ]

I'm hitting this now as well. But, adding support for JavaScript's flavour of \x.. escapes to the Clojure reader makes no sense to me. If escapes are to be used, then the \u.... format seems preferable (it supersets \x..).

However, all of the readers in play (Clojure reader, ClojureScript reader, edn) all play nice with Unicode, so there's no reason to be escaping anything except for \t, \n, and so on.

It looks like tweaking cljs' string implementations of IPrintWithWriter and IPrintable so that only those characters are escaped would be fairly easy. Right now, they're using goog.string.escape, which "encloses a string in double quotes and escapes characters so that the string is a valid JS string"; whatever escaping is appropriate for a "valid JavaScript string" seems irrelevant to what e.g. pr-str should produce.

I propose closing this ticket and moving the party to CLJS.

Comment by Stuart Halloway [ 19/Oct/12 1:55 PM ]

Following Chas's lead and closing this one. \x doesn't appear in the JSON spec, and a quick search of StackOverflow shows people stumbling over it from a bunch of other language platforms. I think we should root it out of ClojureScript.

Comment by Chas Emerick [ 19/Oct/12 1:58 PM ]

Great, I'll open a CLJS ticket with a patch tonight or tomorrow.

Comment by Ivan Kozik [ 19/Oct/12 2:39 PM ]

Re: "no reason to be escaping anything except for \t, \n": sometimes it is difficult or impossible to transmit all of Unicode (e.g. sending non-Character codepoints through XDomainRequest, or sending U+0000/U+FFFE/U+FFFF through many XHR implementations), so it might be nice to have an ASCII-only printing mode. Probably for another ticket, though.

Comment by Chas Emerick [ 19/Oct/12 7:59 PM ]

Here's the new ticket: http://dev.clojure.org/jira/browse/CLJS-400

@Ivan: I agree that options in this area would be good. There are a lot of edge cases where the defaults aren't right (e.g. I think escaping all nonprintables is a no-brainer for readably-printed strings).

I suspect planning out such details should probably happen [here](http://dev.clojure.org/pages/viewpage.action?pageId=4063586) or [here](https://github.com/edn-format/edn/issues).





[CLJ-1024] Varargs protococol impls can be defined but not called Created: 10/Jul/12  Updated: 14/Feb/13  Resolved: 13/Feb/13

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.4
Fix Version/s: Release 1.5

Type: Enhancement Priority: Minor
Reporter: Víctor M. Valenzuela Assignee: Stuart Halloway
Resolution: Declined Votes: 1
Labels: patch

Attachments: Text File 0001-CLJ-1024-Check-for-invalid-varags-destrucuring-uses.patch    
Patch: Code

 Description   

The compiler accepts this:

(deftype foo []
clojure.lang.IFn
(invoke [this & xs]))

However calling ((foo.) :bar) will throw an AbstractMethodError. Wouldn't some checking be desirable?



 Comments   
Comment by Tassilo Horn [ 11/Jul/12 1:20 AM ]

First of all, clojure.lang.IFn is no protocol but an interface. And it does not declare a

  public Object invoke(Object... obs)

method. It has an `invoke` method with 20 Object parameters followed by an Object... parameter, but to give an implementation for that, you have to specify every parameter separately, and the last Object... arg is just a normal argument that must be an Object[]. That's because Java-varags Type... parameters are just Java syntax sugar, but in the byte-code its simply a Type-array.

What your example does is provide an `invoke` implementation for the 2-args version, where the first parameter happens to be named `&`, which has no special meaning here. Take that example:

(deftype MyFoo []
  clojure.lang.IFn
  (invoke [this & xs]
    [& xs]))

((MyFoo.) 1 2)
=> [1 2]

But you are right in that `deftype`, `defrecord`, `defprotocol`, and `definferface` probably should error if user's seem to try to use varargs or destructuring.

Comment by Víctor M. Valenzuela [ 11/Jul/12 1:55 AM ]

Cheers for a most clarifying response.

The fact that the meaning of & gets 'subverted' makes the issue only (slightly) worse, in my opinion.

Just for the record, destructuring seems to work, at least for interface impls.

Comment by Tassilo Horn [ 11/Jul/12 2:42 AM ]

> The fact that the meaning of & gets 'subverted' makes the issue only (slightly) worse, in my opinion.

I agree. I'll attach a patch which checks for those invalid usages soon.

> Just for the record, destructuring seems to work, at least for interface impls.

Could you please provide a complete example demonstrating your statement?

I'm rather sure that varargs and destructuring don't work for any of defprotocol, definterface, deftype, defrecord, and reify. But you can use varargs and destructuring when providing dynamic implementations via `extend` (or `extend-protocol`, `extend-type`), because those impls are real functions in contrast to methods.

Comment by Tassilo Horn [ 11/Jul/12 2:43 AM ]

I attached a patch. Here's the commit message:

Check for invalid varags/destrucuring uses.

Protocol, interface method declarations and implementations don't allow for
varags and destructuring support. Currently, for example

(defprotocol FooBar
(foo [this & more]))

compiles just fine, and & is interpreted as a usual argument that happens to be
named & without special meaning. But clearly, the user wanted to specify a
varags parameter here. The same applies to definterface.

Similarly, providing method implementations via defrecord, deftype, and reify
don't allow for destructuring and varags (but dynamic extenions via extend do).

So this patch makes defprotocol, definterface, defrecord, deftype, and reify
throw an IllegalArgumentException if any argument vector contains a
destructuring form or varargs argument.

Comment by Víctor M. Valenzuela [ 12/Jul/12 3:13 AM ]

Glad you've considered my request.

As for destructuring, I was speaking after this example, which may or may not work like it looks like - I don't know.

(deftype foo []
clojure.lang.IFn
(invoke [this [a b] c] (println a b c)))

((foo.) [1 2] 3)

Comment by Tassilo Horn [ 12/Jul/12 8:22 AM ]

Indeed, descructuring seems to work for method implementations. I'll adapt my patch...

Comment by Tassilo Horn [ 12/Jul/12 8:42 AM ]

Revamped patch. Here's the commit message:

Protocol, interface method declarations don't allow for varags and
destructuring support. Currently, for example

  (defprotocol FooBar
    (foo [this & more]))

compiles just fine, and & is interpreted as a usual argument that happens to be
named & without special meaning. But clearly, the user wanted to specify a
varags parameter here. The same applies to definterface.

Similarly, providing method implementations via defrecord, deftype, and reify
don't allow for varags (but dynamic extenions via extend do).

So this patch makes defprotocol and definterface throw an
IllegalArgumentException if a user tries to use varargs and destructuring in
method signatures.

Similarly, defrecord, deftype, and reify throw an IllegalArgumentException if
any method implementation arglist contains a varargs argument.

Comment by Andy Fingerhut [ 12/Jul/12 3:43 PM ]

Tassilo, with your patch 0001-CLJ-1024-Check-for-invalid-varags-destrucuring-uses.patch dated July 12, 2012, I get the following error message while testing, apparently because some metadata is missing on the new functions your patch adds to core:

[java] Testing clojure.test-clojure.metadata
[java]
[java] FAIL in (public-vars-with-docstrings-have-added) (metadata.clj:45)
[java] expected: (= [] (remove (comp :added meta) public-vars-with-docstrin
gs-not-generated))
[java] actual: (not (= [] (#'clojure.core/throw-on-varargs-and-destr #'cl
ojure.core/throw-on-varargs)))

Comment by Tassilo Horn [ 13/Jul/12 2:10 AM ]

Hi Andy, this updated patch declares the two new checking fns private which makes the tests pass again.

Stupid mistake by me: Of course, I've tested the last version, too, but afterwards I decided it wouldn't be bad to add some docstrings, and of course, adding docstrings cannot break anything.

Comment by Aaron Bedra [ 14/Aug/12 7:58 PM ]

Patch applies cleanly against 4004d267e124f12b65b0d7fb6522f32a75e3c4fb. Submitter confirmed as a CA signer.

Comment by Aaron Bedra [ 14/Aug/12 8:02 PM ]

This looks ok to me, but it seems like a fair amount of duplication to accomplish the task. It seems like we should just be able to ask if it is ok to proceed, instead of having to pick which function needs to be called in what case.

Comment by Tassilo Horn [ 15/Aug/12 1:23 AM ]

Aaron, can you please elaborate? I don't get what you mean with duplication and asking if it is ok to proceed.

Comment by Tassilo Horn [ 31/Aug/12 1:40 AM ]

Rebased to apply cleanly on master again.

Comment by Víctor M. Valenzuela [ 31/Aug/12 7:11 AM ]

Pardon the silly contribution, but the added methods' usage of double-negations (when-not ...) seems unnecessary.

Comment by Tassilo Horn [ 31/Aug/12 8:03 AM ]

Hi Victor, this revamped patch removes the double-negation and is more concise and clearer as a result. So your comment wasn't as silly as you thought.

Comment by Tassilo Horn [ 14/Feb/13 1:36 AM ]

Hey Stu, do you mind to explain why you've declined the patch?

Comment by Marek Srank [ 14/Feb/13 8:52 AM ]

@Tassilo: https://groups.google.com/forum/#!topic/clojure-dev/qjkW-cv8nog

Comment by Tassilo Horn [ 14/Feb/13 10:03 AM ]

@Marek, Stu: Thanks, I've left a reply there: https://groups.google.com/d/msg/clojure-dev/qjkW-cv8nog/rMNFqbjNj-EJ





[CLJ-1023] non-tail-position try block breaks mutable fields in deftype Created: 08/Jul/12  Updated: 27/Jun/13  Resolved: 03/Dec/12

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.3, Release 1.4
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Stuart Sierra Assignee: Rich Hickey
Resolution: Declined Votes: 0
Labels: None

Attachments: File demonstration.clj    

 Description   

The :unsynchronized-mutable fields of a deftype cannot be set! inside a try block that is not in tail position of the method.

See file *demonstration.clj* for an complete code example.



 Comments   
Comment by Rich Hickey [ 05/Sep/12 7:07 AM ]

I looked at this. The problem is that non-tail try blocks turn into closures, and thus the field gets propagated as a constant. IOW this can't work:

(deftype Foo4 [^:unsynchronized-mutable x]
  MutableX
  (set-x [this v]
    ((fn [] (set! x v)))
    v))

I'm not going to re-evaluate the try/closure approach right now, so I recommend you make a helper method that just does the assignment and then call that in the bigger context, as a workaround.

Comment by Timothy Baldridge [ 03/Dec/12 10:55 AM ]

Closing this as it requires more than a simple bug fix. If you feel that Rich's work-around is unsatisfactory please create a clojure-dev discussion about rewriting try-catch.

Comment by Nicola Mometto [ 27/Jun/13 5:33 AM ]

The patch at ticket CLJ-1226 makes it possible to write

(deftype foo [^:unsynchronized-mutable x] MutableX (set-x [this v] (try (set! (.x this) v)) v))

that is probably a better workaround than writing a helper method





[CLJ-1014] Latest Clojure master doesn't build Created: 14/Jun/12  Updated: 20/Jul/12  Resolved: 20/Jul/12

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Edward Z. Yang Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

Ubuntu 10.10 Maverick
Java 1.6.0_20m OpenJDK (IcedTea6 1.9.13)



 Description   

Compile fails with the following error:

compile-clojure:
[java] Compiling clojure.core to /home/ezyang/Dev/clojure/target/classes
[java] Compiling clojure.core.protocols to /home/ezyang/Dev/clojure/target/classes
[java] Compiling clojure.core.reducers to /home/ezyang/Dev/clojure/target/classes
[java] Exception in thread "main" java.lang.ClassNotFoundException: jsr166y.ForkJoinPool, compiling:(clojure/core/reducers.clj:56)
[java] at clojure.lang.Compiler.analyzeSeq(Compiler.java:6462)
[java] at clojure.lang.Compiler.analyze(Compiler.java:6262)
[java] at clojure.lang.Compiler.analyzeSeq(Compiler.java:6443)
[java] at clojure.lang.Compiler.analyze(Compiler.java:6262)
[java] at clojure.lang.Compiler.analyze(Compiler.java:6223)
[java] at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5618)
[java] at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5054)
[java] at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3674)
[java] at clojure.lang.Compiler.analyzeSeq(Compiler.java:6453)
[java] at clojure.lang.Compiler.analyze(Compiler.java:6262)
[java] at clojure.lang.Compiler.analyze(Compiler.java:6223)
[java] at clojure.lang.Compiler$NewExpr$Parser.parse(Compiler.java:2478)
[java] at clojure.lang.Compiler.analyzeSeq(Compiler.java:6455)
[java] at clojure.lang.Compiler.analyze(Compiler.java:6262)
[java] at clojure.lang.Compiler.analyzeSeq(Compiler.java:6443)
[java] at clojure.lang.Compiler.analyze(Compiler.java:6262)
[java] at clojure.lang.Compiler.access$100(Compiler.java:37)
[java] at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:518)
[java] at clojure.lang.Compiler.analyzeSeq(Compiler.java:6455)
[java] at clojure.lang.Compiler.analyze(Compiler.java:6262)
[java] at clojure.lang.Compiler.analyze(Compiler.java:6223)
[java] at clojure.lang.Compiler.compile1(Compiler.java:7030)
[java] at clojure.lang.Compiler.compile1(Compiler.java:7025)
[java] at clojure.lang.Compiler.compile1(Compiler.java:7025)
[java] at clojure.lang.Compiler.compile(Compiler.java:7097)
[java] at clojure.lang.RT.compile(RT.java:387)
[java] at clojure.lang.RT.load(RT.java:427)
[java] at clojure.lang.RT.load(RT.java:400)
[java] at clojure.core$load$fn__4919.invoke(core.clj:5424)
[java] at clojure.core$load.doInvoke(core.clj:5423)
[java] at clojure.lang.RestFn.invoke(RestFn.java:408)
[java] at clojure.core$load_one.invoke(core.clj:5236)
[java] at clojure.core$compile$fn__4924.invoke(core.clj:5435)
[java] at clojure.core$compile.invoke(core.clj:5434)
[java] at clojure.lang.Var.invoke(Var.java:415)
[java] at clojure.lang.Compile.main(Compile.java:81)
[java] Caused by: java.lang.ClassNotFoundException: jsr166y.ForkJoinPool
[java] at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
[java] at java.security.AccessController.doPrivileged(Native Method)
[java] at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
[java] at clojure.lang.DynamicClassLoader.findClass(DynamicClassLoader.java:61)
[java] at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
[java] at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
[java] at java.lang.Class.forName0(Native Method)
[java] at java.lang.Class.forName(Class.java:264)
[java] at clojure.lang.RT.classForName(RT.java:2043)
[java] at clojure.lang.Compiler$HostExpr.maybeClass(Compiler.java:957)
[java] at clojure.lang.Compiler$HostExpr.access$400(Compiler.java:736)
[java] at clojure.lang.Compiler$NewExpr$Parser.parse(Compiler.java:2473)
[java] at clojure.lang.Compiler.analyzeSeq(Compiler.java:6455)
[java] ... 35 more



 Comments   
Comment by Andy Fingerhut [ 14/Jun/12 11:42 AM ]

What command did you use?

From the error message, my guess is that you ran "ant" without first running "./antsetup.sh". If that is the case, run "./antsetup.sh" first. This is a new step added to readme.txt on May 7, 2012, because of the jsr166y.ForkJoinPool class used within Clojure to implement the new parallel reducers feature.

Comment by Edward Z. Yang [ 14/Jun/12 2:16 PM ]

Yep, that's exactly it. Can we setup ant to warn people if antsetup.sh hasn't been run?

Comment by Andy Fingerhut [ 14/Jun/12 5:12 PM ]

I don't know. I suspect if it could be done and it were a straightforward modification, a patch for that would be accepted. I suspect those who created antsetup.sh would have simply modified the build.xml file for ant, and not created antsetup.sh at all, if it were easy to do so.

Comment by Roy Truelove [ 26/Jun/12 3:58 PM ]

It can be done with just the build.xml but requires the Maven Ant Tasks jar to be in the local ant's classpath, which is not ideal.

Because a local maven install is anyway required by antsetup.sh, IMHO it would be best to remove the ant build all together and stick with solely with a maven build, no?

Comment by Andy Fingerhut [ 27/Jun/12 1:16 PM ]

I can't find the email right now, but I believe in the past Rich Hickey has expressed a preference for continuing to have a way to build Clojure using ant.

Comment by Stuart Halloway [ 20/Jul/12 4:49 PM ]

Ant is there for the convenience of various dinosaurs, myself included. In general you should use the maven build, as that is what the CI and release process do.





[CLJ-1006] Quotient on bigdec may produce wrong result Created: 01/Jun/12  Updated: 01/Mar/13  Resolved: 09/Nov/12

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.4
Fix Version/s: None

Type: Defect Priority: Major
Reporter: laurent joigny Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: bug
Environment:

Linux 3.2.0-24-generic #39-Ubuntu SMP i686 GNU/Linux


Attachments: Java Source File TestBigDecimalQuotient.java    

 Description   

Hi,

As discussed on the mailing list in the message "When arithmetic on a computer bite back" (01/jun)

There may be bug in the way quotient is implemented for bigdec.

user> (quot 1.4411518807585587E17 2) ;; correct with doubles
7.2057594037927936E16
user> (quot 1.4411518807585587E+17M 2) ;; wrong with BigDecs
72057594037927935M


Laurent



 Comments   
Comment by laurent joigny [ 01/Jun/12 5:48 PM ]

I can reproduce the bug when using BigDecimal constructor on String.
See attached file for a test class.

More infos :
java version "1.6.0_24"
OpenJDK Runtime Environment (IcedTea6 1.11.1) (6b24-1.11.1-4ubuntu3)
OpenJDK Client VM (build 20.0-b12, mixed mode, sharing)

Comment by laurent joigny [ 01/Jun/12 5:49 PM ]

A simple test file, that you can drop in Clojure sources and execute to reproduce the bug on BigDecimal constructor using String as argument.

Comment by Tassilo Horn [ 03/Jun/12 4:30 AM ]

Seems to be a general precision problem. Note that in

user> (quot 1.4411518807585587E17 2) ;; correct with doubles
7.2057594037927936E16
user> (quot 1.4411518807585587E+17M 2) ;; wrong with BigDecs
72057594037927935M

the double result is actually wrong and the bigdec one is correct. The problem which lead to the wrong conclusion is that in your calculation the input number is already wrong.

So the moral is: don't use any floating points (neither doubles nor bigdecs) for computations involving divisibility tests.

For bigdecs, you can set the math context for making computations throw exceptions if they lose precision, though:

user> (binding [*math-context* (java.math.MathContext. 1 java.math.RoundingMode/UNNECESSARY)]
	       (quot (bigdec (Math/pow 2 58)) 2))
;Division impossible
;  [Thrown class java.lang.ArithmeticException]
Comment by Stuart Sierra [ 09/Nov/12 8:49 AM ]

Not a bug. Just floating-point arithmetic.





[CLJ-996] alter-var-root + protocol function call results in StackOverflow Created: 16/May/12  Updated: 01/Mar/13  Resolved: 09/Nov/12

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.3, Release 1.4
Fix Version/s: None

Type: Defect Priority: Critical
Reporter: Dmitri Naumov Assignee: Unassigned
Resolution: Declined Votes: 1
Labels: None


 Description   

The following code:

(ns example.core)

(defprotocol Foo
  (foo [x]))

(extend-protocol Foo
  Object (foo [x] x)
  nil (foo [x] nil))

(defn apply-foo [f]
  (fn [& args]
    (foo (apply f args))))

(alter-var-root #'assoc apply-foo)

takes forever to compile from emacs+swank. Running from lein repl results in following:

user=> (use 'example.core)
StackOverflowError   clojure.lang.ArrayChunk.<init> (ArrayChunk.java:28)

If delete the foo call from the apply-foo:

(defn apply-foo [f]
  (fn [& args]
    (apply f args)))

then code compiles and executes fine.

This is true not only for assoc, but also for conj, into and possibly some other functions. Note also that crashes was seen even when the protocol function is not called, but there is call to satisfies? in the apply-foo function (although it's not clear for me how to reproduce it). Tested on clojure 1.3 and 1.4.



 Comments   
Comment by Tassilo Horn [ 11/Oct/12 1:23 PM ]

Is this bug a fairly well-constructed joke? I guess so.

But this is what I think happens: You change the value of #'assoc to the function returned by apply-foo. The alter-var-root call executes (apply-foo assoc) because assoc is the current value of #'assoc, thus the new value of #'assoc is {{(fn [& args] (foo (apply assoc args)))}}. However, fn is a macro that expands to fn* and calls destructure which uses assoc!!! So now foo gets called, and probably there's another assoc call during protocol dispatch, and there you have your non-terminating recursion.

So the lesson is: Don't alter core functions unless you're exactly knowing what you do.

Comment by Stuart Sierra [ 09/Nov/12 8:42 AM ]

Not a bug. You can't alter core functions and expect things not to break.





[CLJ-991] partition-by reducer Created: 10/May/12  Updated: 09/Mar/15  Resolved: 05/Mar/15

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: Release 1.7

Type: Enhancement Priority: Minor
Reporter: Kevin Downey Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: reducers

Attachments: File reducer-partition-by2.diff     File reducer-partition-by3.diff     File reducer-partition-by4.diff     File reducer-partition-by.diff    
Patch: Code and Test

 Comments   
Comment by Rich Hickey [ 14/Aug/12 1:52 PM ]

I'd like to see something much faster than this.

Comment by Kevin Downey [ 15/Aug/12 1:58 AM ]

For reference here is a benchmark of a non-reducers (seq based) process that uses partition-by

user=> (def x (vec (range 1e6)))
#'user/x
user=> (bench (reduce + (map count (partition-by #(or (zero? (mod % 3)) (zero? (mod % 5))) x))))
Evaluation count             : 60
             Execution time mean : 1.072157 sec  95.0% CI: (1.070606 sec, 1.073381 sec)
    Execution time std-deviation : 165.818282 ms  95.0% CI: (163.873585 ms, 168.271261 ms)
         Execution time lower ci : 972.562000 ms  95.0% CI: (972.562000 ms, 973.301850 ms)
         Execution time upper ci : 1.419148 sec  95.0% CI: (1.419148 sec, 1.419148 sec)

Found 7 outliers in 60 samples (11.6667 %)
	low-severe	 2 (3.3333 %)
	low-mild	 5 (8.3333 %)
 Variance from outliers : 85.8489 % Variance is severely inflated by outliers
nil
user=>

Same again using r/partition-by from reducer-partition-by.diff

user=> (bench (r/reduce + (r/map count (r/partition-by #(or (zero? (mod % 3)) (zero? (mod % 5))) x))))
Evaluation count             : 60
             Execution time mean : 1.418350 sec  95.0% CI: (1.417738 sec, 1.418948 sec)
    Execution time std-deviation : 66.736477 ms  95.0% CI: (66.186568 ms, 67.610777 ms)
         Execution time lower ci : 1.370419 sec  95.0% CI: (1.370419 sec, 1.370419 sec)
         Execution time upper ci : 1.544151 sec  95.0% CI: (1.544151 sec, 1.544156 sec)

Found 10 outliers in 60 samples (16.6667 %)
	low-severe	 2 (3.3333 %)
	low-mild	 8 (13.3333 %)
 Variance from outliers : 33.5591 % Variance is moderately inflated by outliers
nil
user=> 

(using https://github.com/hugoduncan/criterium for benchmarking)

Comment by Kevin Downey [ 15/Aug/12 2:17 AM ]

same again for r/partition-by from reducers-partition-by2.diff

user=> (bench (r/reduce + (r/map count (r/partition-by #(or (zero? (mod % 3)) (zero? (mod % 5))) x))))
Evaluation count             : 180
             Execution time mean : 307.596806 ms  95.0% CI: (307.271339 ms, 307.961550 ms)
    Execution time std-deviation : 34.060809 ms  95.0% CI: (33.613169 ms, 34.416837 ms)
         Execution time lower ci : 285.339333 ms  95.0% CI: (285.339333 ms, 285.339333 ms)
         Execution time upper ci : 385.087950 ms  95.0% CI: (385.087950 ms, 385.087950 ms)

Found 10 outliers in 60 samples (16.6667 %)
	low-severe	 4 (6.6667 %)
	low-mild	 6 (10.0000 %)
 Variance from outliers : 73.8053 % Variance is severely inflated by outliers
nil
user=> 

same again driven using r/fold (for grins) instead of r/reduce

user=> (bench (r/fold + (r/map count (r/partition-by #(or (zero? (mod % 3)) (zero? (mod % 5))) x))))
Evaluation count             : 360
             Execution time mean : 215.214486 ms  95.0% CI: (214.915417 ms, 215.664236 ms)
    Execution time std-deviation : 36.588464 ms  95.0% CI: (36.305548 ms, 36.847846 ms)
         Execution time lower ci : 185.575000 ms  95.0% CI: (185.575000 ms, 185.575000 ms)
         Execution time upper ci : 287.605175 ms  95.0% CI: (286.547833 ms, 287.605175 ms)

Found 6 outliers in 60 samples (10.0000 %)
	low-severe	 3 (5.0000 %)
	low-mild	 3 (5.0000 %)
 Variance from outliers : 87.6303 % Variance is severely inflated by outliers
nil
user=> 

reducers-partition-by2.diff is faster, but I am not wild about introducing a type and a protocol. also not sure about the CollFold impl.

Comment by Rich Hickey [ 15/Aug/12 6:58 AM ]

Let's leave fold out for this first patch, please.

Comment by Kevin Downey [ 15/Aug/12 2:34 PM ]

reducer-partition-by3.diff is a cleaned up version of reducer-partition-by2.diff without fold

Comment by Devin Walters [ 20/Oct/12 7:07 PM ]

Per Andy Fingerhut's email reducer-partition-by3.diff was failing to apply. This patch should apply cleanly to current master.

Comment by Andy Fingerhut [ 01/Nov/12 6:59 PM ]

Presumptuously changing Approval from Incomplete to None, since the reason for its being marked Incomplete seems to have been addressed with the latest patch.

Comment by Kevin Downey [ 04/Mar/13 2:49 PM ]

should this be assigned to someone?

Comment by Andy Fingerhut [ 03/Sep/14 8:09 PM ]

Patch reducer-partition-by4.diff dated Oct 20 2012 no longer applies cleanly to latest master after some commits were made to Clojure on Sep 3, 2014.

I have not checked whether this patch is straightforward to update, nor do I know if there is interest in an updated patch, or whether transducers are the preferred way to go over reducers, and thus all reducers-related tickets will be closed. See the section "Updating stale patches" at http://dev.clojure.org/display/community/Developing+Patches for suggestions on how to update patches.

Comment by Kevin Downey [ 05/Mar/15 11:41 AM ]

the single arity for completion added to reducing functions in 1.7 makes partition-by easier to write, and low and behold clojure.core/parition-by can return a partitioning transducing function





[CLJ-984] Expose minKey and maxKey on PersistentTreeSet Created: 05/May/12  Updated: 07/May/12  Resolved: 07/May/12

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.3
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Greg Chapman Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

I have found it occasionally useful to be able to get the minimum or maximum of a sorted set. PersistentTreeMap already has public minKey and maxKey methods; I suggest adding public minKey and maxKey methods to PersistentTreeSet (which obviously will just call the relevant methods on the impl map).



 Comments   
Comment by Greg Chapman [ 05/May/12 9:09 PM ]

Actually, on further reflection, I was too hasty in opening this. first combined with seq or rseq is good enough. If I could close this I would, but I don't see a way to do so.

Comment by Andy Fingerhut [ 07/May/12 12:05 PM ]

Closing this since submitter wishes it to be.





[CLJ-982] Implement an interface? predicate to balance class? Created: 04/May/12  Updated: 09/Jun/12  Resolved: 08/Jun/12

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.5
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: David Rupp Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: enhancement, patch, test
Environment:

Any


Attachments: File drupp-add-interface-predicate.diff    
Patch: Code and Test

 Description   

clojure.core implements a class? predicate to detect if a thing is an instance of java.lang.Class. The attached patch implements interface? to further distingui