Skip to content

Latest commit

 

History

History
310 lines (223 loc) · 11.7 KB

changes.md

File metadata and controls

310 lines (223 loc) · 11.7 KB

Changes to Clojure in Version 1.4

CONTENTS

 1 Deprecated and Removed Features
    1.1 Fields that Start With a Dash Can No Longer Be Accessed Using Dot Syntax
 2 New/Improved Features
    2.1 Reader Literals
    2.2 clojure.core/mapv
    2.3 clojure.core/filterv
    2.4 clojure.core/ex-info and clojure.core/ex-data
    2.5 clojure.core/reduce-kv
    2.6 clojure.core/contains? Improved
    2.7 clojure.core/min and clojure.core/max prefer NaN
    2.8 clojure.java.io/as-file and clojure.java.io/as-url Handle URL-Escaping Better
    2.9 New Dot Syntax for Record and Type Field Access
    2.10 Record Factory Methods Available Inside defrecord
    2.11 assert-args Displays Namespace and Line Number on Errors
    2.12 File and Line Number Added to Earmuff Dynamic Warning
    2.13 require Can Take a :refer Option
    2.14 *compiler-options* Var
    2.15 Improved Reporting of Invalid Characters in Unicode String Literals
    2.16 clojure.core/hash No Longer Relies on .hashCode
    2.17 Java 7 Documentation
    2.18 loadLibrary Loads Library Using System ClassLoader
    2.19 Java int is boxed as java.lang.Integer
 3 Performance Enhancements
 4 Bug Fixes

1 Deprecated and Removed Features

1.1 Record and Type Fields that Start With a Dash Can No Longer Be Accessed Using Dot Syntax

Clojure 1.4 introduces a field accessor syntax for the dot special form that aligns Clojure field lookup syntax with ClojureScript's.

For example, in Clojure 1.3, one can declare a record with a field starting with dash and access it like this:

(defrecord Bar [-a]) ;=> user.Bar
(.-a (Bar. 10)) ;=> 10

In 1.4, the above code results in IllegalArgumentException No matching field found: a for class user.Bar

However, the field may still be accessed as a keyword:

(:-a (Bar. 10)) ;=> 10

2 New and Improved Features

2.1 Reader Literals

Clojure 1.4 supports reader literals, which are data structures tagged by a symbol to denote how they will be read.

When Clojure starts, it searches for files named data_readers.clj at the root of the classpath. Each such file must contain a Clojure map of symbols, like this:

{foo/bar my.project.foo/bar
 foo/baz my.project/baz}

The key in each pair is a tag that will be recognized by the Clojure reader. The value in the pair is the fully-qualified name of a Var which will be invoked by the reader to parse the form following the tag. For example, given the data_readers.clj file above, the Clojure reader would parse this form:

#foo/bar [1 2 3]

by invoking the Var #'my.project.foo/bar on the vector [1 2 3]. The data reader function is invoked on the form AFTER it has been read as a normal Clojure data structure by the reader.

Reader tags without namespace qualifiers are reserved for Clojure. Default reader tags are defined in clojure.core/default-data-readers but may be overridden in data_readers.clj or by rebinding *data-readers*.

2.1.1 Instant Literals

Clojure supports literals for instants in the form #inst "yyyy-mm-ddThh:mm:ss.fff+hh:mm". These literals are parsed as java.util.Dates by default. They can be parsed as java.util.Calendars or java.util.Timestamps by binding *data-readers* to use clojure.instant/read-instant-calendar or clojure.instant/read-instant-timestamp.

(def instant "#inst \"@2010-11-12T13:14:15.666\"")

; Instants are read as java.util.Date by default
(= java.util.Date (class (read-string instant)))
;=> true

; Instants can be read as java.util.Calendar or java.util.Timestamp

(binding [*data-readers* {'inst read-instant-calendar}]
  (= java.util.Calendar (class (read-string instant))))
;=> true

(binding [*data-readers* {'inst read-instant-timestamp}]
  (= java.util.Timestamp (class (read-string instant))))
;=> true

2.1.2 UUID Literals

Clojure supports literals for UUIDs in the form #uuid "uuid-string". These literals are parsed as java.util.UUIDs.

2.2 clojure.core/mapv

mapv takes a function f and one or more collections and returns a vector consisting of the result of applying f to the set of first items of each collection, followed by applying f to the set of second items in each collection, until any one of the collections is exhausted. Any remaining items in other collections are ignored. f should accept a number of arguments equal to the number of collections.

(= [1 2 3] (mapv + [1 2 3]))
;=> true

(= [2 3 4] (mapv + [1 2 3] (repeat 1)))
;=> true

2.3 clojure.core/filterv

filterv takes a predicate pred and a collection and returns a vector of the items in the collection for which (pred item) returns true. pred must be free of side-effects.

(= [] (filterv even? [1 3 5]))
;=> true

(= [2 4] (filter even? [1 2 3 4 5]))
;=> true

2.4 clojure.core/ex-info and clojure.core/ex-data

ex-info creates an instance of ExceptionInfo. ExceptionInfo is a RuntimeException subclass that takes a string msg and a map of data.

(ex-info "Invalid use of robots" {:robots false})
;=> #<ExceptionInfo clojure.lang.ExceptionInfo: Invalid use of robots {:robots false}>

ex-data is called with an exception and will retrieve that map of data if the exception is an instance of ExceptionInfo.

(ex-data (ex-info "Invalid use of robots" {:robots false}))
;=> {:robots false}

2.5 clojure.core/reduce-kv

reduce-kv reduces an associative collection. It takes a function f, an initial value init and an associative collection coll. f should be a function of 3 arguments. Returns the result of applying f to init, the first key and the first value in coll, then applying f to that result and the 2nd key and value, etc. If coll contains no entries, returns init and f is not called. Note that reduce-kv is supported on vectors, where the keys will be the ordinals.

(reduce-kv str "Hello " {:w \o :r \l :d \!})
;=> "Hello :rl:d!:wo"
(reduce-kv str "Hello " [\w \o \r \l \d \!])
;=> "Hello 0w1o2r3l4d5!"

2.6 clojure.core/contains? Improved

contains? now works with java.util.Set.

2.7 clojure.core/min and clojure.core/max prefer NaN

min and max now give preference to returning NaN if either of their arguments is NaN.

2.8 clojure.java.io/as-file and clojure.java.io/as-url Handle URL-Escaping Better

as-file and as-url now handle URL-escaping in both directions.

2.9 New Dot Syntax for Record and Type Field Access

Clojure 1.4 introduces a field accessor syntax for the dot special form that aligns Clojure field lookup syntax with ClojureScript's.

In 1.4, to declare a record type and access its property x, one can write:

(defrecord Foo [x]) ;=> user.Foo
(.-x (Foo. 10)) ;=> 10

This addition makes it easier to write code that will run as expected in both Clojure and ClojureScript.

2.10 Record Factory Methods Available Inside defrecord

Prior to 1.4, you could not use the factory functions (->RecordClass and map->RecordClass) to construct a new record from inside a defrecord definition.

The following example did not work prior to 1.4, but is now valid. This example makes use of ->Mean which would have not yet been available.

(defrecord Mean [last-winner]
  Player
  (choose [_] (if last-winner last-winner (random-choice)))
  (update-strategy [_ me you] (->Mean (when (iwon? me you) me))))

2.11 assert-args Displays Namespace and Line Number on Errors

assert-args now uses &form to report the namespace and line number where macro syntax errors occur.

2.12 File and Line Number Added to Earmuff Dynamic Warning

When a variable is defined using earmuffs but is not declared dynamic, Clojure emits a warning. That warning now includes the file and line number.

2.13 require Can Take a :refer Option

require can now take a :refer option. :refer takes a list of symbols to refer from the namespace or :all to bring in all public vars.

2.14 *compiler-options* Var

The dynamic var *compiler-options* contains a map of options to send to the Clojure compiler.

Supported options:

  • :elide-meta: Have certain metadata elided during compilation. This should be set to a collection of keywords.
  • :disable-locals-clearing: Set to true to disable clearing. Useful for using a debugger.

The main function of the Clojure compiler sets the *compiler-options* from properties prefixed by clojure.compiler, e.g.

java -Dclojure.compiler.elide-meta='[:doc :file :line]'

2.15 Improved Reporting of Invalid Characters in Unicode String Literals

When the reader finds an invalid character in a Unicode string literal, it now reports the character instead of its numerical representation.

2.16 clojure.core/hash No Longer Relies on .hashCode

hash no longer directly uses .hashCode() to return the hash of a Clojure data structure. It calls clojure.lang.Util.hasheq, which has its own implementation for Integer, Short, Byte, and Clojure collections. This ensures that the hash code returned is consistent with =.

2.17 Java 7 Documentation

*core-java-api* will now return the URL for the Java 7 Javadoc when you are running Java 7.

2.18 loadLibrary Loads Library Using System ClassLoader

A static method, loadLibrary, was added to clojure.lang.RT to load a library using the system ClassLoader instead of Clojure's class loader.

2.19 Java int is Boxed As java.lang.Integer

Java ints are now boxed as java.lang.Integers. See the discussion on clojure-dev for more information.

3 Performance Enhancements

  • (= char char) is now optimized
  • equiv is inlined in variadic =
  • toString cached on keywords and symbols

4 Bug Fixes

  • CLJ-829 Transient hashmaps mishandle hash collisions
  • CLJ-773 Macros that are expanded away still have their vars referenced in the emitted byte code
  • CLJ-837 java.lang.VerifyError when compiling deftype or defrecord with argument name starting with double underscore characters
  • CLJ-369 Check for invalid interface method names
  • CLJ-845 Unexpected interaction between protocol extension and namespaced method keyword/symbols
    • Ignoring namespace portion of symbols used to name methods in extend-type and extend-protocol
  • CLJ-852 IllegalArgumentException thrown when defining a var whose value is calculated with a primitive fn
  • CLJ-855 catch receives a RuntimeException rather than the expected checked exception
  • CLJ-876 #^:dynamic vars declared in a nested form are not immediately dynamic
  • CLJ-886 java.io/do-copy can garble multibyte characters
  • CLJ-895 Collection.toArray implementations do not conform to Java API docs
    • obey contract for toArray return type
  • CLJ-898 Agent sends consume heap
    • Only capture a shallow copy of the current Frame in binding-conveyor-fn, so that sends in agent actions don't build infinite Frame stacks
  • CLJ-928 Instant literal for Date and Timestamp should print in UTC
  • CLJ-931 Syntactically broken clojure.test/are tests succeed
  • CLJ-933 Compiler warning on clojure.test-clojure.require-scratch