My notes and explorations around Clojure's reader literals in preparation for the Austin Clojure Meetup
JavaScript Clojure
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.

Discussion of Reader Literals in Clojure

Austin Clojure Meetup

Hosted by Capital Factory

Monday, February 4th, 2013

Presenter: Steve Suehs, Principal Engineer, Datical

The Reader

  • Parses stream -> Data

which also gives us

  • Parses stream -> Code

Reader Literals

    #foo/bar form
    #foo/bar [1 2 3]
  • magic sequence that the reader will map to a function and invoke
    • namespaced with slash
    • root space reserved for Clojure
  • reader will pass next form to that function
  • allows extension of reader without allowing change of the language
    • contrasts with other LISP's reader extensions, which could change semantics

Reader Literals (cont'd)

    #foo/bar [1 2 3]
    #nascan/file "archives/2012/"
    #nascan/file { :path "archives/2012/" 
                       :size 12345678
                       :scantime  223048}
    #nas.File {...} ;; note no slash! while a reader literal, 
                     ;; used by Clojure for objects and classes.


S expressions are so powerful, why not use functions?

The difference is subtle but important. With the reader literals we can represent a data object and not rely on executable code, which means we can use it to operate with other systems or map to other implementations in a different context.

The reader literals also mean we can change the function that the reader will call with the next form.

The date-time instance is a good example of both.

Reader Literals has roots in EDN

or maybe the other way around.

  • EDN = Extensible Data Notation
  • Used by Clojure and Datomic
  • Intended to be used by other languages
  • Looks like it is extracted from Clojure

If you took the programming out of Clojure and just left the data parts, it would look like EDN.

Default Data Readers

    user=> default-data-readers
    {inst #'clojure.instant/read-instant-date, 
	 uuid #'clojure.uuid/default-uuid-reader}

Let us Code

Fire up a repl and play.

nastimer example

I was having a problem with a disk usage program and my home NAS so I played around with literals.

  • two parts to example. The nastimer has a method to write records with reader literals to a text file.
  • The second part can read that text file but interprets with its own code.
  • Owch: If the data_readers.clj exists, it must have at least an empty map, or reader will fail, and repl may not start.

Possible Pitfalls

Clojure searches for data_readers.clj at the "root of the classpath".

I suspect this will be perilous, but time will tell.

Counter examples:

  • hibernate configuration pain
  • memcache configuration pain
  • singletons not

Worth digging into the reader internals and proposing a solution.

This Presentation on Github

Research Links

Presentation Tools