ClojureScript

1.10.238 リリース

2018年3月26日
ClojureScriptチーム

ClojureScript 1.10がついにリリースされました!

Java 9とJava 10のサポートを含む多くの機能強化が行われました。以下では、主な新機能のいくつかについて簡単に説明します。

cljs.main

ClojureScriptには、cljs.mainが含まれるようになりました。これは、clojure.mainの多くの機能(および新しいClojure CLIツールで普及)をClojureScriptにもたらし、ClojureScript環境の追加の考慮事項と機能に対する特別なサポートとともに、コマンドラインから直接ClojureScriptコードをコンパイルまたは実行できるようにします。

cljs.main機能により、新規ユーザーのエクスペリエンスを大幅に簡素化することができました。クイックスタートガイドの以前のバージョンにおける複雑さと儀式的な手順の多くは、単に解消されました。

また、経験豊富なClojureScriptユーザーにとって、cljs.mainは簡単であるべき操作を、本当に簡単にしてくれます。複雑な設定を必要とせずに、1つか2つのコマンドラインフラグだけで多くのことができるようになりました。

cljs.mainの詳細については、ClojureScriptコマンドラインをご覧ください。

共有AOTキャッシュ

共有AOTキャッシュ機能は、JARからコンパイルされたアーティファクトを保存し、プロジェクト間で再利用したり、プロジェクトでクリーンビルドを実行した場合に再利用したりできるようにします。これにより、変更のないコードの再コンパイルを回避することで、時間を節約できます。

この機能の詳細については、共有AOTキャッシュをご覧ください。

モジュール処理の改善とClosureのアップデート

ClojureScriptは、最新のClosure Compilerリリース(v20180204)を使用するようになりました。これには、Nodeモジュールを使用するための多くの改善が含まれています。Closure Compilerのアップデートに加えて、ClojureScript側でいくつかの変更が実装されました。改善点の一部を以下に示します。

  • CommonJSおよびES6モジュールは、互いにrequireできるようになりました

  • Closureは、より多くのUMDラッパーを検出して削除できるようになりました

  • node_modulesディレクトリが存在するが使用すべきでない場合に、:npm-depsオプションをfalseに設定することで、Nodeモジュールのサポートを無効にできます

安定した名前

新しいコンパイラオプションである:stable-namesが導入されました。これにより、高度なビルド間の名前の変更が減り、:modulesを使用している場合に適切なベンダー化を容易にします。

強化されたソケットREPLとアルファ版pREPL

このリリースでは、-Dclojure.server.replとの統合のためのcljs.server.*名前空間がいくつか追加され、より豊富なClojureScriptソケットREPL機能が可能になりました。

さらに、pREPLのサポートが追加されました。これはソケットREPLに似ていますが、代わりにEDNベースであるため、ツールはプログラムでREPL出力を利用できます。

新しいソケットREPLおよびpREPL機能を使用するには、Clojure 1.10.0-alpha4がクラスパス上にある必要があります。

core.specs.alpha

core.specs.alphaライブラリがClojureScriptに移植され、このリリースではオプトイン機能として利用できます。このライブラリには、コアマクロと関数を記述するスペックが含まれています。ns特殊形式のサポートも追加されています。

このライブラリを使用するには、新しいcljs.core.specs.alpha名前空間をrequireするだけです。これにより、defnlet、およびその他のマクロのスペックが登録され、これらのマクロの後続のコンパイルはスペック検証の対象となります。

以下に、REPLでの使用例を示します。ClojureScriptには存在しないClojure固有の機能を使用して、ライブラリのすべてのシンボルを誤って参照しようとしたとしましょう

 cljs.user=> (require '[clojure.set :refer :all])
 clojure.lang.ExceptionInfo: Don't know how to create ISeq from: clojure.lang.Keyword at line 1 ...

このエラーは少し曖昧です。では、もう一度試してみましょう。ただし、core.specs.alphaを使用します

cljs.user=> (require 'cljs.core.specs.alpha)
nil
cljs.user=> (require '[clojure.set :refer :all])
clojure.lang.ExceptionInfo: Call to cljs.core/require did not conform to spec:
In: [0 1 :refer] val: :all fails spec: :cljs.core.specs.alpha/refer at:
[:args :spec :libspec :lib+opts :options :refer] predicate: coll?
...

結果として得られるエラーは、:allが問題であり、:referが引数としてコレクションを受け取ることを基本的に示しています。

この機能はまだアルファ版ですが、ぜひ試してみて、発見したバグを報告してください!

可約シーケンスジェネレーター

このClojureScriptリリースでは、iteraterepeat、およびcycleの結果が直接可約になりました。これにより、Alex MillerがClojureで行った素晴らしい作業が数年前にClojureScriptにもたらされました。これは、これらの関数の出力に対してreduceを行うときに、パフォーマンスが大幅に向上することを意味します。

たとえば、:advanced最適化でコンパイルした場合に、(transduce (take 64) + (iterate inc 0))を合計10,000回実行するベンチマークを考えてみましょう。このベンチマークは自分のマシンで試すことができますが、V8およびSpiderMonkeyでは4.5倍、JavaScriptCoreでは3.3倍高速化されています。

さらに、これにより、中間シーケンス生成を伴わずに大きな出力を処理する方法が提供され、ClojureScriptで発生するローカルクリアの欠如と不可避的なヘッド保持を回避できます。これは、次のようなプログラムを実行できるようになったことを意味します。

(transduce (comp (map inc) (filter odd?) (take 1e8)) + (iterate inc 0))

そして、それらは非常に少ないメモリを消費します。この例は、Node REPLで約10秒で完了し、わずか数メガバイトのRAMを使用しますが、以前は基本的に終了せず、ギガバイトのRAMを消費していました。

マップエントリ

便宜上、ClojureScriptは、ソートされていない永続マップエントリに対して2要素のベクトルを返していました。多くの場合、マップエントリはベクトルとして使用できるため、これは問題ありません。しかし、逆の場合はそうではなく、これを実現するために、ClojureScriptはkeyおよびvalマップエントリ関数に対して永続ベクトルへの人工的なサポートを追加する必要がありました。

Clojureと合わせるために、ClojureScriptはこのケースに対して専用のマップエントリ型を返すようになり、人工的なベクトルサポートを排除しました。Clojureとの忠実度が高いことを示す1つの例は、マップエントリにemptyが適用された場合にClojureScriptが適切にnilを返すことができることです。(マップエントリは正確に2つの要素を持つため、空のマップエントリを持つことはできません。)

これにより確かに整理されますが、ベクトルをマップエントリとして誤って扱うコードに注意してください。たとえば、(key (first {:a 1}))および(val (first {:a 1}))は完全に有効ですが、(key [:a 1])および(val [:a 1])は正しくなく、実行時例外が発生します。

最後に、専用のマップエントリ型を使用すると、マップエントリを扱う一部のコードでパフォーマンスが向上する可能性があります。たとえば、:advancedモードでは、このコード

(simple-benchmark [m (zipmap (range 100) (range))]
  (reduce (fn [a [k v]] (if (even? v) (+ a k) a)) 0 m) 100000)

は、JavaScriptCoreで11%、V8で18%、SpiderMonkeyで驚異の105%高速に実行されます。また、非構造化の代わりに専用のkeyおよびval関数を使用すると、V8のパフォーマンスは44%向上し、SpiderMonkeyは112%向上します。

ClojureScript 1.10.238の完全な更新リストについては、変更点を参照してください。

コントリビューター

ClojureScript 1.10.238に貢献してくれたすべてのコミュニティメンバーに感謝します

  • Andrea Richiardi

  • Bruce Hauman

  • Dieter Komendera

  • Enzzo Cavallo

  • Erik Assum

  • Hendrik Poernama

  • Jannis Pohlmann

  • Jinseop Kim

  • John Newman

  • Juho Teperi

  • Levi Tan Ong

  • Mark Hepburn

  • Martin Klepsch

  • Mike Fikes

  • Oliver George

  • Paulus Esterhazy

  • Roman Scherer

  • Thomas Heller

  • Tim Pote

  • Tom Mulvaney