LoginSignup
23
13

More than 5 years have passed since last update.

require vs use

Posted at

要約

Clojure 1.4以降では、基本的にuseを使う必要はありません。requireを使いましょう。

requireとuseの違い

Clojureで名前空間を定義する際、別の名前空間をロードして使う方法がいくつか提供されています。その中でも、requireuseはよく似た機能をもっていて、使い分けが難しいと感じる人もいるかもしれません。

requireuseの使い方を表にまとめると次のようになります。

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 ...)

表に戻ってrequireuseを比べてみると、その違いはほとんどないように見えます。しかし、両者の間で顕著に異なっている部分が1つあります。それは、オプションをまったく指定しなかった場合のデフォルトの挙動です。
requireはオプションを指定しなかった場合、対象となる名前空間で定義された名前はすべて名前空間修飾してしか使うことができません。一方、useをオプションなしで使った場合には、すべての名前が名前空間修飾なしで使えるようになります。useのこのデフォルトの挙動によって、どの名前がどの名前空間で定義されているのかを追いづらくなり保守性が悪くなってしまうため、使用は控えた方がいいといわれています。

なぜこのような状況になっているのか?

ここまで読んできた人の中には、なぜ似たような機能を2つも持つような状況になっているのか疑問に思う人もいるかもしれません。
useはもともと、requirerefer1相当の機能として実装されています。今回は触れませんでしたが、useには:rename:excludeなどのオプションも備えています。逆に、1.4以前のrequireには:referの機能はありませんでした。つまり、useの方がrequireの完全な上位互換なのです。しかし、実際には:rename:excludeなどのマイナーなオプションはあまり使われず、requireuseはほとんど同じように使われてきました。そして、不慣れな人にとってはますますrequireuseの機能の違いは分かりづらく、不用意にオプションなしのuseが乱用されることで、保守性の悪いコードを生みやすい状況を作っていました。
このような事態を受けて、デフォルトの挙動で名前空間修飾を必要とするrequireで一本化してuseの使用を置き換えることを目的に、1.4で新たにrequire:referオプションが加えられたのです。

このあたりの事情は、該当チケットやそこにリンクの張られたメーリングリストのスレッドに当時のやりとりがあります。

そんなわけで、1.4以降ではuseは使わずともrequireだけでコードが書けるようになっています。use自体はdeprecatedとまではなっていないものの、上記の修正の意図をくみとると積極的にuseを使う理由はないように思います。今、あえてuseを使う状況は、REPLでの開発で逐一(require [... :refer :all])とするのが面倒な場合やテストコードを書くときなど、一部のケースに限られるでしょう。

おわりに

require:referオプションがサポートされたのはClojureの歴史の中では比較的最近(とはいえ3年前)で、現存するClojureに関する日本語の書籍でこれについて触れている本はほとんどありません。これに限らず、Clojureの新しい機能について日本語の情報が手に入るまでにはかなり"時差"があります。現状としては、Clojureのモダンな書き方にキャッチアップしていくには、活発に開発されているClojureプロジェクトのコードを読んで学ぶか、やはり頑張って英語のドキュメント等をウォッチしていくしかないでしょう(Clojureにもっと普及してもらいたいと思っている身としては、この状況をもうちょっと是正できれば、とも思っていますが…)。


  1. 別の名前空間で定義された名前を名前空間修飾なしに参照できるようにする機能 

23
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
13