<< Back to previous view

[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: 31/Jan/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.





[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-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-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: 29/Jan/14  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





[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-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 distinguish classes that are also interfaces. This gives us Clojure api for e.g., enumerating all interfaces a thing's base class implements; as in, (filter #(interface? %) (supers (class my-thing))).



 Comments   
Comment by Stuart Halloway [ 08/Jun/12 12:28 PM ]

I would prefer to see this, and other interop/reflective items, in a separate contrib lib.

Comment by David Rupp [ 09/Jun/12 9:08 AM ]

Thanks for the feedback, Stu. Is there an existing contrib lib for stuff like this? Or should I create one?





[CLJ-980] Documentation for extend-type falsely implies that & is allowed in protocol fn signatures Created: 03/May/12  Updated: 18/Oct/13  Resolved: 18/Oct/13

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

Type: Defect Priority: Trivial
Reporter: Charles Duffy Assignee: Stuart Halloway
Resolution: Declined Votes: 0
Labels: docstring

Attachments: File clojure--extend-type-doc-fix.diff     Text File extended-type-doc-fix-v2.patch    
Patch: Code
Approval: Vetted

 Description   

The documentation for extend-type contains the following example:

(extend-type MyType 
    Countable
      (cnt [c] ...)
    Foo
      (bar [x y] ...)
      (baz ([x] ...) ([x y & zs] ...)))

However, [x y & zs] is not a valid parameter list for a protocol fn. The documentation should be appropriately amended.



 Comments   
Comment by John Szakmeister [ 25/May/12 4:00 AM ]

v2 of the patch is simply converts the patch to git format. I made sure that Mr. Duffy got proper attribution. I also took a stab at a simple log message. Any problems with the latter are mine, and I'm happy to fix it up if necessary.

Comment by Aaron Bedra [ 15/Aug/12 10:08 PM ]

This doesn't update the entire doc string. The expansion is updated, but the signature section isn't. Here's what shows up.

user=> (doc extend-type)
-------------------------
clojure.core/extend-type
([t & specs])
Macro
  A macro that expands into an extend call. Useful when you are
  supplying the definitions explicitly inline, extend-type
  automatically creates the maps required by extend.  Propagates the
  class as a type hint on the first argument of all fns.

  (extend-type MyType 
    Countable
      (cnt [c] ...)
    Foo
      (bar [x y] ...)
      (baz ([x] ...) ([x y & zs] ...)))

  expands into:

  (extend MyType
   Countable
     {:cnt (fn [c] ...)}
   Foo
     {:baz (fn ([x] ...) ([x y ...] ...))
      :bar (fn [x y] ...)})
Comment by Tassilo Horn [ 25/Aug/12 6:44 AM ]

This is very much related to http://dev.clojure.org/jira/browse/CLJ-1024.

NOTE: While varargs are not supported in protocol declarations, dynamic extension of a protocol via extend (extend-type, extend-protocol) does allow for varargs and also destructuring, cause the method impls are actually normal clojure functions.

So if a Foo protocol declares a (foo [this a b c]) method, you can extend/extend-type/extend-protocol it dynamically using (foo [this & more] (do-magick)) where `a b c` are conflated into the `more` parameter.

However, that doesn't work for method implementations defined by deftype, defrecord, and reify.

So with respect to the facts, the example in the docstring is actually correct, so I'm not sure if it should be changed. However, what's supported in which cases should be documented better as it is right now.

Comment by Alex Miller [ 28/Jul/13 10:13 PM ]

Putting back in triage to go through release assignment again.

Comment by Stuart Halloway [ 18/Oct/13 9:31 AM ]

I agree with Tassilo's comment, the documented behavior works. You can't use varargs in defprotocol but you can use them in extend-type.





[CLJ-971] Jar within a jar throws a runtime error Created: 10/Apr/12  Updated: 22/Aug/14  Resolved: 22/Aug/14

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

Type: Defect Priority: Minor
Reporter: Ron Romero Assignee: Unassigned
Resolution: Declined Votes: 2
Labels: None
Environment:

Maven using the one-jar plugin


Attachments: Text File clj-971-1.patch     Text File clj-971-2.patch    
Patch: Code
Approval: Incomplete

 Description   

The code in RT.load() will load a class by name in several situations. One of these is when a .class resource exists, a .clj resource exists and the class is newer than the clj file. To determine the age of the class and clj, a call is made into RT.lastModified with the resource URL. If the URL is a jar protocol, then RT.lastModified() will try to open a connection to that jar, find the entry in the jar, and return its time.

Sometimes deployment occurs using nested jar files (for example: http://one-jar.sourceforge.net/) and custom classloaders. In this usage, the jar file can be opened, but the entry will not be found and an NPE will result during load:

Caused by: java.lang.NullPointerException
    at clojure.lang.RT.lastModified(RT.java:374)
    at clojure.lang.RT.load(RT.java:408)
    at clojure.lang.RT.load(RT.java:398)
    at clojure.lang.RT.doInit(RT.java:434)
    at clojure.lang.RT.<clinit>(RT.java:316)
... 7 more

Proposal: Make lastModified() more tolerant of finding a null entry and falling back to return the last modified date of the jar file itself.

Patch: clj-971-2.patch

Screened by:



 Comments   
Comment by Anders Sveen [ 11/Nov/13 3:29 AM ]

Would be awesome if you could get this working. Wanting to use som Clojure libs in Java so Leiningen uberjar is not an option right now.

Comment by Paavo Parkkinen [ 24/Nov/13 7:11 AM ]

Took the code change in the description and rolled it into a patch to hopefully push this forward a little bit.

Comment by Alex Miller [ 24/Nov/13 10:06 AM ]

Thanks Paavo - on a quick scan, it looks like in the case you're interested in the updated code would now call url.openConnection() twice - perhaps that could be factored out?

Comment by Paavo Parkkinen [ 25/Nov/13 6:19 AM ]

New patch with duplicate calls to url.openConnection() factored out.

Comment by Gleb Kanterov [ 13/Dec/13 4:30 AM ]

I had the same issue, adding following line to manifest file worked for me

One-Jar-URL-Factory: com.simontuffs.onejar.JarClassLoader$OneJarURLFactory
Comment by Stuart Halloway [ 31/Jan/14 1:04 PM ]

Can we get a test showing the normal path and the can't-read-inside path?

Comment by Sean Shubin [ 17/Apr/14 9:34 PM ]

I notice this solution falls back on the last modified date for the entire jar, while it is still possible to get the date of the individual file, albeit less efficiently.
I posted a way to get the individual file date in CLJ-1405.
Perhaps you don't need the date of the individual file, but I am having a hard time groking the calling code so I am not sure what its intent is.
I did notice in the calling code that the if statement
(classURL != null && (cljURL == null || lastModified(classURL, classfile) > lastModified(cljURL, cljfile))) || classURL == null
Is logically equivalent to the much simpler
classURL == null || cljURL == null || lastModified(classURL, classfile) > lastModified(cljURL, cljfile)

Comment by Alex Miller [ 23/May/14 10:56 AM ]

Why is the solution that Gleb proposed not sufficient without changing Clojure? It seems fairly trivial to add a manifest line in the one-jar packaging step:

One-Jar-URL-Factory: com.simontuffs.onejar.JarClassLoader$OneJarURLFactory

Stu - I doubt the effort of setup is worth a test in the clojure tests but it might be useful to have documented steps to repro manually.

Sean - I think the effort on CLJ-1405 of scanning the full jar is going too far and not needed if we decide to go forward with this.

Comment by Sean Shubin [ 06/Jul/14 12:32 AM ]

Alex,

Regarding scanning the jar, I was worried about the behavior not matching the intent of the code. As I have not had time to get familiar with the code, I figured this route was safer. If scanning the jar turns out to be overkill, so be it, we could just have the lastModified return 0 or something. Either way the code should be under test coverage, I will try to block out some time for that next weekend. Also, as I mentioned in CLJ-1405 (sorry about the duplicate issue), I did document the steps to reproduce the issue here: https://github.com/SeanShubin/clojure-one-jar.

Regarding Gleb's solution, that seems like a decent workaround, but I figured it would be better to fix the bug where it is rather than rely on a workaround. Shouldn't Clojure be changed if it is legitimately a bug in Clojure?

Comment by Alex Miller [ 06/Jul/14 6:06 PM ]

Onejar creates a new kind of classpath container (which happens to have the same type as a .jar) but works differently. As such, resource urls that start with the jar protocol no longer work in certain ways (in this case returning null for lastModified). Java provides a mechanism to customize this behavior with a new url protocol, which is what the One-Jar-URL-Factory installs and uses. It thus seems to me that onejar introduces the issue and also provides the solution. As far as I see it, this is not a bug in Clojure itself.

If there were situations (without custom jar types or protocols) where lastModified() really does throw an NPE, then I would be more convinced that this was a scenario where Clojure should change behavior.

To modify the greeter example given in CLJ-1405:
1) bump the onejar-maven-plugin version to at least 1.4.5
2) add the following to the executions/execution/configuration for the plugin:

<manifestEntries>
      <One-Jar-URL-Factory>com.simontuffs.onejar.JarClassLoader$OneJarURLFactory</One-Jar-URL-Factory>
    </manifestEntries>




[CLJ-967] java.io/do-copy can still garble multibyte characters on IBM JDK 1.5 and 1.6 Created: 07/Apr/12  Updated: 01/Mar/13  Resolved: 01/Mar/13

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

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

At least Linux + IBM JDK 1.5, and Linux + IBM JDK 1.6


Attachments: Text File clj-886-improved-fix-for-ibm-jdks-patch2.txt     Text File clj-967-disable-failing-io-copy-tests-on-ibm-jdk-16-patch1.txt    
Patch: Code and Test

 Description   

Same issue as CLJ-886, but while the patch applied for that issue fixes the problem for many OS/JDK combos, there appear to be differences in how surrogate pair characters are handled in some OS/JDK combos. In particular, at least Linux + IBM JDK 1.5 and Linux + IBM JDK 1.6 still fail the tests checked in for do-copy.



 Comments   
Comment by Andy Fingerhut [ 07/Apr/12 9:32 AM ]

clj-886-improved-fix-for-ibm-jdks-patch2.txt dated Apr 7 2012 makes the tests pass with Linux + IBM JDK 1.5, as well as these other combos tested:

Linux + Oracle JDK 1.7
Linux + IBM JDK 1.5
Mac OS X 10.6.8 + Oracle/Apple JDK 1.6

There are still failing tests for Linux + IBM JDK 1.6. This patch currently skips the failing tests whenever the java.vendor is "IBM Corporation" and java.version is "1.6.0", so that "ant" succeeds. It is easy enough to modify the patch so that the failing tests are kept as a bright shining reminder. Let me know if that would be preferred – it just involves removing the function ibm-jdk16, and simplifying where it is called after replacing it with false.

Comment by Stuart Halloway [ 18/May/12 9:30 AM ]

Not sure if we should be in the business of building JDK-specific workarounds into our IO library, but marking this as screened.

Option B is to leave the code as-is and only disable the tests. Rich?

Comment by Rich Hickey [ 18/May/12 2:42 PM ]

Please disable the tests. We shouldn't be doing such workarounds.

Comment by Andy Fingerhut [ 19/May/12 2:50 AM ]

clj-967-disable-failing-io-copy-tests-on-ibm-jdk-16-patch1.txt dated May 19, 2012 disables tests of clojure.java.io/copy that fail with IBM JDK 1.6.0. It makes minor changes to the clojure.java.io code file, but these are only to eliminate uses of reflection, and to make a few of the versions of do-copy share more of their implementation code.

Tested that all results are good on Mac OS X 10.6.8 + Oracle/Apple JDK 1.6.0 and Ubuntu 11.10 + Oracle JDK 1.7.0, including that the number of tests run are identical to before this patch. Only 2 tests are disabled on IBM JDK 1.6.0, and all of the rest pass before and after these changes.

Comment by Andy Fingerhut [ 19/May/12 3:22 AM ]

Hoping that I'm not out of line changing approval from Incomplete to None after attaching a patch that should address the reason it was marked incomplete. The only other way to get a ticket out of Incomplete state is for a core team member to do it for me, which seems like busy-work.

Comment by Andy Fingerhut [ 30/Aug/12 2:13 PM ]

Any comments from Rich or other screeners on the status of this one? Just curious, since it seemed to have been screened, and then quietly tossed back into the unscreened pile. Is it considered undesirable to disable selected tests for a particular JDK as the patch clj-967-disable-failing-io-copy-tests-on-ibm-jdk-16-patch1.txt does? My motivation was to selectively disable only the tests that fail, and only on the JDK where they fail, leaving all passing tests to continue to run wherever possible.





[CLJ-956] [java.lang.ClassFormatError: Duplicate method name&signature] when using gen-class Created: 20/Mar/12  Updated: 01/Mar/13  Resolved: 09/Nov/12

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

Type: Defect Priority: Major
Reporter: Daniel Ribeiro Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: AOT
Environment:

$ java -version
java version "1.6.0_29"
Java(TM) SE Runtime Environment (build 1.6.0_29-b11-402-11M3527)
Java HotSpot(TM) 64-Bit Server VM (build 20.4-b02-402, mixed mode)



 Description   

Hi,

When extending a class that defines a method with the signature "public void load();", I get the following load time error:

java.lang.ClassFormatError: Duplicate method name&signature

Looking into javap, I see that in fact gen-class is generating two entries for the load method. Prefix does not help in this case, as the defined load method is generated anyway.

Cheers,

  • Daniel


 Comments   
Comment by Daniel Ribeiro [ 22/Mar/12 5:10 AM ]

Hi,

I've create this small sample project to exemplify the bug ocurring: https://github.com/danielribeiro/ClojureBugReport

Cheers,

  • Daniel
Comment by Daniel Ribeiro [ 24/Mar/12 6:57 PM ]

Note that the name load is not special: it works with any abstract method, no matter the name.

Comment by Daniel Ribeiro [ 24/Mar/12 7:34 PM ]

Not a bug: I was declaring the method load, which was already defined on the abstract class. The docs do mention this:

http://clojuredocs.org/clojure_core/clojure.core/gen-class

Comment by Stuart Sierra [ 09/Nov/12 8:40 AM ]

Closed as not-a-bug.





[CLJ-951] Clojure 1.3+ can't intern a dynamic var Created: 09/Mar/12  Updated: 30/Nov/12  Resolved: 30/Nov/12

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

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


 Description   

In Clojure 1.3+, interned vars don't set the dynamic field in clojure.lang.Var and can't be used in a binding:

user=> (intern ns (with-meta 'dyna-var {:dynamic true}) 100)
user=> (binding [dyna-var "one hundred"] dyna-var)
;=> IllegalStateException Can't dynamically bind non-dynamic var: user/dyna-var clojure.lang.Var.pushThreadBindings (Var.java:339)

The var has the right metadata

user=> (meta #'dyna-var)
;=> {:ns #<Namespace user>, :name dyna-var, :dynamic true}

But doesn't set the dynamic flag on the var:

user=> (.isDynamic #'dyna-var)
;=> false

The push-thread-bindings function looks for the .dynamic flag. Vars created via def have it:

user=> (def ^:dynamic def-dyna-var 100)
user=> (.isDynamic #'def-dyna-var)
;=> true

Along with the metadata

user=> (meta #'def-dyna-var)
{:ns #<Namespace user>, :name def-dyna-var, :dynamic true, :line 6, :file "NO_SOURCE_PATH"}



 Comments   
Comment by Timothy Baldridge [ 30/Nov/12 3:57 PM ]

This is actually an enhancement. The Var.java and Namespace.java code does not attempt to read the metadata on the var. Instead, the compiler handles this at compile time. If you would like to see this behavior changed, feel free to bring it up on clojure-dev, and we'll discuss it.

Closing until that time.





[CLJ-950] Function literals behavior differ from that of fns Created: 08/Mar/12  Updated: 01/Mar/13  Resolved: 08/Mar/12

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

Type: Defect Priority: Major
Reporter: Víctor M. Valenzuela Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: reader


 Description   

((fn [] true)) ; true
(#(true)) ; classcast exception

((fn [])) ; nil
(#()) ; ()

(some (fn [_]_) [nil false 0 1]) ; 0
(some #(%) [nil false 0 1]) ; NPE



 Comments   
Comment by Tassilo Horn [ 08/Mar/12 12:27 PM ]

This is no defect. Function literals must have a function (or macro or special form) as first symbol.
So your examples should be written like so:

user> (#(do true))
true
user> (#(do))
nil
user> (some #(do %) [nil false 0 1])
0
Comment by Víctor M. Valenzuela [ 08/Mar/12 2:10 PM ]

It makes sense. However (and correct me if I'm wrong) there should be little problem in making them fully equivalent to fns, resulting in a more concise and consistent API.

Please consider re-opening the issue as a feature request.

Regards - Víctor.

Comment by Tassilo Horn [ 09/Mar/12 1:26 AM ]

The reader docs at http://www.clojure.org/reader say that #() is not a replacement for (fn [] ...). You can't make it more equivalent to fn without making it much harder to understand. Let me explain that with an example.

(defn get-time []
  (System/currentTimeMillis))

(#(get-time)) ;; What's the result?

What's the result of the funcall above? Clearly, right now, it is the current system time.

So if we decided to allow to write #(true) as an alternative to (constantly true) [which is a varargs fn] or #(do true) [which is a fn of zero args], then valid values of #(get-time) where both the current system time but also the function object for get-time. Functions are values, too.

Ok, one could say that in the case of a function, #(function) is always a call, but it would make it harder to reason about what the code does for not much benefit.

Comment by Víctor M. Valenzuela [ 09/Mar/12 7:56 AM ]

You're right - satisfying my request would require to change the average use of this feature to #((some_fn %1 %2)) rather than just #(some_fn %1 %2), if we wanted #(true) to be valid. Which indeed would be barely handy.

Thank you.





[CLJ-945] clojure.string/capitalize can give wrong result if first char is supplementary Created: 05/Mar/12  Updated: 01/Mar/13  Resolved: 01/Mar/13

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

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

all


Attachments: Text File capitalize-for-supplementary-chars-patch.txt    
Patch: Code and Test

 Description   

When the first unicode code point of a string is supplementary (i.e. requires two 16-bit Java chars to represent in UTF-16), and that first code point is changed by converting it to upper case, clojure.string/capitalize gives the wrong answer.



 Comments   
Comment by Rich Hickey [ 20/Jul/12 7:43 AM ]

Isn't this a Java bug?

Comment by Andy Fingerhut [ 20/Jul/12 12:36 PM ]

If using UTF-16 to encode Unicode strings, and making every UTF-16 code unit (i.e. Java char) individually indexable as a separate entity in strings, is such a bad design choice that you consider it a bug, then yes, this is a Java bug (and a bug in all the other systems that use UTF-16 in this way).

clojure.string/capitalize isn't using some Java capitalization method that has a bug, though. By calling (.toUpperCase (subs s 0 1)) it is not giving enough information to .toUpperCase for any implementation, Java or otherwise, to do the job correctly. It is analogous to calling toupper on the least significant 4 bits of the ASCII encoding of a letter and expecting it to return the correct answer.





[CLJ-926] Instant literals do not round trip correctly Created: 05/Feb/12  Updated: 17/Feb/12  Resolved: 17/Feb/12

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

Type: Defect Priority: Major
Reporter: Cosmin Stejerean Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: instant, reader, tagged-literals

Attachments: Text File CLJ-926-round-trip-date-instants-with-tests.patch    
Patch: Code and Test
Approval: Screened
Waiting On: Stuart Sierra

 Description   

When using java.util.Date for instant literals (which is the default) instants do not round-trip properly during daylight savings. Here is an example:

(read-string "#inst \"2010-11-12T13:14:15.666-06:00\"")
#inst "2010-11-13T06:14:15.666+10:00"

I'm currently in Melbourne, which is normally GMT+10. However, on November 12th daylight savings is in effect, so the proper GMT offset is +11. The date above is actually using the correct local time (6:14:15) but with the wrong offset. The problem is more obvious when you attempt to round-trip the instant that was read.

user> #inst "2010-11-13T06:14:15.666+10:00"
#inst "2010-11-13T07:14:15.666+10:00"

Notice that we read 6:14am but the output was 7:14 with the same offset. Upon digging deeper the real culprit seems to be the use of String.format (through clojure.core/format) when outputting java.util.Date. Notice the following inside caldate->rfc3339

(format "#inst \"%1$tFT%1$tT.%1$tL%1$tz\"" d))

Let's compare the timezone offset in the underlying date with what is printed by %1$tz

user> (def d #inst "2010-11-13T06:14:15.666+10:00")
#'clojure.instant/d                                                                                                                                                                                         
user> (.getHours d)
7                                                                                                                                                                                                           
user> (.getTimezoneOffset d)
-660

For reference, the definition of getTimezoneOffset is

-(Calendar.get(Calendar.ZONE_OFFSET) + Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)

So far it looks good. 6am in GMT+10 becomes 7am in GMT+11. Let's see how String.format handles it though.

                                                                                               
clojure.instant> (format "%1$tz" d)
"+1000"                                                                                                                                                                                                     
clojure.instant> (format "%1$tT" d)
"07:14:15"

String.format prints the correct hour, but with the wrong offset. The recommended way for formatting dates is to use a DateFormatter.

The String.format approach appears to work properly for Calendar, but not for Date. Therefore the attached patch keeps the current
implementation for java.util.Calendar but uses SimpleDateFormat to handle java.util.Date correctly. This fixes the roundtrip problem.



 Comments   
Comment by Cosmin Stejerean [ 05/Feb/12 9:29 PM ]

Not quite sure how to create a repeatable test for this since the issue depends on the local timezone.

Comment by Steve Miner [ 06/Feb/12 8:33 AM ]

java.util.TimeZone/setDefault could be used for testing in various timezones.

Comment by Steve Miner [ 06/Feb/12 8:37 AM ]

Regarding the patch: SimpleDateFormat is a relatively heavy-weight object, so it seems bad to allocate one every time you print a Date. Unfortunately, SimpleDateFormat is not thread-safe, so you can't just share one. The Java world seems to agree that you should use JodaTime instead, but if you're stuck with the JDK, you need to have a ThreadLocal SimpleDateFormat. I'm working on my own patch along those lines.

Comment by Fogus [ 06/Feb/12 7:38 PM ]

Excellent analysis. I'll keep track of this case and vet any patches that come along. Please do attach a regression test if possible.

Comment by Cosmin Stejerean [ 06/Feb/12 8:39 PM ]

I attached a new patch using a SimpleDateFormat per thread using a thread local. I'll try to add some tests next.

Comment by Cosmin Stejerean [ 06/Feb/12 10:42 PM ]

A combined patch that uses a thread local SimpleDateFormat, tests round-tripping at a known daylight savings point (by overriding the default timezone) and checks round tripping at multiple points throughout the year (every hour of the first 4 weeks of every month of the year).

Steve, thanks for the suggestions on using a thread local and TimeZone/setDefault.

Comment by Steve Miner [ 07/Feb/12 1:32 PM ]

I filed CLJ-928 with my patch for fixing the printing of Date and Timestamp using UTC. I copied the tests from the CLJ-926 patch to make sure we're compatible.

Comment by Fogus [ 07/Feb/12 3:11 PM ]

Thanks for the regression test also. I'll vett this patch ASAP.

Comment by Fogus [ 17/Feb/12 1:24 PM ]

Seems reasonable to me.

Comment by Stuart Sierra [ 17/Feb/12 1:46 PM ]

Vetted. Will apply later.

Comment by Stuart Sierra [ 17/Feb/12 1:56 PM ]

Not Vetted. Test. That thing.

Comment by Stuart Sierra [ 17/Feb/12 2:10 PM ]

No, it's "Screened," not "Test." Somebody save me.

Comment by Stuart Sierra [ 17/Feb/12 3:55 PM ]

Superseded by CLJ-928.





[CLJ-922] Transient maps lose values Created: 31/Jan/12  Updated: 31/Jan/12  Resolved: 31/Jan/12

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

Type: Defect Priority: Major
Reporter: Carl Lerche Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

OS X, java 1.6.0_29


Attachments: File bug.clj    

 Description   

I have tested this on the latest clojure 1.4 alpha (1.4.0-alpha5).

I am not exactly sure what the problem is w/ transient maps, but at a certain point they appear to lose values (values that are inserted into the maps w/ assoc! do not get saved).

I have a test script that illustrates this bug:

https://gist.github.com/497879a727dabac46ec3

All the values up to content-length are saved, but content-length never makes it into the transient map.



 Comments   
Comment by Tassilo Horn [ 31/Jan/12 1:20 AM ]

This is no bug, but you use assoc! wrongly. Just like with assoc, you need to use the return value of the call instead of "bashing the transient map in place". I.e., in your code, replace the doto with ->, which threads the result of each assoc! call to the next one, returning the last value.

BTW: This came up on the list the last days, too. See:

https://groups.google.com/d/msg/clojure/rmLLnRx5p3U/10GYNQdTVksJ

Comment by Tassilo Horn [ 31/Jan/12 1:21 AM ]

This is no bug but a usage error.





[CLJ-913] slurp fails on /proc files (linux) Created: 19/Jan/12  Updated: 01/Mar/13  Resolved: 29/Feb/12

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

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

linux



 Description   

On my machine,
(slurp "/proc/cpuinfo")
fails with:
java.io.IOException: Argument invalide (NO_SOURCE_FILE:0)

whereas the following succeeds:
(with-open [f (java.io.FileReader. "/proc/cpuinfo")] (slurp f))



 Comments   
Comment by Tassilo Horn [ 23/Jan/12 8:57 AM ]

It seems this is not an error in Clojure but an error in the native implementation of FileInputStream.available(). For example, this Java code throws the same exception.

    FileInputStream fis = new FileInputStream("/home/horn/dead.letter");
    System.out.println(fis.available());  // Works fine

    fis = new FileInputStream("/proc/cpuinfo");
    System.out.println(fis.available());  // IOException is thrown

Tested with sun-jdk 1.6.0.29 and IcedTea 7.2.0.

Comment by Andy Fingerhut [ 20/Feb/12 7:42 PM ]

This is not a fix, but a workaround for this issue with the JVM: call slurp on a reader that you force to be constructed as unbuffered. For example:

(slurp (java.io.InputStreamReader. (java.io.FileInputStream. "/proc/cpuinfo")))

(tested with Sun/Oracle JDK 1.7.0_02)

This is less efficient for large files, so I wouldn't recommend that the slurp code be modified to work this way for all files.

One can imagine an implementation of Clojure slurp and clojure.java.io/reader that first tried the slurp call with buffered I/O, and if an exception like this one occurs fall back to unbuffered I/O. However, that sounds like it would get very hairy very quickly, and would be difficult to write it in such a way that it did not mask I/O errors that should be visible to the caller. Also that seems like unwanted complexity in Clojure to work around what is likely a bug in the JVM. Someone (Tassilo?) filed a bug with Oracle about this exception:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7132461

Comment by Andy Fingerhut [ 29/Feb/12 1:06 AM ]

I contacted Romain, the submitter, and they agreed that trying to work around this JVM bug in Clojure's slurp might be a bit excessive, and that closing the ticket was reasonable.

I have added a note about Romain's workaround at http://clojuredocs.org/clojure_core/1.3.0/clojure.core/slurp in hopes that others will be able to find it more easily.





[CLJ-912] clojure.java.browse/browse-url fails to open http://localhost:3000 with swing backend Created: 17/Jan/12  Updated: 12/Mar/12  Resolved: 12/Mar/12

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

Type: Defect Priority: Minor
Reporter: Dmitri Naumov Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

I've got the following exception after launching (clojure.java.browse/browse-url "http://localhost:3000"):

java.lang.RuntimeException: java.io.FileNotFoundException: http://localhost:3000
at clojure.lang.Util.runtimeException(Util.java:165)
at clojure.lang.Reflector.invokeConstructor(Reflector.java:193)
at clojure.java.browse_ui$open_url_in_swing.invoke(browse_ui.clj:15)
at clojure.lang.Var.invoke(Var.java:401)
at clojure.java.browse$open_url_in_swing.invoke(browse.clj:44)
at clojure.java.browse$browse_url.invoke(browse.clj:52)
at user$eval1689.invoke(NO_SOURCE_FILE:1)
at clojure.lang.Compiler.eval(Compiler.java:6465)
at clojure.lang.Compiler.eval(Compiler.java:6431)
at clojure.core$eval.invoke(core.clj:2795)
at swank.commands.basic$eval_region.invoke(basic.clj:47)
at swank.commands.basic$eval_region.invoke(basic.clj:37)
at swank.commands.basic$eval845$listener_eval__846.invoke(basic.clj:71)
at clojure.lang.Var.invoke(Var.java:401)
at user$eval1687.invoke(NO_SOURCE_FILE)
at clojure.lang.Compiler.eval(Compiler.java:6465)
at clojure.lang.Compiler.eval(Compiler.java:6431)
at clojure.core$eval.invoke(core.clj:2795)
at swank.core$eval_in_emacs_package.invoke(core.clj:92)
at swank.core$eval_for_emacs.invoke(core.clj:239)
at clojure.lang.Var.invoke(Var.java:409)
at clojure.lang.AFn.applyToHelper(AFn.java:167)
at clojure.lang.Var.applyTo(Var.java:518)
at clojure.core$apply.invoke(core.clj:600)
at swank.core$eval_from_control.invoke(core.clj:99)
at swank.core$eval_loop.invoke(core.clj:104)
at swank.core$spawn_repl_thread$fn_527$fn_528.invoke(core.clj:309)
at clojure.lang.AFn.applyToHelper(AFn.java:159)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:600)
at swank.core$spawn_repl_thread$fn__527.doInvoke(core.clj:306)
at clojure.lang.RestFn.invoke(RestFn.java:397)
at clojure.lang.AFn.run(AFn.java:24)
at java.lang.Thread.run(Thread.java:679)
Caused by: java.io.FileNotFoundException: http://localhost:3000
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:532)
at sun.net.www.protocol.http.HttpURLConnection$6.run(HttpURLConnection.java:1458)
at java.security.AccessController.doPrivileged(Native Method)
at sun.net.www.protocol.http.HttpURLConnection.getChainedException(HttpURLConnection.java:1452)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1106)
at javax.swing.JEditorPane.getStream(JEditorPane.java:827)
at javax.swing.JEditorPane.setPage(JEditorPane.java:433)
at javax.swing.JEditorPane.setPage(JEditorPane.java:939)
at javax.swing.JEditorPane.<init>(JEditorPane.java:273)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:532)
at clojure.lang.Reflector.invokeConstructor(Reflector.java:183)
... 32 more
Caused by: java.io.FileNotFoundException: http://localhost:3000
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1401)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:397)
at javax.swing.JEditorPane.getStream(JEditorPane.java:792)
... 40 more

It works with urls like http://google.com:80, so probably the problem is in the combination of one-segment domen and port.

Note: I use Ubuntu 11.10 with Chromium as a default browser. I'm not sure why browse-url fails to open urls via standart browser. Should I create another issue for that or is it a java problem?



 Comments   
Comment by Andy Fingerhut [ 29/Feb/12 1:38 PM ]

Dmitri: CLJ-896 has a patch that changes browse-url to use the command line tool xdg-open instead of Java Swing. If the command:

xdg-open http://localhost:3000

works on your system from the command line, then that patch will probably also make (browse-url "http://localhost:3000") work, too.

I tried (browse-url "http://localhost:3000") on an Ubuntu 10.04 LTS system using Sun/Oracle's JVM 1.6.0_26, and it worked. Which JVM are you using?

Comment by Dmitri Naumov [ 12/Mar/12 1:09 PM ]

I tried it again and now I can't reproduce it - browse-url works as expected and Swing gui also works when launched manually. I use openjdk, so maybe it was a problem with its classes? Anyway, the issue should be closed.
Sorry for bothering you.

Comment by Andy Fingerhut [ 12/Mar/12 1:17 PM ]

I'm not sure if this should be marked with a Resolution of Declined or Completed, if the issue cannot be reproduced. I'm picking Declined for this change. Feel free to change it if I've picked incorrectly.

Comment by Dmitri Naumov [ 12/Mar/12 1:24 PM ]

Yeah, I also think Declined is correct.





[CLJ-907] records do not enforce type hints Created: 08/Jan/12  Updated: 01/Mar/13  Resolved: 27/Nov/12

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

Type: Defect Priority: Major
Reporter: Chip Salzenberg Assignee: Unassigned
Resolution: Declined Votes: 1
Labels: None


 Description   

Specify a record with a field as say ^String, but the constructor won't throw if you pass in a non-String.



 Comments   
Comment by Alan Malloy [ 10/Jan/12 4:59 PM ]

I doubt there's any desire to change this. Records only support typehints to enable performant storage of primitive types like ints, not to provide static typing in general. An Object is stored the same way as a String, so there's no need to pay attention to that typehint.

Functions behave the same way: ((fn [^String x] x) :test) works just fine. Only if you use a member method of the hinted type (such as .substring in this example) is an exception thrown then the compiler casts to String in order to call the method.

Comment by Chip Salzenberg [ 10/Jan/12 5:08 PM ]

I don't understand how you get from "this is how it is" to "this is how it is meant to be." The compiler can do a better job if the underlying field is properly typed: Type errors can be caught sooner, and cast operations can be omitted on use. This is a worthy enhancement.

Comment by Timothy Baldridge [ 27/Nov/12 1:52 PM ]

Alan is correct, the reason type hints exist is to reduce reflection and to allow for the unboxing of primitives. String is not a primitive and therefore type-hinting it only reduces the amount of reflection performed.

It has always been Rich's policy that any type systems used in Clojure should not throw compile time errors, but instead should only enhance the performance of existing code. (see the implementation of Typed Clojure for more info on this).

Closing this issue, as it is by design.

Comment by Timothy Baldridge [ 27/Nov/12 1:52 PM ]

By design.





[CLJ-906] defrecord with protocol implementation fails when field and method names collide Created: 01/Jan/12  Updated: 01/Mar/13  Resolved: 27/Nov/12

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

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


 Description   

The following produces a NullPointerException:

(defprotocol Foo (act [this]))
(defrecord Fred []
Foo
(act [this] (println "done.")))
(defrecord Bar [act] ;; <<<<<======= Field name is the same as method name.
Foo
(act [this] (act (Fred.)))) ;; <<<<<====== Behaves as (nil (Fred.))
(act (Bar. nil))

Produces:
Exception in thread "main" java.lang.NullPointerException
at protocol.Bar.act(protocol.clj:8)
at protocol$eval66.invoke(protocol.clj:9)
at clojure.lang.Compiler.eval(Compiler.java:6465)
at clojure.lang.Compiler.load(Compiler.java:6902)
at clojure.lang.Compiler.loadFile(Compiler.java:6863)
at clojure.main$load_script.invoke(main.clj:282)
at clojure.main$script_opt.invoke(main.clj:342)
at clojure.main$main.doInvoke(main.clj:426)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.lang.Var.invoke(Var.java:401)
at clojure.lang.AFn.applyToHelper(AFn.java:161)
at clojure.lang.Var.applyTo(Var.java:518)
at clojure.main.main(main.java:37)

The following works as expected:

(defprotocol Foo (act [this]))
(defrecord Fred []
Foo
(act [this] (println "done.")))
(defrecord Bar [x] ; <<== Field name is the DIFFERENT than method name
Foo
(act [this] (act (Fred.))))
(act (Bar. [1 2 3]))

Produces:
"done."

The following also works:

(defprotocol Foo (act [this]))
(defrecord Fred [])
(defrecord Bar [act]) ; <<== Field name is the same as method name
(extend-protocol Foo
Fred
(act [this] (println "done."))
Bar
(act [this] (act (Fred.))))
(act (Bar. [1 2 3]))



 Comments   
Comment by Timothy Baldridge [ 27/Nov/12 2:03 PM ]

The thing to remember here is that protocol functions are not (only) methods on a class, they are functions global to the namespace. So notice the subtle difference here:

user=> (defprotocol Foo (act [this]))
Foo
user=> (defrecord Fred [act] Foo (act [this] (act this)))
user.Fred
user=> (Fred. 42)
#user.Fred{:act 42}
user=> (act (Fred. 42))
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn user.Fred (NO_SOURCE_FILE:1)

user=> (defrecord Fred [act] Foo (act [this] (user/act this)))
user.Fred
user=> (act (Fred. 42))
StackOverflowError user.Fred (NO_SOURCE_FILE:1)

So, it you want to access the data, you can use "act" directly, if you want to recursively call act (the protocol function), you can use recur, or the fully qualified name. Also, since these are records we're talking about, the following also works:

user=> (defrecord Fred [act] Foo (act [this] (:act this)))
user.Fred
user=> (act (Fred. 42))
42

Comment by Timothy Baldridge [ 27/Nov/12 2:07 PM ]

Declined since this is not really a bug. There is a work-around and no obvious solution to the more general problem of defrecord name collisions. If this still bugs you, please feel free to bring it up on clojure-dev, and we'll open a new ticket once a discussion has been had.





[CLJ-901] implementation of doc macro in core.repl incorrect for special names... add one character to fix Created: 23/Dec/11  Updated: 01/Mar/13  Resolved: 28/Feb/12

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

Type: Defect Priority: Trivial
Reporter: Daniel Eklund Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

In the implementation of the doc macro in core.repl, the line:
(if-let [special-name ('{& fn catch try finally try} name)]
contains:{& fn catch try finally try} which is a hashmap.

It should be a set, and the line should read:
(if-let special-name ('#{& fn catch try finally try} name)

To see the bug at work:
user> (doc &)
-------------------------
clojure.core/fn
(fn name? [params*] exprs*)
(fn name? ([params*] exprs*) +)
Special Form
params => positional-params* , or positional-params* & next-param
positional-param => binding-form
next-param => binding-form
name => symbol

Defines a function

Please see http://clojure.org/special_forms#fn



 Comments   
Comment by Andy Fingerhut [ 17/Feb/12 12:06 AM ]

Daniel, I'm pretty sure it is intended to be a map, not a set. The goal is to show the same documentation for try whether you ask for the documentation of try, catch, or finally. Also, to show the documentation for fn if you ask for the documentation of &, since that symbol is only useful in arg lists in fn (or let). They could have put multiple entries in special-doc-map and not had that little map inside doc, but that little map avoided the need for such duplication.

Comment by Daniel Eklund [ 28/Feb/12 7:34 PM ]

100% agree. It was an incorrect report on my part. Thanks for clearing it up.

Comment by Andy Fingerhut [ 28/Feb/12 8:04 PM ]

Daniel asked me to change the state of the ticket, since he could not see how to (perhaps insufficient privileges). Not sure if it should be marked Closed or Resolved, so I'm picking Resolved.





[CLJ-894] Better reduce performance Created: 09/Dec/11  Updated: 13/Apr/12  Resolved: 13/Apr/12

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

Type: Enhancement Priority: Minor
Reporter: Mike Anderson Assignee: Unassigned
Resolution: Declined Votes: 2
Labels: None

Attachments: Text File clj-894-better-reduce-performance-patch2.txt    
Patch: Code and Test

 Description   

Currently reduce is implemented in Clojure by calling seq on a collection. Construction of an entire new seq is an unnecessary and expensive operation, particularly for the key persistent collections (map, set and vector suffer - list is not a problem because it implements ISeq directly for free).

This patch proposes to improve this by doing the following:
1. Make use of a Java interface for reducible collections (IReduce)
2. Make persistent collections support implementations of reduce
directly by implementing IReduce
3. Modify the internal-reduce protocol to operate on concrete
collections (not just seqs) and make use of IReduce implementations
where available
4. Change reduce itself to call internal-reduce directly rather than
calling seq first



 Comments   
Comment by Mike Anderson [ 09/Dec/11 3:58 AM ]

Link to initial discussion on Clojure Dev Google Group

http://groups.google.com/group/clojure-dev/browse_frm/thread/bdab332c4e47721f?hl=en

Comment by Mike Anderson [ 09/Dec/11 3:59 AM ]

Link to experimental implementation on GitHub:

https://github.com/mikera/clojure/tree/better-reduce

Comment by Mike Anderson [ 09/Dec/11 4:00 AM ]

Performance testing shows approx 2x speedup for relevant operations:

Clojure 1.3.0
(def ms (zipmap (range 100) (range 100)))
#'user/ms
user=> (dotimes [i 10] (time (dotimes [i 100000] (reduce (fn [acc [k
v]] (+ acc v)) 0 ms))))
"Elapsed time: 646.512414 msecs"
"Elapsed time: 553.264593 msecs"
"Elapsed time: 544.999672 msecs"
"Elapsed time: 510.606868 msecs"
"Elapsed time: 513.192451 msecs"
"Elapsed time: 537.665664 msecs"
"Elapsed time: 524.166514 msecs"
"Elapsed time: 512.966964 msecs"
"Elapsed time: 501.677219 msecs"
"Elapsed time: 496.379194 msecs"

Clojure 1.4.0-alpha2
user=> (def ms (zipmap (range 100) (range 100)))
#'user/ms
user=> (dotimes [i 10] (time (dotimes [i 100000] (reduce (fn [acc [k
v]] (+ acc v)) 0 ms))))
"Elapsed time: 548.822683 msecs"
"Elapsed time: 469.275299 msecs"
"Elapsed time: 464.742096 msecs"
"Elapsed time: 443.500129 msecs"
"Elapsed time: 431.272138 msecs"
"Elapsed time: 430.514649 msecs"
"Elapsed time: 432.753752 msecs"
"Elapsed time: 431.195876 msecs"
"Elapsed time: 435.254274 msecs"
"Elapsed time: 433.516375 msecs"

Clojure 1.4.0 snapshot (with better reduce modifications)
(def ms (zipmap (range 100) (range 100)))
#'user/ms
user=> (dotimes [i 10] (time (dotimes [i 100000] (reduce (fn [acc [k
v]] (+ acc v)) 0 ms))))
"Elapsed time: 202.29696 msecs"
"Elapsed time: 186.589505 msecs"
"Elapsed time: 179.691805 msecs"
"Elapsed time: 184.191644 msecs"
"Elapsed time: 183.265131 msecs"
"Elapsed time: 180.162578 msecs"
"Elapsed time: 182.323219 msecs"
"Elapsed time: 181.810649 msecs"
"Elapsed time: 182.896285 msecs"
"Elapsed time: 187.30153 msecs"

Comment by Mike Anderson [ 19/Feb/12 4:03 AM ]

better_reduce branch now updated to merge in the latest changes from the clojure/clojure master branch.

Comment by Brian Taylor [ 19/Feb/12 1:29 PM ]

Reviewers:

To make this change easier to review (and for a cleaner history), I mashed all of the commits that make up this change together and rebased that onto the latest from clojure/clojure master.

https://github.com/netguy204/clojure/tree/better-reduce
https://github.com/netguy204/clojure/commit/b262a69c32d26bb6f3c5ba711310361d77609a22

Hope it helps.

Comment by Mike Anderson [ 19/Feb/12 6:24 PM ]

Awesome, thanks Brian! I must admit that my git-fu is not yet good enough to do things like this, so your help is much appreciated!

Comment by Andy Fingerhut [ 23/Feb/12 1:52 AM ]

clj-894-better-reduce-performance-patch1.txt was created from pulling Brian Taylor's Clojure github repo, creating a diff of it, applying it to latest master as of Feb 22, 2012, and making a properly formatted patch from it. It has only a single commit, and has Mike Anderson's name and email address in it, along with a date of 4 Dec 2011, when it appears he made his final commit of this work. It compiles and tests cleanly, and I have run Mike's timing experiments and seen similar speed improvements.

No docstrings need changing that I can think of. Mike and I have both signed CAs. I don't see Brian Taylor's name on the list of those who signed a CA, but as long as the patch contains only code that Mike wrote, it should be clean. Patch status is "Code and Test".

Comment by Andy Fingerhut [ 23/Feb/12 2:00 AM ]

Correcting Mike's name and email address in patch.

Comment by Brian Taylor [ 23/Feb/12 5:08 AM ]

The patch contains only code that Mike wrote.

Comment by Mike Anderson [ 23/Feb/12 7:32 AM ]

Thanks guys I've reviewed the patch and can confirm that it looks like exactly the changes I intended to make. I am happy for them to be committed as per my signed CA.

Comment by Rich Hickey [ 13/Apr/12 8:05 AM ]

Similar objective now achieved via a protocol:
https://github.com/clojure/clojure/commit/1f90942690d5395330347cb31fdb3d69cea1ec56





[CLJ-883] Clojure head holding bug Created: 27/Nov/11  Updated: 01/Mar/13  Resolved: 27/Nov/12

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

Type: Defect Priority: Major
Reporter: Gerrard McNulty Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

java 6 jdk on linux, jre 6 on windows 7



 Description   

I've a head holding problem that I believe is a bug in clojure 1.3. I
wrote the following function to split a a lazy seq of strings across
files of x size:

(defn split-file
 ([path strs size]
    (trampoline split-file path (seq strs) size 0))
 ([path strs size part]
    (with-open [f (clojure.java.io/writer (str path "." part))]
      (loop [written 0, ss strs]
        (when ss
          (if (>= written size)
            #(split-file path ss size (inc part))
            (let [s (first ss)]
              (.write f s)
              (recur (+ written (.length s)) (next ss)))))))))

If I call the 3 arg version of the function:
(split-file "foo" (repeat 100000000 "blah blah blah") 100000000)

I see memory usage increases as I'm writing each file with the usual
gc slow down, then memory usage goes back down again as I get to a new
split file.

Memory usage is fine if I call the 4 arg version (which only writes
one part of the split file):
(split-file "foo" (repeat 100000000 "blah blah blah") 100000000 0)

I can also avoid the head holding problem by removing trampoline and
recursively calling split-file directly, but then those recursive
calls use up stack and don't close files until all calls complete



 Comments   
Comment by a_strange_guy [ 16/Jan/12 4:15 AM ]

There is actually no problem with head retention in your code.
It's zust the garbage collector that doesn't collect the seq right away. If there were problems, then you would get a OutOfMemoryError pretty fast.

compare
(split-file "foo" (repeat 100000000 "blah blah blah") 100000000 0)
with
(doall (repeat 100000000 "blah blah blah"))
to see the difference

Comment by Timothy Baldridge [ 27/Nov/12 2:29 PM ]

Closing due to lack of reproducible tests. On my system I actually saw memory usage not move at all when I ran the demo code, and at one point the GC kicked in and the memory usage went down a bit.





[CLJ-877] contains? is broken for vectors Created: 14/Nov/11  Updated: 14/Nov/11  Resolved: 14/Nov/11

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

Type: Defect Priority: Critical
Reporter: Jeff Palmucci Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

OSX Lion



 Description   

contains? returns the wrong result for the last item in a vector:

user> (map #(contains? [1 2 3 4] %) [1 2 3 4])
(true true true false)



 Comments   
Comment by Steve Miner [ 14/Nov/11 12:41 PM ]

This is not a bug. Check the doc – contains? refers to the keys of the collection, not the values. For a vector, the "keys" are the indices.

user=> (map #(contains? [10 20 30 40] %) (range 4))
(true true true true)

Comment by Ben Smith-Mannschott [ 14/Nov/11 12:45 PM ]

This is a (common) misusing of contains?. Perhaps it would have been better if contains? had been named contains-key?, but that ship has sailed.

Usage: (contains? coll key)

Returns true if key is present in the given collection, otherwise returns false. Note that for numerically indexed collections like vectors and Java arrays, this tests if the numeric key is within the range of indexes. 'contains?' operates constant or logarithmic time; it will not perform a linear search for a value. See also 'some'.

A vector of length 4 has four keys (indexes): 0, 1, 2, 3, which is why your example is returning (true true true false).

To get the behavior your are expecting from contains?, use some:

Usage: (some pred coll)

Returns the first logical true value of (pred x) for any x in coll, else nil. One common idiom is to use a set as pred, for example this will return :fred if :fred is in the sequence, otherwise nil: (some #{:fred} coll)

user> (map #(some #{%} [1 2 3 4]) [1 2 3 4])
(1 2 3 4) ; all of which are truthy

If you prefer booleans, you could do something like this:

user> (map (comp boolean #(some #{%} [1 2 3 4])) [1 2 3 4])
(true true true true)




[CLJ-875] Clojure's seq, keys, and vals can produce inconsistent values on strange iterators (e.g., IdentityHashMap) Created: 11/Nov/11  Updated: 02/Dec/11  Resolved: 02/Dec/11

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: Jason Wolfe Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

user> clojure-version
{:major 1, :minor 4, :incremental 0, :qualifier "alpha1"}
user> (def x (keys (java.util.IdentityHashMap. {:a true :b true})))
#'user/x
user> x
(:b :a)
user> x
(:a :a)

As discussed on the mailing list, it's not clear exactly whose fault this is:
https://groups.google.com/group/clojure-dev/browse_frm/thread/bed458abf8e266aa#
given that the javadocs for iterators and entrySet dont' seem to require (or mention at all) whether each .next() must return a unique value.

keys and vals could be fixed by using keySet and values rather than entrySet, at least in this case, but this would not help for seq.



 Comments   
Comment by Stuart Halloway [ 02/Dec/11 9:28 AM ]

The powers that be acknowledge that this is Java's fault: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6312706





[CLJ-869] Macro auto-gensym in let not visible after a nested unquote/syntax-quote Created: 03/Nov/11  Updated: 02/Dec/11  Resolved: 02/Dec/11

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

Type: Defect Priority: Minor
Reporter: Alexander Taggart Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

See the following simplified example:

user=> (defmacro foo [flag]
        `(let [a# 1]
          ~(if flag
             `(println a#))))
#'user/foo
user=> (foo false)
nil
user=> (foo true)
java.lang.Exception: Unable to resolve symbol: a__574__auto__ in this context (NO_SOURCE_FILE:6)
user=> (macroexpand-1 '(foo true))
(clojure.core/let [a__575__auto__ 1] (clojure.core/println a__574__auto__))


 Comments   
Comment by Rich Hickey [ 02/Dec/11 10:42 AM ]

This is not a bug





[CLJ-851] Type-hinting a var with primitive array pseudo-class results in IllegalArgumentException when the var is used as an arg Created: 10/Oct/11  Updated: 01/Mar/13  Resolved: 09/Nov/12

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

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

Attachments: Text File CLJ-851-test.patch    

 Description   

Example:

user=> (def ^longs la (long-array 0))
#'user/la
user=> (defn foo [] (alength la))
CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: clojure.core$longs@32dfcb47, compiling:(NO_SOURCE_PATH:9) 

Workaround: use the class string, e.g., ^"[J"



 Comments   
Comment by Ben Smith-Mannschott [ 15/Oct/11 11:40 AM ]

CLJ-851-test.patch

Provides a test to reproduce this issue, as well as a test that shows that the workaround of using ^"[J" as type hint works correctly.

Comment by Ben Smith-Mannschott [ 16/Oct/11 2:23 AM ]

OK, I see the problem here: longs plays two roles in Clojure:

  1. As an unqualified symbol, it's taken to mean long[].class.
  2. clojure.core/longs is a definline function which calls clojure.lang.Numbers.longs(...).

The example in the issue description is expecting the first interpretation, but what we're actually getting is the second interpretation, i.e. the :tag is not a symbol longs, but rather a function (an instance of the class clojure.core$longs, to be precise).

So, it's as if we'd written this:

(def ^{:tag clojure.core/longs} la (long-array 0))

When really, we meant this:

(def ^{:tag 'longs} la (long-array 0))

While the behavior described by this issue is confusing, it looks to me like it's not a bug.

Comment by Stuart Sierra [ 09/Nov/12 8:39 AM ]

Correct, this is not a bug. The reader will attempt to resolve symbols in the ^tag metadata form, so that it can resolve unqualified class names.





[CLJ-848] defn :or form does not warn you if you provide a vector instead of a map Created: 06/Oct/11  Updated: 26/Jul/13  Resolved: 25/Oct/11

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

Type: Enhancement Priority: Trivial
Reporter: Dave Barker Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

Clojure 1.3, Emacs 23, OSX Lion



 Description   

I had a problem defining a function today, I passed :or a vector instead of a map - everything seemed to work fine but later on I got a really puzzling "Null pointer exception".

raek helped me debug the problem and suggested opening this ticket. I think it would be useful if an exception was thrown on the :or line unless it's given a map.

Here are some examples

(defn broken-example [{:keys [i processor]
:or [processor identity]}]
(processor i))

(defn working-example [{:keys [i processor]
:or {processor identity}}]
(processor i))

(working-example {:i 1})
=> 1
(broken-example {:i 1})
=> Null pointer exception

Cheers, Dave.



 Comments   
Comment by Dave Barker [ 06/Oct/11 6:51 AM ]

Apologies, I meant to tag this as a minor issue instead of a major one!

Comment by Stuart Halloway [ 07/Oct/11 9:39 AM ]

Since vectors are associative, maybe using vectors for :or should just work?

(let [{noun 0
       verb 1
       obj 2
       :or [:n :v :o]}
      [:code :is]] obj)
Comment by Stuart Halloway [ 25/Oct/11 6:04 PM ]

Closing this until someone wants to make a principled argument for what should happen (see my previous comment)





[CLJ-841] Unable to download clojure using wget. Wget seems to be blocked... Created: 23/Sep/11  Updated: 01/Mar/13  Resolved: 08/May/12

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

Type: Defect Priority: Minor
Reporter: Thomas Dziedzic Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

wget http://repo1.maven.org/maven2/org/clojure/clojure/1.3.0/clojure-1.3.0.zip
Gives me a 403, same with other people.

When I add -U YUBLOCKWGET to the command, it downloads the file successfully.

This "feature" needs to be removed.

Also, I encountered this while trying to package clojure 1.3. So no, I can't just use a browser



 Comments   
Comment by Jim Blomo [ 08/May/12 11:44 PM ]

This is actually a policy of maven.org/sonatype: https://issues.sonatype.org/browse/MVNCENTRAL-119 , not Clojure.





[CLJ-826] Include drop, take, butlast from clojure.contrib.string (1.2) in clojure.string 1.3 Created: 08/Aug/11  Updated: 02/Dec/11  Resolved: 02/Dec/11

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

Type: Enhancement Priority: Minor
Reporter: Arthur Edelstein Assignee: Unassigned
Resolution: Declined Votes: 3
Labels: None

Attachments: File clj-826-add-take-drop-butlast.diff     File clj-826-add-take-drop-butlast-v3.diff     File clj-826-add-take-drop-butlast-with-versions.diff    
Patch: Code and Test
Waiting On: Matthew Lee Hinman

 Description   

From clojure.contrib.string 1.2, I have found myself