Clojure Language Update 2020


今年もアドベントカレンダーの季節がやってきました。この1年のClojure/ClojureScript界隈の動きを振り返ってみましょう。

## Clojure 1.10.2

今年は、コロナ禍の影響か、昨年に引き続きClojureのメジャーアップデート(1.11)はありませんでした。一方で、マイナーアップデート(1.10.2)については予定されていて、12月1日現在で既に[1.10.2-alpha4](https://github.com/clojure/clojure/releases/tag/clojure-1.10.2-alpha4)までリリースが進められています。

1.10.2の変更は基本的にはGraalVM向けのアップデートと不具合修正になる予定です。
比較的影響が大きそうな修正としては [CLJ-1472](https://clojure.atlassian.net/browse/CLJ-1472) があります。CLJ-1472 は、Javaの`synchronized`ブロック相当の機能である`locking`マクロから生成されるバイトコードが、GraalVMやART等一部の実装におけるバイトコードベリフィケーションに引っかかり、ロード時に`VerifyError`となってしまう問題でした。
対応策としては、Clojureコンパイラの関連する箇所に手を加える案やJavaで書かれたランタイムライブラリを呼び出す方式に変更する案などさまざま考えられましたが、最終的には[二重にネストしたtryというやや技巧的なフォームに展開する](https://github.com/clojure/clojure/commit/f5403e9c666f3281fdb880cb2c21303c273eed2d)よう変更することで、GraalVM等のベリファイアでも妥当と認識されるバイトコードが生成できるようになりました。
また、それ以外のGraalVM向けの変更としてはリフレクションの修正がいくつかありました：

- [CLJ-2572： clojure.dataのリフレクションの修正](https://clojure.atlassian.net/browse/CLJ-2572)
- [CLJ-2587： gvecのリフレクションの修正](https://clojure.atlassian.net/browse/CLJ-2587)

Clojureのこれまでの基本的なスタンスとしては、パフォーマンスが支障がない場面ではフィールドアクセスやメソッド呼び出しでリフレクションが発生していても問題ないと判断されてきましたが、GraalVMが絡む場合にはリフレクションが実行時エラーとなって致命的なため修正されるようになってきています。

上記以外の変更点の詳細については[こちら](https://clojure.atlassian.net/issues/?jql=project%20%3D%20CLJ%20AND%20fixVersion%20%3D%20%22Release%201.10.2%22)から確認できます。

## Clojure CLIの進化
Clojure本体の開発はあまり活発ではありませんでしたが、Clojure CLIについてはかなりアクティブに開発が進められました。既存のコマンドラインオプションが廃止になるなど、使い方もドラスティックに変更されています。

Clojure CLIの基本的な使い方は、新しく以下の3つに整理されました：

- `clj` (オプションなし)：REPLの起動
- `clj -X`: 関数実行
- `clj -M`: `clojure.main` の実行

### `-X` オプション
`-X` オプションを指定することで、Clojureの関数を実行することができるようなりました。これまでも `-m` オプションで同様の機能が提供されていましたが、 `-X` はより柔軟な拡張になっています。

`-X` オプションの最も単純な使い方では、 `-X` オプションに続いて実行する関数名を指定します。指定する関数はマップを1つ引数にとる関数である必要があります。関数名の後にキーバリューのペアをEDN文字列として並べると、それがマップとして関数に渡されます。

たとえば、以下のような関数を定義したとしましょう：

```clojure
(ns example.cli)

(defn hello [{:keys [name]}]
  (println (str "Hello, " name "!")))
```

これを `-X` オプションを使って呼び出すには以下のようにします：

```shell
$ clj -X example.cli/hello :name "Clojurian"
Hello, Clojurian!
```

`-X` オプションには1つ以上のエイリアスを指定することもできます。指定するエイリアスには `:exec-fn` および `:exec-args` キーでそれぞれ実行する関数名および引数を記述します。

先ほどの`example.cli/hello`関数を呼び出すには、たとえば`deps.edn`に以下のように記述します：

```clojure
{:aliases
 {:hello
  {:exec-fn example.cli/hello
   :exec-args {:name "Clojurian"}}}}
```

CLIからの呼び出しは次のようになります：

```shell
$ clj -X:hello
Hello, Clojurian!
$ clj -X:hello :name Rich
Hello, Rich!
```

また、エイリアスに `:ns-default` キーや `:ns-aliases` キーを設定することで、実行する関数として名前空間修飾された完全な名前を指定することなく実行することができるようになります：

```clojure
(ns example.cli)

(defn hello [{:keys [name]}]
  (println (str "Hello, " name "!")))

(defn calc [{:key [expr]}]
  (println (eval expr)))
```

`:ns-default`として名前空間を指定しておくと、名前空間修飾されていない関数名をその名前空間から探してくれるようになります。たとえば、次のように名前空間`example.cli`を`:ns-default`として指定しておくと：

```clojure
{:aliases
 {:cli
  {:ns-default example.cli}}}
```

以下のような呼び出しでそれぞれ`example.cli/hello`, `example.cli/calc`を呼び出すことができます：

```sh
$ clj -X:cli hello :name Alex
$ clj -X:cli calc :expr '(+ 1 2)'
```

`:ns-aliases` で名前空間エイリアスを指定すると、`(require [<namespace> :as <alias>])`と宣言するのと同じような効果が得られます：

```clojure
{:aliases
 {:cli
  {:ns-aliases {cli example.cli}}}
```

```sh
$ clj -X:cli cli/hello :name Alex
$ clj -X:cli cli/calc :expr '(+ 1 2)'
```

これらの機能を使うと、コマンドラインツールのサブコマンドのような機能を簡単に作り上げることができるようになります。

### `-M` オプション
`-M` オプションは `:main-opts` を指定するのにこれまでも使われていたオプションでしたが使い方が見直され、今回のアップデートでエイリアスを引数にとれるようになりました。
機能としては、これまで `-T`, `-R`, `-C`, `-O` の各オプションとして提供されていた機能が `-M` に一本化され、 `-T`, `-R`, `-C`, `-O` オプションはdeprecatedになりました。

### `-X:deps`
`-X` オプションが導入されたことにより、これまでClojure CLIが専用のオプションとして提供してきたいくつかの機能が `-X` オプションを使った関数の呼び出しに置き換えられました。
Clojure CLIは `deps` という組み込みのエイリアスを持っていて、それを経由して次の機能が呼び出せるようになりました：

| 従来の呼び出し方法 | 対応する新しい呼び出し方法 |
|:---------------|:---------------|
| `clj -Stree` | `clj -X:deps tree` |
| `clj -Spom` | `clj -X:deps mvn-pom` |
| `clj -Sresolve-tags` | `clj -X:deps git-resolve-tags` |

この変更と併せて、 [ローカル Maven インストール](https://clojure.org/reference/deps_and_cli#_local_maven_install)という新しい機能が追加され、JARをローカルリポジトリにインストールすることができるようになりました：

```shell
$ clj -X:deps mvn-install :jar <path/to/jar>
```

### runtime basis
また、新たにruntime basisという機能が追加されました。これにより、`deps.edn` に記述された内容やCLIのオプションとして `-Sdeps` で指定した内容を実行中のClojureプラグラムから参照できるようになりました。この機能は、上で紹介した `-X:deps` の各機能を実現するためにも利用されています。
runtime basisの内容は、`clojure.basis`というシステムプロパティで指されているファイルに書き出されるため、以下のようにしてプログラムから読み出すことができます：

```clojure
(require '[clojure.java.io :as jio]
         '[clojure.edn :as edn])

(def basis
  (-> (System/getProperty "clojure.basis") 
      jio/file
      slurp
      edn/read-string))
```

関連記事

- https://insideclojure.org/2020/07/28/clj-exec/
- https://insideclojure.org/2020/09/04/clj-exec/

## Clojure CLIを独自のHomebrew tapとして配布開始
Clojure CLIはこれまでHomebrewで配布されていましたが、今年2月からHomebrew tapでの配布が開始され、公式のインストール方法はそちらに移行されました。
Clojure開発チームは、Homebrew tapに移行することで以下のような運用上のメリットがあるとしています：

- `homebrew-core` メンテナからのレビューや折衝が省略でき、リリースやメンテナンスが省力化できる
- リリースのタイミングをコントロールしやすい
- リリースの自動化がしやすい

最新のClojure CLIは以下のコマンドでインストールできます：

```shell
$ brew install clojure/tools/clojure
```

`homebrew-core` でも依然Clojure CLIのformulaが配布されていますが、そちらは有志によって非公式にメンテナンスされているもので、今後も最新にアップデートし続けられる保証がありません。そのため、特別な理由がなければ公式のHomebrew tapを使うようにした方がいいでしょう。

関連記事

- https://clojure.org/news/2020/02/28/clojure-tap

## Cognitect 買収
今年7月、Rich HickeyやAlex MillerらClojure開発チームが在籍するCognitect社がNubankに買収されました。

[Nubank](https://nubank.com.br/)はブラジルに拠点を置く南米最大のオンラインバンクなどを手掛けるFinTech企業で、以前からサービスの開発にはClojureやDatomicをヘビーに使っているとしていました。また、Nubankは今年6月に[Elixirの開発元であるPlataformatecを買収した]( https://building.nubank.com.br/tech-perspectives-behind-nubanks-first-acquisition-deal)ことでも知られ、Cognitectの買収により1社で言語開発チームを2つ抱える体制になったことになります。
この買収がClojureの開発体制に影響を及ぼすことはなく、ClojureやDatomicの開発は今後もこれまで通り続けられるとのことです。Clojureのユーザ視点からは、この買収によりCognitectの財政基盤が安定化してClojureの開発体制がより磐石になることを期待したいところです。

関連記事

- https://cognitect.com/blog/2020/07/23/Cognitect-Joins-Nubank

## A History of Clojure 公開
ClojureがHOPL IVに採択され、Clojureのこれまでの歴史や言語設計についてまとめられたレポート ["A History of Clojure"](https://clojure.org/about/history) が公開されました。

[HOPL](https://hopl4.sigplan.org/) (History of Programming Languages)はプログラミング言語の歴史や発展についてをテーマとする不定期開催のカンファレンスで、これまで1978年、1993年、2007年の計3回開催されています。4回目のカンファレンスが今年6月に開催予定でしたが、新型コロナの影響により2021年に開催が延期されました。
"A History of Clojure" は、Clojure開発に至るまでの取り組みからこれまでに導入されてきた機能に対する設計判断に至るまで、Rich Hickey本人がまとめたレポートです。内容的には [Effective Programs](https://www.youtube.com/watch?v=2V1FtfBDsLU) 等、Rich Hickeyの過去の発表内容と重なる部分も多く含んでいますが、Clojureというプログラミング言語の背景にある思想等をかいつまんで理解するには手頃な文書といえそうです。

関連記事

- https://clojure.org/about/history

## contribライブラリ 1.0.0リリース
今年の2月にはClojureの多くのcontribライブラリが軒並み1.0.0にアップデートされました。

Clojureコミュニティでは、単機能の小さなライブラリを作ることが多く、そのためライブラリとしての機能が比較的初期に安定化しやすく、0.\*.\*のようなバージョンで長く運用されることがよくあります。Clojureの準標準ライブラリであるcontribライブラリの多くも、0.\*.\*のまま開発が続けられています(もしく枯れたライブラリとなり、活発な開発がなされなくなっています)。
しかし他の言語、特にセマンティックバージョニングが広く受け入れられている言語のコミュニティから来た開発者からは、0.\*.\*のバージョンを持つライブラリに気軽に依存する姿勢は安定性に対するリスクから不安視されるポイントでもありました。
Clojureコミュニティでは(言語開発に近い範囲では特に)そもそも破壊的変更を極力入れない方針が取られているため、メジャーバージョンに大きな意味を持たせていないプロダクトが多いのですが、逆に0.\*.\*に留まる大きな理由もないため、これを機にと一部を除くすべてのcontribライブラリが一斉に1.0.0にアップデートされました。
サードパーティのライブラリについても、同じように十分成熟したものは1.\*.\*へのアップデートが奨励されており、今後ゆるやかなトレンドとしてコミュニティ全体に広がっていくのではないかと思われます。

関連記事

- https://insideclojure.org/2020/02/18/lib-version/
- https://insideclojure.org/2020/02/28/journal/#10-libs

## Clojurists Together Summer of Bugs 始動
Clojurists Togetherが新しくSummer of Bugsという支援プログラムを始めました。

Summer of Bugsはより多様なプロジェクトを支援することを目的とし、年4期の期間・支援額とも固定の支援枠とは別で、より少額・短期間から支援が受けられるようになっています。今回の選出では、以下の7プロジェクトが支援対象として選ばれました。日本人の開発するプロジェクトとしては、 @uochan さんのvim-icedが選出されました！

- clj-kondo
- vim-iced
- DataScript
- Calva
- reitit
- Keycloak-clojure
- cljc.java-time

Clojurists Togetherは今後も、Summer of Bugsに限らず様々なOSSプロジェクトを支援する取り組みを模索していきたいと言っています。

関連記事

- 告知: https://www.clojuriststogether.org/news/announcing-summer-of-bugs/
- 対象プロジェクト公表: https://www.clojuriststogether.org/news/clojurists-together-summer-of-bugs-selections/
- 報告: https://www.clojuriststogether.org/news/summer-of-bugs-update-2020/

## おわりに
(TODO: 気が向いたら書く)