[ANN] Clojure 1.7.0-beta1 released

1,284 views
Skip to first unread message

Alex Miller

unread,
Apr 10, 2015, 3:26:30 PM4/10/15
to clo...@googlegroups.com, cloju...@googlegroups.com, clojur...@googlegroups.com
Clojure 1.7.0-beta1 is now available.

Try it via
- Leiningen: [org.clojure/clojure "1.7.0-beta1"]

Regression fixes since 1.7.0-alpha6:

1) CLJ-1692 - make iterate match prior laziness
2) CLJ-1694 - make cycle match prior laziness
3) CLJ-1685 - correctly handle :eof option in read and read-string

One faster sequence and reduce path that didn't quite make it into alpha6 is now available - range is now faster for both the traditional sequence use case (both chunked and unchunked traversal) and the fast reduce path.

Also, since alpha6 was released, reader conditionals were ported to tools.reader and the latest ClojureScript release now supports them, so now is a great time to try them out!
 
For all changes new in beta1, see the issues marked "(beta1)" in the
full changes below.

------------------------------------------------------------
Clojure 1.7.0-beta1 has the following updates since 1.6.0:

# Changes to Clojure in Version 1.7

## 1 New and Improved Features

### 1.1 Transducers

Transducers is a new way to decouple algorithmic transformations from their
application in different contexts. Transducers are functions that transform
reducing functions to build up a "recipe" for transformation.


Many existing sequence functions now have a new arity (one fewer argument
than before). This arity will return a transducer that represents the same
logic but is independent of lazy sequence processing. Functions included are:

* conj (conjs to [])
* map
* mapcat
* filter
* remove
* take
* take-while
* drop
* drop-while
* take-nth
* replace
* partition-by
* partition-all
* keep
* keep-indexed
* map-indexed
* distinct
* interpose

Additionally some new transducer functions have been added:

* cat - concatenates the contents of each input
* de-dupe - removes consecutive duplicated values
* random-sample - returns items from coll with random probability

And this function can be used to make completing transforms:

* completing

There are also several new or modified functions that can be used to apply
transducers in different ways:

* sequence - takes a transformation and a coll and produces a lazy seq
* transduce - reduce with a transformation (eager)
* eduction - returns a reducible/iterable of applications of the transducer to items in coll. Applications are re-performed with every reduce/iterator.
* run! - run the transformation for side effects on the collection

There have been a number of internal changes to support transducers:

* volatiles - there are a new set of functions (volatile!, vswap!, vreset!, volatile?) to create and use volatile "boxes" to hold state in stateful transducers. Volatiles are faster than atoms but give up atomicity guarantees so should only be used with thread isolation.
* array iterators - added support for iterators over arrays

Some related issues addressed during development:

### 1.2 Reader Conditionals

Reader Conditionals are a new capability to support portable code that
can run on multiple Clojure platforms with only small changes. In
particular, this feature aims to support the increasingly common case
of libraries targeting both Clojure and ClojureScript.

Code intended to be common across multiple platforms should use a new
supported file extension: ".cljc". When requested to load a namespace,
the platform-specific file extension (.clj, .cljs) will be checked
prior to .cljc.

A new reader form can be used to specify "reader conditional" code in
cljc files (and *only* cljc files). Each platform defines a feature
identifying the platform (:clj, :cljs, :cljr). The reader conditional
specifies code that is read conditionally based on the feature/

Form #? takes a list of alternating feature and expression. These are
checked like cond and the selected expression is read and returned. Other
branches are unread. If no branch is selected, the reader reads nothing
(not nil, but literally as if reading ""). An optional ":default" branch
can be used as a fallthrough.

Reader conditional with 2 features and a default:

#?(:clj     Double/NaN
  :cljs    js/NaN
  :default nil)

There is also a reader conditional splicing form. The evaluated expression
should be sequential and will be spliced into the surrounded code, similar
to unqoute-splicing.

For example:

   [1 2 #?@(:clj [3 4] :cljs [5 6])]

This form would read as [1 2 3 4] on Clojure, [1 2 5 6] on ClojureScript,
and [1 2] on any other platform.

Additionally, the reader can now be invoked with options for the features
to use and how to interpret reader conditionals. By default, reader conditionals
are not allowed, but that can be turned on, or a "preserve" mode can be used to
preserve all branches (most likely useful for tooling or source transforms).

In the preserve mode, the reader conditional itself and any tagged literals
within the unselected branches are returned as tagged literal data.

For more information, see:


### 1.3 Keyword and Symbol Construction

In response to issues raised in [CLJ-1439](http://dev.clojure.org/jira/browse/CLJ-1439),
several changes have been made in symbol and keyword construction:

1) The main bottleneck in construction of symbols (which also occurs inside keywords) was
interning of the name and namespace strings. This interning has been removed, resulting
in a performance increase.

2) Keywords are cached and keyword construction includes a cache check. A change was made
to only clear the cache reference queue when there is a cache miss.

### 1.4 Warn on Boxed Math

One source of performance issues is the (unintended) use of arithmetic operations on
boxed numbers. To make detecting the presence of boxed math easier, a warning will now
be emitted about boxed math if \*unchecked-math* is set to :warn-on-boxed (any truthy
value will enable unchecked-math, only this specific value enables the warning).

Example use:

    user> (defn plus-2 [x] (+ x 2))  ;; no warning, but boxed
#'user/plus-2
    user> (set! *unchecked-math* :warn-on-boxed)
true
    user> (defn plus-2 [x] (+ x 2)) ;; now we see a warning
    Boxed math warning, NO_SOURCE_PATH:10:18 - call: public static java.lang.Number
clojure.lang.Numbers.unchecked_add(java.lang.Object,long).
    #'user/plus-2
user> (defn plus-2 [^long x] (+ x 2)) ;; use a hint to avoid boxing
#'user/plus-2


### 1.5 update - like update-in for first level

`update` is a new function that is like update-in specifically for first-level keys:

    (update m k f args...)

Example use:

    user> (update {:a 1} :a inc)
{:a 2}
user> (update {:a 1} :a + 2)
{:a 3}
user> (update {} :a identity)  ;; missing returns nil
{:a nil}


### 1.6 Faster reduce and iterator paths

Several important Clojure functions now return sequences that also
contain fast reduce() (or in some cases iterator()) paths. In many
cases, the new implementations are also faster for lazy sequences

* repeat - now implements IReduce
* cycle - implements IReduceInit
* iterate - implements IReduceInit
* range - implements IReduce, specialized case handles common case of all longs
* keys - iterates directly over the keys of a map, without seq or MapEntry allocation
* vals - iterates directly over the vals of a map, without seq or MapEntry allocation
* iterator-seq - creates a chunked sequence when previously it was unchunked

Additionally, hash-maps and hash-sets now provide iterators that walk
the data structure directly rather than via a sequence.

A new interface (IMapIterable) for direct key and val iterators on maps
was added. External data structures can use this interface to provide
direct key and val iterators via keys and vals.

These enhancements are particularly effective when used
in tandem with transducers via transduce, sequence, into, and
eduction.


### 1.7 Printing as data

There have been enhancements in how the REPL prints values without a
print-method, specifically Throwable and the fallthrough Object case.
Both cases now print in a tagged literal data form that can be read
by the reader.

Unhandled objects print with the class, hash code, and toString:

user=> *ns*
#object[clojure.lang.Namespace 0x55aa628 "user"]

Thrown exceptions will still be printed in the normal way by the default
REPL but printing them to a stream will show a different form:

user=> (/ 1 0)
ArithmeticException Divide by zero  clojure.lang.Numbers.divide (Numbers.java:158)
user=> (println *e)
#error{:cause Divide by zero,
  :via [{:type java.lang.ArithmeticException,
     :message Divide by zero,
 :at [clojure.lang.Numbers divide Numbers.java 158]}],
  :trace
    [[clojure.lang.Numbers divide Numbers.java 158]
 [clojure.lang.Numbers divide Numbers.java 3808]
 [user$eval5 invoke NO_SOURCE_FILE 3]
 ;; elided ...
 ]]}

## 2 Enhancements

### 2.1 Error messages

  Invalid defrecord results in exception attributed to consuming ns instead of defrecord ns
  Report line,column, and source in defmacro errors
  Give more specific hint if namespace with "-" not found to check file uses "_"

### 2.2 Documentation strings

  clojure.java.io/input-stream has incorrect docstring
  Fix typo in gen-class doc-string
  Fix typo in filterv example
  Fix typo in defmulti docstring
  Fix typo in deftype docstring
  Fix typo in clojure.main usage

### 2.3 Performance

  Improve performance of partial with more unrolling
  clojure.core/set should use transients for better performance
  Cache unknown multimethod value default dispatch
  Reduce compile times by avoiding unnecessary calls to Class.forName()
  vec is now faster on almost all inputs
  set is now faster on almost all inputs
  Fixed reflection call in variadic vector-of constructor

### 2.4 Other enhancements

  Improve apropos to show some indication of namespace of symbols found
  Hints don't work with #() form of function
  Removes owner-thread check from transients - this check was preventing some valid usage of transients in core.async where a transient is created on one thread and then used again in another pooled thread (while still maintaining thread isolation).
  Extracted IAtom interface implemented by Atom.
  Don't initialize classes when importing them
  Class name clash between top-level functions and defn'ed ones
  Update to latest test.generative and add dependency on test.check
  vec now works with things that only implement Iterable or IReduceInit
  set now works with things that only implement Iterable or IReduceInit
  PersistentList/creator doesn't handle ArraySeqs correctly
  Clean up unused paths in InternalReduce
  Add setLineNumber() to LineNumberingPushbackReader
  Change test to avoid using hard-coded socket port
  Change reduce tests to better catch reduce without init bugs

## 3 Bug Fixes

  Reduce broken on some primitive vectors
  Equality bug on records created with nested calls to map->record
  Unable to set compiler options via system properties except for AOT compilation
  NPE when AOTing overrided clojure.core functions
  reductions does not check for reduced value
  Using def with metadata {:type :anything} throws ClassCastException during printing
  Error when calling primitive functions with destructuring in the arg vector
  Piping seque into seque can deadlock
  <= is incorrect when args include Double/NaN
  Make cached string value of Keyword and Symbol transient
  clojure.core/bean should implement Iterable
  Make refer of Clojure core function not throw exception on reload
  LazySeq equals() should not use equiv() logic
  into (and other fns that rely on reduce) require only IReduceInit
  PersistentVector now directly implements reduce without init
  Transient collections should guarantee thread visibility
  Some IReduce/IReduceInit implementors don't respect reduced
  Clojure resolves to wrong deftype classes when AOT compiling or reloading
  Fix intermittent SeqIterator problem by removing use of this as a sentinel
  Fix regression from CLJ-1546 that broke vec on MapEntry
  Fix regression from CLJ-979 for DynamicClassLoader classloader delegation
  Fix error from AOT'ed code defining a var with a clojure.core symbol name
  Fix incorrect line number reporting for error locations
  Fix incorrect line number reporting for error locations
  Fix regression from CLJ-1546 removed PersistentVector.create(List) method
  Fix regression from CLJ-1248 (1.6) in reflection warning with literal nil argument

whodidthis

unread,
Apr 12, 2015, 4:39:15 PM4/12/15
to clo...@googlegroups.com, cloju...@googlegroups.com, clojur...@googlegroups.com
Are there any thoughts on code like this:

#_#?(:cljs (def unrelated-1 nil))

#?(:cljs (def unrelated-2 nil))

#?(:cljs (def unrelated-3 nil))

#?(:clj (def n 10))

#?(:clj (defn num [] n))
; compile on clj =>RuntimeException: Unable to resolve symbol: n

I guess it's fine if it continues to work that way but I can imagine it being a little surprising from time to time heh

Leon Grapenthin

unread,
Apr 13, 2015, 6:02:24 AM4/13/15
to clojur...@googlegroups.com, clo...@googlegroups.com, cloju...@googlegroups.com
Why would that be fine?

Robin Heggelund Hansen

unread,
Apr 13, 2015, 6:37:54 AM4/13/15
to clo...@googlegroups.com, cloju...@googlegroups.com, clojur...@googlegroups.com
Hmm... In Clojurescript you can do the following

(try
  ;; throw something
  (catch :default e
     e))

When I try the same thing in Clojure, it seems to not be supported. Is there any plans to support this syntax in Clojure 1.7?

David Nolen

unread,
Apr 13, 2015, 6:45:35 AM4/13/15
to clojur...@googlegroups.com, clojure, cloju...@googlegroups.com
The only reason :default exists is because *anything* in JavaScript can be thrown and there needs to be some way to catch non-Error derived values. This is not the case for Java of course. :default could probably be aliased to Throwable, but in the meantime differences like this are now handleable via conditional reading.

David

--
Note that posts from new members are moderated - please be patient with your first post.
---
You received this message because you are subscribed to the Google Groups "ClojureScript" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojurescrip...@googlegroups.com.
To post to this group, send email to clojur...@googlegroups.com.
Visit this group at http://groups.google.com/group/clojurescript.

Robin Heggelund Hansen

unread,
Apr 13, 2015, 7:26:24 AM4/13/15
to clo...@googlegroups.com, clojur...@googlegroups.com, cloju...@googlegroups.com
Ahh ok, makes sense.

Alex Miller

unread,
Apr 13, 2015, 9:48:28 AM4/13/15
to clo...@googlegroups.com, cloju...@googlegroups.com, clojur...@googlegroups.com
I think what you're seeing here makes sense.


On Sunday, April 12, 2015 at 3:39:15 PM UTC-5, whodidthis wrote:
Are there any thoughts on code like this:

#_

This says to ignore the next read form....
 
#?(:cljs (def unrelated-1 nil))

This evaluates to *nothing*, ie nothing is read, so it is not ignored by the #_.
 
#?(:cljs (def unrelated-2 nil))
#?(:cljs (def unrelated-3 nil))

These also read as *nothing*.
 
#?(:clj (def n 10))

This *is* read, but ignored per the prior #_ 

#?(:clj (defn num [] n))
; compile on clj =>RuntimeException: Unable to resolve symbol: n

And then this makes sense.
 

I guess it's fine if it continues to work that way but I can imagine it being a little surprising from time to time heh

Conditional reading is definitely something to be careful about - I think in this case you are combining two types of conditional reading so be doubly careful. :) 

To get the effect you want in this, using #_ *inside* the reader conditional would work:

#?(:cljs #_(def unrelated-1 nil))

 

Alex Miller

unread,
Apr 13, 2015, 9:57:57 AM4/13/15
to clo...@googlegroups.com, clojur...@googlegroups.com, cloju...@googlegroups.com
There is a ticket to consider a portable solution to this issue:

Daniel Kersten

unread,
Apr 13, 2015, 11:15:20 AM4/13/15
to clojur...@googlegroups.com, clo...@googlegroups.com, cloju...@googlegroups.com
Ouch! But that actually makes a lot of sense.

whodidthis

unread,
Apr 13, 2015, 12:17:47 PM4/13/15
to clo...@googlegroups.com, cloju...@googlegroups.com, clojur...@googlegroups.com
Sounds like you guys have it figured out; conditional reading forms cannot be ignored, only their results.

Just wanted to make sure, had some bad times with it heh

whodidthis

unread,
Apr 13, 2015, 3:38:01 PM4/13/15
to clo...@googlegroups.com, cloju...@googlegroups.com, clojur...@googlegroups.com


On Monday, April 13, 2015 at 4:48:28 PM UTC+3, Alex Miller wrote:
Sorry, back to this stuff again. I tried using discard inside but 

#?(:clj #_'whatever)

just throws

CompilerException java.lang.RuntimeException: read-cond starting on line 32 requires an even number of forms"

when compiling on clojure.

Would be nice to have a way to ignore reader conditional forms or the thingie things inside but there does not seem to be an easy way.

Michał Marczyk

unread,
Apr 13, 2015, 3:43:36 PM4/13/15
to clojur...@googlegroups.com, clojure, cloju...@googlegroups.com
Just noticed that I sent my previous email to clojure-dev only – reposting to all groups involved:

On 13 April 2015 at 16:25, Michał Marczyk <michal....@gmail.com> wrote:
> On 13 April 2015 at 15:48, Alex Miller <al...@puredanger.com> wrote:
> To get the effect you want in this, using #_ *inside* the reader conditional would work:
> #?(:cljs #_(def unrelated-1 nil))
> Actually this doesn't work because of the cond-like structure of #? conditionals:
> user=> (read-string {:read-cond :allow} "#?(:clj #_foo) bar")
> RuntimeException read-cond requires an even number of forms.  clojure.lang.Util.runtimeException (Util.java:221)

To this I would add that it is possible to say

Clojure 1.7.0-beta1
user=> (read-string {:read-cond :allow} "#?(#_#_:clj foo) bar")
bar

taking advantage of the nice "stacking" property of #_ (which follows from the recursive nature of the reader in the same way that the original surprising case does).

Cheers,
Michał


--
Note that posts from new members are moderated - please be patient with your first post.
---

Andy Fingerhut

unread,
Apr 13, 2015, 3:43:59 PM4/13/15
to clojur...@googlegroups.com, clo...@googlegroups.com, cloju...@googlegroups.com
Your particular example is equivalent to #?(:clj) which is illegal, for the reason given in the error message you saw.

Normal Clojure comments are far less surprising in their behavior than #_ is

I understand there can be convenience in using #_ when it works.

Andy

Sent from my iPhone
--

Andy-

unread,
Apr 13, 2015, 5:34:10 PM4/13/15
to clo...@googlegroups.com, cloju...@googlegroups.com, clojur...@googlegroups.com
Why not just change the `?' to `_'? ?
So:
#?(:cljs (def unrelated-1 nil))
then
#_(:cljs (def unrelated-1 nil))

Even saved a character :)

Geraldo Lopes de Souza

unread,
Apr 14, 2015, 7:06:49 AM4/14/15
to clo...@googlegroups.com, cloju...@googlegroups.com, clojur...@googlegroups.com
Hi, 

Fancy printing is not working.

Geraldo 
fancy-printing-not-working.png

Alex Miller

unread,
Apr 14, 2015, 1:56:44 PM4/14/15
to clo...@googlegroups.com, cloju...@googlegroups.com, clojur...@googlegroups.com
Well, we never added "fancy printing", just data printing of Throwables. :)  

But we were working on this in the context of another thing that got moved out and I have pulled that back as a separate ticket:

Haven't talked to Rich about it yet, but we'll discuss for 1.7.

Geraldo Lopes de Souza

unread,
Apr 14, 2015, 2:04:45 PM4/14/15
to clo...@googlegroups.com, cloju...@googlegroups.com, clojur...@googlegroups.com
Thank you ! We live inside our heads but we expend much time inside repl. 
This is very much appreciated!

Geraldo

Sean Corfield

unread,
Apr 16, 2015, 2:51:53 PM4/16/15
to cloju...@googlegroups.com, clo...@googlegroups.com
We deployed beta1 to production this morning. I’ll report back if we encounter any problems (generally we’ve found Clojure pre-release builds to be very stable). We were previously running alpha5 in production.

Sean

On Apr 10, 2015, at 12:25 PM, Alex Miller <al...@puredanger.com> wrote:


tcrayford

unread,
Apr 16, 2015, 10:00:16 PM4/16/15
to clo...@googlegroups.com, cloju...@googlegroups.com
I've been running beta1 in production since about 1 day after it was announced. Everything's been smooth so far :D

vra...@gmail.com

unread,
Apr 19, 2015, 3:08:42 PM4/19/15
to clo...@googlegroups.com, cloju...@googlegroups.com, clojur...@googlegroups.com
Possible issue with doseq in 1.7.0-beta1? Was working in 1.7.0-alpha5. (Found with clj-jgit)

Leiningen 2.5.1 on Java 1.8.0_31 Java HotSpot(TM) 64-Bit Server VM


Error:

#error{:cause Unable to resolve symbol: private-key in this context, :via [{:type clojure.lang.Compiler$CompilerException, :message java.lang.RuntimeException: Unable to resolve symbol: private-key in this context, compiling:(clj_jgit/porcelain.clj:481:40), :at [clojure.lang.Compiler analyze Compiler.java 6543]} {:type java.lang.RuntimeException, :message Unable to resolve symbol: private-key in this context, :at [clojure.lang.Util runtimeException Util.java 221]}], :trace [[clojure.lang.Util runtimeException Util.java 221] …


Files:

;; project.clj
(defproject abc "0.1.0-SNAPSHOT"
  :main abc.core
  :dependencies [;[org.clojure/clojure "1.7.0-alpha5"] ;;- no error
                 [org.clojure/clojure "1.7.0-beta1"]
                 [clj-jgit "0.8.4"]])

;; src/abc/core.clj
(ns abc.core
  (:require clj-jgit.porcelain))


Link to clj-jgit:

https://github.com/clj-jgit/clj-jgit/blob/7817456d55793095fd7dac5de92a0796ded25572/src/clj_jgit/porcelain.clj#L481

Ambrose Bonnaire-Sergeant

unread,
Apr 19, 2015, 3:26:02 PM4/19/15
to clojure
This looks like the minimal case:

;; beta1
user=> (let [x 1] (let [{:keys [a b] :or {a b}} {}] a))

CompilerException java.lang.RuntimeException: Unable to resolve symbol: b in this context, compiling:(/tmp/form-init3618156055290903409.clj:1:12) 

This returns nil in at least alpha1, could someone else please figure out exactly where this fails?

Thanks,
Ambrose

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com

Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Michał Marczyk

unread,
Apr 19, 2015, 3:38:14 PM4/19/15
to clojure
See inline:

On 19 April 2015 at 21:25, Ambrose Bonnaire-Sergeant <abonnair...@gmail.com> wrote:
This looks like the minimal case:

;; beta1
user=> (let [x 1] (let [{:keys [a b] :or {a b}} {}] a))

CompilerException java.lang.RuntimeException: Unable to resolve symbol: b in this context, compiling:(/tmp/form-init3618156055290903409.clj:1:12) 

This returns nil in at least alpha1, could someone else please figure out exactly where this fails?

Currently the behaviour of :keys + :or destructuring depends on the order of keys in :keys. This was discovered by Michael Blume a while ago – there's a ticket for this:


Your example form evaluates to nil with :keys [b a] in place of :keys [a b].

My proposed approach – implemented in the patch attached to the above ticket – is to disallow any situations where :or defaults depend on :keys. Clearly the example form still wouldn't compile with that patch in place, but neither would the version with :keys [b a], and I believe this is the most sensible behaviour.

Cheers,
Michał

Jason Wolfe

unread,
Apr 20, 2015, 10:57:43 PM4/20/15
to cloju...@googlegroups.com, clo...@googlegroups.com, clojur...@googlegroups.com
Just tried the beta on our test suite.  Aside from warnings from new Clojure functions now shadowed by existing functions and obvious cases of hash sensitivity, there are a couple less clear-cut cases (which likely fall into the above hash case but will require further investigation), and we also notice that (range 100) cannot be serialized because clojure.lang.LongRange$LongChunk is not Serializable -- not sure if that's intentional.  

Will follow up when we resolve the remaining test failures.  Looking forward to the release -- thanks!  

Alex Miller

unread,
Apr 21, 2015, 12:04:59 AM4/21/15
to clo...@googlegroups.com
The serializable thing is not intentional - would definitely like to fix it!

Alex Miller

unread,
Apr 21, 2015, 10:01:10 AM4/21/15
to clo...@googlegroups.com
I logged it with a patch here - thanks very much for that report. It's tricky because you have to start realizing a chunk before you can see this, so the existing serialization tests for range (which didn't do this) were working!

Geraldo Lopes de Souza

unread,
Apr 25, 2015, 3:21:16 PM4/25/15
to clo...@googlegroups.com, cloju...@googlegroups.com, clojur...@googlegroups.com
Thank you Mr. Alex Miller!

Fancy printing of exceptions is working :)

Geraldo
Reply all
Reply to author
Forward
0 new messages