要約
Clojure 1.4以降では、基本的にuse
を使う必要はありません。require
を使いましょう。
requireとuseの違い
Clojureで名前空間を定義する際、別の名前空間をロードして使う方法がいくつか提供されています。その中でも、require
とuse
はよく似た機能をもっていて、使い分けが難しいと感じる人もいるかもしれません。
require
とuse
の使い方を表にまとめると次のようになります。
require | use | 名前の参照方法 | |
---|---|---|---|
すべて名前空間修飾あり | (:require foo.a) |
- |
foo.a/f , foo.a/g
|
すべて名前空間修飾あり(別名) | (:require [foo.a :as a]) |
(:use [foo.a :as a]) |
a/f , a/g
|
指定した名前のみ名前空間修飾なし | (:require [foo.a :refer [f]]) |
(:use [foo.a :only [f]]) |
f , foo.a/g
|
すべて名前空間修飾なし | (:require [foo.a :refer :all]) |
(:use foo.a) |
f , g
|
たとえば、次のような名前空間foo.a
があったとしましょう。
(ns foo.a)
(defn f [x] ...)
(defn g [x] ...)
この名前空間foo.a
を使用する名前空間foo.b
が次のように定義されているとき、
(ns foo.b
(:require [foo.a :refer [f]]))
この名前空間の中では、:refer
で指定されたf
のみが名前空間修飾なしで参照でき、それ以外(この場合はg
)は必ず名前空間名で修飾して参照しなければいけません。
(f ...)
(foo.a/g ...)
require
の:as
と:refer
は組み合わせて使うこともできます。その場合は:refer
で指定した名前のみが名前空間修飾なしで参照でき、それ以外の名前は:as
で指定した別名で修飾して参照します。use
でも同様のことができます。
(ns foo.b
(:require [foo.a :as a :refer [f]]))
(f ...)
(a/g ...)
表に戻ってrequire
とuse
を比べてみると、その違いはほとんどないように見えます。しかし、両者の間で顕著に異なっている部分が1つあります。それは、オプションをまったく指定しなかった場合のデフォルトの挙動です。
require
はオプションを指定しなかった場合、対象となる名前空間で定義された名前はすべて名前空間修飾してしか使うことができません。一方、use
をオプションなしで使った場合には、すべての名前が名前空間修飾なしで使えるようになります。use
のこのデフォルトの挙動によって、どの名前がどの名前空間で定義されているのかを追いづらくなり保守性が悪くなってしまうため、使用は控えた方がいいといわれています。
なぜこのような状況になっているのか?
ここまで読んできた人の中には、なぜ似たような機能を2つも持つような状況になっているのか疑問に思う人もいるかもしれません。
use
はもともと、require
+refer
1相当の機能として実装されています。今回は触れませんでしたが、use
には:rename
や:exclude
などのオプションも備えています。逆に、1.4以前のrequire
には:refer
の機能はありませんでした。つまり、use
の方がrequire
の完全な上位互換なのです。しかし、実際には:rename
や:exclude
などのマイナーなオプションはあまり使われず、require
とuse
はほとんど同じように使われてきました。そして、不慣れな人にとってはますますrequire
とuse
の機能の違いは分かりづらく、不用意にオプションなしのuse
が乱用されることで、保守性の悪いコードを生みやすい状況を作っていました。
このような事態を受けて、デフォルトの挙動で名前空間修飾を必要とするrequire
で一本化してuse
の使用を置き換えることを目的に、1.4で新たにrequire
に:refer
オプションが加えられたのです。
このあたりの事情は、該当チケットやそこにリンクの張られたメーリングリストのスレッドに当時のやりとりがあります。
- CLJ-879: Allow :require to support a :refer clause
- Clojure Dev: simplifying the require/use situation
そんなわけで、1.4以降ではuse
は使わずともrequire
だけでコードが書けるようになっています。use
自体はdeprecatedとまではなっていないものの、上記の修正の意図をくみとると積極的にuse
を使う理由はないように思います。今、あえてuse
を使う状況は、REPLでの開発で逐一(require [... :refer :all])
とするのが面倒な場合やテストコードを書くときなど、一部のケースに限られるでしょう。
おわりに
require
で:refer
オプションがサポートされたのはClojureの歴史の中では比較的最近(とはいえ3年前)で、現存するClojureに関する日本語の書籍でこれについて触れている本はほとんどありません。これに限らず、Clojureの新しい機能について日本語の情報が手に入るまでにはかなり"時差"があります。現状としては、Clojureのモダンな書き方にキャッチアップしていくには、活発に開発されているClojureプロジェクトのコードを読んで学ぶか、やはり頑張って英語のドキュメント等をウォッチしていくしかないでしょう(Clojureにもっと普及してもらいたいと思っている身としては、この状況をもうちょっと是正できれば、とも思っていますが…)。
-
別の名前空間で定義された名前を名前空間修飾なしに参照できるようにする機能 ↩