前置き
初回起動が遅いためprint文すら1秒かかるClojureで JVMにオプション指定するんだ とか GraalVMに入門するんだ とか様々な工夫が試みられている中に颯爽と現れたbabashkaは初回起動が普通に早い。頻繁に起動させる使い方でも耐えられそう。
じゃあもう全部babashkaでいいじゃんと思ったら 機能に制限があるらしい (Clojureの全ての機能は使えない)
たとえば babashka-sample
プロジェクトをこんな感じで1ファイルにまとめる時、もし利用できない機能が含まれているとエラーが出る (本稿ではそういう話をする)
$ bb -cp $(clojure -Spath):classes -m babashka-sample.main --uberscript standalone.clj
※ 元々babashkaは bashスクリプトで行わせる処理をClojureで書いてしまおう
という発想らしいので、babashkaで何でもやろうとする考えはbashで何でもやろうとする考えに近いのかもしれない。。。
The main idea behind babashka is to leverage Clojure in places where you would be using bash otherwise.
clojure.specを使うためspartan.specがある
clojure.spec.alpha
をrequireするClojureプログラムは、babashkaで使おうとするとシンボル解決のエラーになる模様。
clojure 1.10.1で試した。
$ bb -cp $(clojure -Spath):classes -m babashka-sample.main --uberscript standalone.clj
clojure.lang.ExceptionInfo: Could not resolve symbol: c/symbol [at clojure/spec/gen/alpha.clj, line 22, column 17]
clojure 1.10.2-alpha1使えば?という言及があるので試したが、ダメみたい (バージョンで解決するのか……)
$ bb -cp $(clojure -Spath):classes -m babashka-sample.main --uberscript standalone.clj
clojure.lang.ExceptionInfo: Could not resolve symbol: c/delay [at clojure/spec/gen/alpha.clj, line 43, column 7]
https://github.com/borkdude/spartan.spec を使えば良いらしい、とは書いてあった。
たぶん動くが、 fdef (関数に対するspec)が未対応らしい
clojure.specのことをfdefが全てみたいに思っていた節があるので悲しい
なお、自分のプロジェクトはspartan.specで代替できたとしても、外部ライブラリで clojure.spec.alphaを活用しているものがあると、読み込み時に弾かれて使えない。
specを使う integrantが弾かれ、integrantを使う duct.coreが弾かれ、これもうわかんねえな。
多分Javaクラスの多くが未対応
Javaクラスの多くをシンボル解決できない疑惑がある。
※ System/getenv
は使えるし、babashkaのゴールとしても一般的なライブラリを使用可能にするらしいとは書かれている
clj-http
clj-httpを読み込んだ時に org.apache.commons.codec.binary.Base64
(java.lang.Class)がシンボル解決エラーで弾かれた。
clj-httpを利用するライブラリ……たとえば clj-slackも当然読み込めない。
(httpライブラリを使いたければ borkdude/clj-http-liteを使う必要がありそう)
Protocol
babashka v0.1.1から (defprotocol)
が使えるらしい。
cf. https://github.com/borkdude/babashka/blob/master/CHANGELOG.md#v020-2020-08-28
が、その Protocol機能を使っている時も、第一引数の型をJavaクラス表記で書くとダメみたい。
たとえばこうやってrecord MyType
をただ指定して、
(defrecord MyType [element])
(defprotocol MyProtocol
(sample [type]))
(extend-protocol MyProtocol
MyType
(sample [type]
(println "プロトコルを実行したぞい")
nil))
(sample (->MyType 5))
とかで呼ぶプログラムは大丈夫だが、
(extend-protocol)
で受け取る第一引数の型を、
(extend-protocol MyProtocol
babashka_sample.main.MyType
(sample [type]
(println "プロトコルを実行したぞい")
nil))
のようにJavaクラス表記 babashka_sample.main.MyType
で書くとシンボル解決エラーになる。
$ bb -cp $(clojure -Spath):classes -m babashka-sample.main --uberscript standalone.clj
clojure.lang.ExceptionInfo: Could not resolve symbol: babashka_sample.main.MyType [at /home/v2okimochi/dev/babashka-sample/src/babashka_sample/main.clj, line 16, column 3]
どちらの例でも (->MyType)
の型を見るとjavaクラスらしいので、何が違うのかはよくわかっていない。