Clojure/conj 2017 in Baltimore

pic of 10th anniversary cake

I just got back from Clojure/conj and wow, was it great! I don’t use Clojure professionally, but the conference was right here in Baltimore this year, so I couldn’t pass it up.

Clojure 1.0 came out in 2009, but they’re calling this the 10th anniversary because it had actually gone public a couple of years before that. In fact, one of the highlights of the conj was this morning’s talk by fogus and Chouser, where they reminisced about the whole ten years. This included details from 2007 and 2008 which were new to many of us.

At the party last night, I was able to meet Rich Hickey. I shook his hand and said, “thank you.” I’m not sure if I said anything coherent after that, so he probably thinks I’m an idiot, but I’m grateful for the opportunity nonetheless. He has done so much for programmers everywhere! He didn’t just create Clojure, he challenged the status quo. Object-oriented programming dominated our collective thinking for decades, almost to the exclusion of everything else. Now it’s common to hear people speak about alternatives.

I met lots of other Clojurists from near (Baltimore, Brooklyn, &c.) and far (Toronto, Tokyo, &c.) and every one was super nice. I’m not sure if programming Clojure makes you a nicer person or if nice people are just attracted to Clojure, but either way it made for a very pleasant conference.

Advertisements
Clojure/conj 2017 in Baltimore

Epoch fail, Clojure edition

A while back, I wrote about doing epoch calculations in Elixir. Recently, I tried the same sort of thing in Clojure. Since Clojure sits on top of Java, I was not optimistic. Historically, Java has not had a good story to tell when it comes to date-time manipulation. But Java 1.8 added a new java.time package, so maybe it’s better now?

Clojure has clj-time, which wraps joda-time. Joda Time is the third-party library that most Java folks used before version 1.8 (and still do, I guess, if they’re stuck on 1.7 or 1.6 for some reason). Perhaps clj-time will move to java.time eventually, but for now at least they are still on joda-time. Maybe it would have been more sensible for me to just have used clj-time, but I wanted to use the java.time package.

I discovered there is a Clojure java-time (with a dash) that wraps java.time (with a period) and I started out doing that, but eventually abandoned it. When I got to the google-calendar calculation, I needed the .toInstant method, and java-time didn’t seem to supply it.

So, I changed to using java.time directly (if you look back in the git history of Epochs-clojure, you can see where I switched). Since Clojure’s Java interop is so seamless, it turned out pretty nice! Here is that google-calendar portion:

(defn google-calendar
  "Google Calendar time seems to count 32-day months from the day
  before the Unix epoch. @noppers worked out how to do this."
  [n]
  (let [seconds-per-day (* 24 60 60)
        utc (java.time.ZoneOffset/UTC)
        n-days (quot n seconds-per-day)
        n-seconds (rem n seconds-per-day)
        g-months (quot n-days 32)
        g-days (rem n-days 32)]
    (-> (java.time.LocalDateTime/ofEpochSecond (- seconds-per-day) 0 utc)
        (.plusDays g-days)
        (.plusMonths g-months)
        (.toInstant utc)
        (.plusSeconds n-seconds))))

Java time has Instants, which are the naive date-times that I want to do everything with. Similar to Elixir, java.time won’t let me add days or months to an Instant. So I create a LocalDateTime, add the days and months, then convert to an Instant and add the seconds.

Not bad. Not as nice as the Perl version, but better than the Elixir version. At least java.time gives me the .plusMonths method I need, even if it does make me choose a timezone to get it. And, remarkably, it’s just Java. I usually can’t bear to look at Java code, but Clojure makes it almost pretty.

I look forward to clj-time or java-time supplying more Clojure-like access to java.time in the future. But in the meantime, accessing it directly isn’t that bad!


(Update: 2017-08-06) I went to see if I could add .toInstant support for LocalDateTimes in java-time. I figured rather than just complain, I’d send a pull request. In so doing, I discovered it is already there! If I have a LocalDateTime in ldt, then this Java interop code

(.toInstant ldt java.time.ZoneOffset/UTC)

can be written as this java-time code

(instant ldt (zone-offset 0))

I think I’m going to leave Epochs-clojure as Java interop for now, but maybe I’ll switch back to java-time in the future if things start to get too Java-y.

Epoch fail, Clojure edition

Hello, interpolation!

You may have noticed in Command-line Clojure that we glued the string together in pieces

(println (str "Hello, " name "!"))

What are we, Neanderthals? There is a string format in Clojure, but that’s not much better

(println (format "Hello, %s!" name))

Doesn’t Clojure have interpolation? Apparently not, but Chas Emerick wrote a macro for it some years ago. According to that, we should be able to use

(println (<< "Hello, ~{name}!"))

instead. The “<<” is a macro that enables variable interpolation in the string with “~{}”. It does a whole lot more too. Nice!

So how do we use it? It’s not in the core of Clojure yet, but it has been moved into something called the core.incubator. It says there we just need to

Add a dependency on core.incubator to your Leinigen project.clj:

[org.clojure/core.incubator “0.1.4”]

So if we create a new project

$ lein new hello-world
$ cd hello-world

and then add that dependency

$ cat project.clj 
(defproject hello-world "0.1.0-SNAPSHOT"
  :description "Hello interpolation"
  :dependencies [[org.clojure/clojure "1.8.0"]
                 [org.clojure/core.incubator "0.1.4"]])

we should be able to use the macro.

$ cat src/hello_world/core.clj 
(ns hello-world.core)

(defn hello
  ([]
   (hello "World"))
  ([name]
   (<< "Hello, ~{name}!")))

But that doesn’t work. We still need to add the namespace. And not clojure.core.incubator as we might expect, but clojure.core.strint!

(ns hello-world.core
  (:use [clojure.core.strint]))

(defn hello
  ([]
   (hello "World"))
  ([name]
   (<< "Hello, ~{name}!")))

Ah, interpolation! Sweet, sweet, interpolation!

$ rlwrap lein repl
user=> (use 'hello-world.core)
user=> (hello)
"Hello, World!"
user=> (hello "Hank")
"Hello, Hank!"

I do hope they add the “<<” macro to the core soon!

Hello, interpolation!

Command line Clojure

I guess folks usually run Clojure in a REPL, but what if we wanted to write a command-line utility?

Clojure

That’s simple enough to do. If we had the following

#!/usr/bin/env clj

(println (str "Hello, World!"))

in an executable file hello.clj, then we could run it just like anything else.

$ ./hello.clj 
Hello, World!

But how do we interact with our environment? For example, most scripts need access to the command line arguments. In Clojure, these are provided in the *command-line-args* variable. So if we have the following

#!/usr/bin/env clj

(def args *command-line-args*)

(defn greet [name]
  (println (str "Hello, " name "!")))

(if (empty? args)
  (greet "World")
  (doseq [name args]
    (greet name)))

then we’ll greet each command line argument in turn.

$ ./hello.clj Hank Dean Brock
Hello, Hank!
Hello, Dean!
Hello, Brock!

If there are none, we’ll just greet “World” like before.

$ ./hello.clj 
Hello, World!

This is fine, but it’s kind of slow.

$ time ./hello.clj 
Hello, World!

real    0m2.278s
user    0m3.484s
sys     0m0.168s

I guess this is because we have to wait for the JVM to start up. I’m not sure we’d want a command line utility this slow. What can we do?

ClojureScript

How about ClojureScript? We normally think of that as running in the browser, but there are other ways to use it as well. Perhaps server-side JavaScript is faster to start up than Java.

ClojureScript with WebKit

Planck is a stand-alone ClojureScript REPL that is based on WebKit. We could write our script for that with just a small change

#!/usr/bin/env planck
;; -*- clojure -*-

(ns hello.core
  (:require [planck.core :refer [*command-line-args*]]))

(def args *command-line-args*)

(defn greet [name]
  (println (str "Hello, " name "!")))

(if (empty? args)
  (greet "World")
  (doseq [name args]
    (greet name)))

We have to add a line to get Planck to arrange for WebKit to get the *command-line-args* for us. Running this, we get

$ time ./hello-planck 
Hello, World!

real    0m3.318s
user    0m4.532s
sys     0m0.316s

Hrm. That didn’t help. What else?

ClojureScript with Node

Lumo is a stand-alone ClojureScript REPL based on Node.js. To use it, we change our script again

#!/usr/bin/env lumo
;; -*- clojure -*-

(def process (js/require "process"))

(def args (.slice (.-argv process) 3))

(defn greet [name]
  (println (str "Hello, " name "!")))

(if (empty? args)
  (greet "World")
  (doseq [name args]
    (greet name)))

Here we ask Lumo to get the Node.js process.argv for us. That is,

(def args (.slice (.-argv process) 3))

is the Lumo version of Node’s

var args = process.argv.slice(3)

We’re ignoring the first few arguments because they are our script’s name and lumo itself and whatnot.

$ time ./hello-lumo
Hello, World!

real    0m1.504s
user    0m1.840s
sys     0m0.148s

That’s a little faster, but still not great. Plus we pretty much still have to know Node.js to write it.

Summary

So, they’re all pretty slow.

And it would be nice if the Clojure code didn’t have to change. Like if there were some Clojure way to get the command line arguments and then Planck and Lumo made it look more like that. Interoperability with WebKit and Node is nice, but it would be even nicer if it were more transparent.

Command line Clojure