JVMのような業界標準のプラットフォームに対して、顧客やステークホルダーは相当な額の投資を行い、そのパフォーマンスやセキュリティ、安定性に快適さを感じている。Java開発者たちは動的言語の簡潔さや柔軟性、生産性をうらやんでいるかもしれないが、顧客が認めるインフラでの実行、既存のコードベースやライブラリへのアクセス、パフォーマンスを気にしている。さらに、ネイティブスレッドとロックによる並行処理の問題にまさに直面している。Clojureはこうした文脈での実用的で動的な言語設計の努力の成果だ。ClojureはJavaが適している領域にふさわしい汎用言語になろうとしている。Clojureは、並行プログラミングの未来には現在普及している度を越した変更(mutation)はなくなるべきだ、という現実を反映している。

Clojureはその目標を次の方法で達成している: 業界標準でオープンなプラットフォームJVMを受け入れること、偉大なるLispを現代化すること、イミュータブルで永続的なデータ構造で関数型プログラミングを促進すること、ソフトウェアトランザクショナルメモリと非同期のAgentによって並行処理を組み込みでサポートすること。その結果は、堅牢で実用的で高速な言語だ。

Clojureは 状態とアイデンティティ に対して独自のアプローチをとっている。

なぜClojureなのか?

なぜ私はさらに別のプログラミング言語を書いたのか? それは基本的に私が次のものを求めていたからだ:

  • Lisp

  • 関数型プログラミングのための言語

  • 確立されたプラットフォームと共存できる言語

  • 並行処理のために設計された言語

そして、そういうものは見つけられなかったからだ。以下がClojureの背景にある動機となったアイディアのいくつかだ。

Lispは良いものだ

  • たびたび模倣され略奪されてきたが、いまだ複製されるには至っていない

  • ラムダ計算は極めて小さなコアをもたらす

  • ほとんどシンタックスがない

  • いまだ核心的な強みであるデータとしてのコード(code-as-data)とシンタックスの抽象化

  • 標準のLisp (Common LispとScheme)はどうだろうか?

    • 標準化以降のイノベーションが遅い/ない

    • コアとなるデータ構造がミュータブルで、拡張もできない

    • 並行処理が仕様に含まれていない

    • JVM向けの良い実装がすでに存在する(ABCL, Kawa, SISCなど)

    • 標準のLispはそれぞれ固有のプラットフォームになっている

  • Clojureは後方互換性による制約のないLispだ

    • データとしてのコード(code-as-data)というパラダイムをマップとベクターにまで拡張している

    • デフォルトでイミュータブルになっている

    • コアのデータ構造は拡張可能な抽象だ

    • プラットフォーム(JVM)を受け入れている

関数型プログラミングは良いものだ

  • イミュータブルなデータ + 第一級関数

  • Lispでは規律や規約によって常に可能だった

    • しかしデータ構造が変更され うる ものであれば変更されないと推定するのは危険だ

    • 伝統的なLispでは、リストというデータ構造だけが構造的に再帰的だ

  • 純粋関数型言語は強い静的型付けである傾向にある

    • みんなに適しているわけではないし、あらゆるタスクに適しているわけでもない

  • Clojureは動的であることを重視する関数型言語だ

    • すべてのデータ構造はイミュータブルで永続的で再帰をサポートしている

    • 異なる型の値が混在したコレクションや戻り型

    • 動的ポリモーフィズム

言語とプラットフォーム

  • OSではなくVMが未来のプラットフォームであり、次のものを提供する:

    • 型システム

      • 動的な強制と安全性

    • ライブラリ

      • OSの抽象化

      • 非常に多数の 機能の集合

      • 組み込みとサードパーティ

    • メモリと他のリソースの管理

      • GCは言語ではなくプラットフォームの機能である

    • バイトコード + JITコンパイル

      • ハードウェアの抽象化

  • プラットフォームとしての言語 vs. 言語 + プラットフォーム

    • 古いやり方 - 各言語がそれぞれランタイムを定義する

      • GC、バイトコード、型システム、ライブラリなど

    • 新しいやり方(JVM, .NET)

      • 言語とは独立した共通のランタイム

  • プラットフォームのために構築された言語 vs プラットフォームにポートされた言語

    • 多くの新しい言語はいまだ「プラットフォームとしての言語」というアプローチをとっている

    • ポートされる際にプラットフォーム上のプラットフォームという問題を抱えることになる

      • メモリ管理、型システム、スレッドの問題

      • ライブラリの重複

      • 元の言語がC言語をベースにしていても、C言語で書かれた一部の拡張ライブラリはついてこない

  • プラットフォームは顧客に指定されている

    • 「JVM(または.NET)上で実行しなければならない」vs「UNIX(またはWindows)で実行しなければならない」

    • JVMは実績と信頼できるレベルを確立してきた

      • 今やオープンソースでもある

    • 他のコードとの相互運用が求められる

      • C言語との連携では最近では不十分になってきている

  • Java/JVMは言語 + プラットフォーム

    • もともとそうだったわけではないが、JVM向けの他の言語は常に存在し、今やSunにも受け入れられている

    • Javaは冗長で表現力が不十分になりがちだ

      • 第一級関数を欠き、型推論がない、など

    • Javaを呼び出し取り込む能力は決定的に重要だ

  • Clojureは言語であり、JVMがプラットフォームだ

オブジェクト指向は過大評価されている

  • シミュレーションから生まれ、今ではあらゆるものに、時には適していないものにさえ利用されている

    • Java/C#によってあらゆる状況で奨励されてきたが、それはJava/C#がそれ以外の(慣用的な)方法を欠いていたためだ

  • ミュータブルでステートフルなオブジェクトは新たなスパゲッティコードだ

    • 理解するのもテストするのも推論するのも難しい

    • 並行処理にとって災難だ

  • 継承はポリモーフィズムを実現する唯一の方法ではない

  • 「10個のデータ構造それぞれに操作する関数が10個ずつあるより、1個のデータ構造を操作する関数が100個あるほうが良い。」 - Alan

    1. Perlis

  • Clojureはデータ構造をインターフェースで表現されたイミュータブルなオブジェクトとしてモデル化し、それ以外の方法で独自のクラスシステムを提供していない

  • 少数の基本的なデータ構造(seq, map, vector, set)に対して定義された多数の関数

  • JavaでJavaを書き、ClojureからJavaを取り込み拡張する

ポリモーフィズムは良いものだ

  • switch文や構造的なマッチなどは脆いシステムをもたらす

  • ポリモーフィズムは拡張可能で柔軟なシステムをもたらす

  • Clojureのマルチメソッドはオブジェクト指向と型からポリモーフィズムを分離したものだ

    • 複数の基準での分類をサポートしている

    • 静的、動的または外部的なプロパティ、メタデータなどによってディスパッチする

並行処理とマルチコアの未来

  • イミュータブルであることによって多くの問題はなくなる

    • スレッド間で自由に共有できる

  • しかし、状態の変更はシミュレーションや外部世界に対するプログラムでのプロキシとして現実に必要なものだ

  • ロックは繰り返し正しく行うにはあまりにも難しい

  • ClojureのソフトウェアトランザクショナルメモリとAgentのシステムはその困難な部分を担っている

要するに、ClojureはJVM向けで強力な並行処理サポートを備えた関数型のLispとして独自のニッチを占めていると私は考えている。 特徴Clojureを始める を確認しよう。