続々 プログラミング言語 Io : 多重継承

Io は、多重継承ができる。

プロタイプベース

前にも書いたように、Io は、クラスベースではなく、プロトタイプベースのオブジェクト指向言語

Vehicle := Object clone
Car := Vehicle clone
Civic := Car clone

と宣言していけば、

Vehicle <- Car <- Civic

というオブジェクトの階層ができる。

これとは別のオブジェクト階層として、

Maker := Object clone
Honda := Maker clone

と宣言して、

Maker <- Honda

というオブジェクトの階層を作る。

継承関係の表示

Io での継承関係は、protos メッセージ( プロトタイプを指す proto の 複数形 ) で確認できる。
スロット名の通り protos は、 list() 、つまり、複数のオブジェクトを保持できる。

Civic protos

は、今のところ

type = Car

だけ。

多重継承

Civic appendProto( Honda )

とメッセージを送ると、Civic のprotos 、つまり元になったオブジェクトの一覧に、 Honda を追加できる。

今度は、

Civic protos だと、

type = Car,
type = Honda

となって、めだたく(?)、Civic は、Car オブジェクトの特性と、Honda オブジェクトの特性を組み合わせて継承したオブジェクトになる。

Civic の生成時に多重継承を宣言しているのではなく、後から、他のオブジェクトの特性を注入(?)している。

Car にも、Honda に、それぞれ、次のようなスロットを追加する。

Car wheels := 4 (車輪は四つ)
Honda ism := "hondaism" (主張は、ホンダイズム)

この結果、

Civic wheels ==> 4
Civic ism ==> hondaism

というように、 Civic は、Car の特性と、Honda の特性を、多重に継承したオブジェクトになる。

触ってみて、はじめてわかる感触

Io は、単純さにこだわった言語なので、多重継承の仕組み、会話的に、ちょっと試してみるのは、とても便利。

第一印象は、継承というより、コンポジションに近い。

動的に継承関係を、append , remove できたり、継承関係を設定した後に、継承元にスロットを増やせば、それがそのまま反映されたりできるのが、そういう印象になっているのかもしれない。

個人的には、(単一継承のパラダイムでも)継承より、コンポジション派なので、多重継承も、正直いうと、懐疑的。

今まで、多重継承で、実際コードで、いろいろ試したことはなかったので、良い機会なので、ちょっと、多重継承ごっこ(?)をやってみようかと思っている。

たぶん、継承よりコンポジション、という自分のスタンスは変わらないだろうけど、多重継承というパラダイムを実際に触ってみることで、自分の設計感覚に新しい財産を追加できそうな期待感はある。

「多重継承」という言葉だけではぴんとこないけど、 Civic appendProto( Honda ) というコードを実際に書いてみると、全然違うものが見えてくるのが実感できる。

非同期メッセージング

すべてはメッセージというのは、オブジェクト指向の原始時代からあった発想だけど、 Io を使って、すっかり気に入ってしまったのは、メッセージの処理を、並行して、非同期に、実行する仕組み。

@@メッセージ

とやってやると、そのメッセージは、キューに突っ込まれて、非同期に処理される。
@@メッセージの結果を参照する時には、同期する。つまり、結果を待つ。

この仕組みを、フューチャーというらしい。

この仕組みは、

コルーチン(マルチスレッドの仕組み。制御を切替タイミングを、自分でコントロールできる。 yield )
アクタ (スレッドをかなり高いレベルで抽象化したもの。なんというか、マルチスレッドでやっている感覚が持てないくらい、抽象化されている)

の上に、実現されている。

並行処理と非同期メッセージングの抽象化(記述の単純化)は、最近の言語では、あたりまえの機能らしいので、Io の独自性とか、良さがどこにあるかは、今はわかっていない。

7つの言語 7つの世界 にでてくる、 ErlangScala のそこらへんの仕組みも試してみるのが、ちょっと楽しみになってきた。

プロセス間通信、マルチスレッド、非同期メッセージングとかは、ちゃんと理解して使いこなすには、かなりハードルが高かった世界。

「ちゃんと理解して」というのは、たぶん、今でもハードルが高いけど、これらの仕組みを実際に「使ってみる」というハードルは、これらの言語では、めちゃくちゃ、低くなっている。

非同期メッセージングとその並行処理を、ふつうのソフトウェア開発で、それと意識せずに使う時代が、そこまで来ているんだろうなあ。

すべてはメッセージ

Io では、

Io> ターゲット メッセージ

というのが基本構文。(というか、これだけ)

興味深いのは、 Object のスロット

Io> Object slotSummary

とやると、

if, for, switch, while, and, or , ...

などがスロットとして一覧される。

制御文も、すべて、メッセージとして、オブジェクトに送る、という考え方が徹底されている。

Object のスロットから、get( "if" ) して、そこに格納されている文を評価する、というわけだ。

このスロットから、key で get して、その value を評価する、という感じがつかめると、Io の仕組みが、すっと腹に落ちるようになる。

名前空間のルート Lobby

上記の today を格納した Map は、 Lobby という特別な名前のオブジェクト。
Io の名前空間のルートになる。

Io> プロンプトは、ようするに、 Lobby からの問いかけ ( Can I help you ? )。

このプロンプトに入力した内容は、Lobby へのメッセージになる。

Io> today := Date now

today という名前にスロットに、 今日の日付を持った Date オブジェクトを入れておいて、という意味。

Io> today

today スロットの内容を教えて、という意味。

おもしろいのは、

Io> Lobby

といって、Lobby を呼べば、 Lobby は、自分の Map の内容を表示してくれる。

ここで、 Protos というスロットが表示されるので

Io> Protos

とメッセージをLobby に送れば、

Addons
Core

という Lobby の元になった(プロトタイプ原型)の二つのオブジェクトを表示。

Addons は、からっぽ。

Core は、Date, List, Object , ... と、いろいろな基本オブジェクトを持っている基本中の基本のMap

Io> Core

で表示されるそれぞれのオブジェクトに、

Io> Date slotSummary
Io> List slotSummary

とかやると、Date オブジェクトや List オブジェクトのスロット(ほとんどがメソッド)を一覧できる。

すべては、Map ( Key-Value ペア )

Io は、すべてのオブジェクトは、Java でいえば Map。 名前(文字列)をキーにして、何らかの値を持つ。

Map のエントリ( key - value のひとつのペア ) を スロット と呼ぶ。

スロットの値は、List とかでもよいし、メソッドでも良い。

単純に言えば、 Io の構文は、Map への put と get だけ。

スロットを追加したければ、 := 演算子を使う。 これが put。
スロットの内容を評価したければ、 単に、スロットの名前(key) を使う。これが get。

Io> today := Date now

とやれば、ある特別の Map ( 後述 )に、 put( "today", 今日の日付 ) する。

Io> today

とやれば、その特別の Map から、 get( "today" ) した取り出した内容を評価して表示する。

文法というか、Io の仕組みは、ようするにこれだけ。

プログラミング言語 Io が面白い

「7つの言語 7つの世界」を読んでいる。
いろいろなプログラミングのパラダイムを知ると、視野が広がることを実感。

7つの言語の最初の Ruby は、まあ、情報も多いし、母体(?)が、昔、いじっていた、 Lisp, Smalltalk, Perl なので、あまり、視野が広がった気はしなかった。
最近は、 Java ばかりだったので、久しぶりに、Smalltalk のころを思い出して、そもそものオブジェクト指向パラダイムの感覚がちょっぴり戻った気分になったのが収穫。

2番目の言語の Io は、この本で初めて知った。
いやー、おもしろい。
昔、人工知能をかじっていたころ、知識の表現方法の一つのフレームモデルの情報の入れ物「スロット」を思い出した。

Io (アイオー)は、とにかく単純。

  • プロトタイプ型 ( new ではなく clone でオブジェクトを増殖させていく)
  • オブジェクトが自分のプロトタイプ(原型)を記憶している。
  • オブジェクトにメッセージを送ることがすべて

「継承」というか、オブジェクトからオブジェクトを複製して、新しい知識(スロット)を、オブジェクトに追加してやる、というモデルが、ほんと、自然に、単純に実装されている。

Vehicle <- Car <- ferrari

という陳腐なサンプルも、 Io のパラダイムでは、別世界。ほんと、単純なだけに、新鮮。

Vehicle := Object clone
Car := Vehicle clone
ferrari := Car clone

これで、 Vehicle に、例えば、 description "移動手段" とか、スロットを追加してやって、

ferrari に description メッセージを送れば、 "移動手段" が返ってくる。

まあ、オブジェクト指向らしい言語であれば、どの言語でも、同じようなことができちゃうけど、Io は、単純ですっきりしている。
( clone メッセージだけで、どんどん、新しいオブジェクトを生み出せる)

この「単純明快」なオブジェクト指向というのが、Io プログラムのパラダイムというわけだ。
Simple is best. それは、美しくさえある。

<補足>

Io 自体は、単純だったけど、インストールは、ちょっと苦労した。

% io
Io>

というインタプリタの起動までに、ちょっとはまった。
備忘録というか、簡単なメモ。

  1. Windows 環境へのインストールの情報が cygwin 前提みたいだったので、あえなく挫折。
  2. Amazon EC2Linux 環境で、トライ。
  3. http://iolangauage.com から、ダウンロード。 まあ、ホームページもシンプル。
  4. Max OS 用の説明がいきなりでてきて、たじろぐ。(英語ですでにたじろぐ)
  5. cmake が必要だったので、cmake を wget して インストール。
  6. build.sh を実行して、警告がありつつも、build は完了。
  7. make install して io とやっても、 ライブラリのロードエラー
  8. Readme.md という見たことのない拡張子に、またたじろぐ。いちおうテキストみたい。
  9. そこで、ldconfig しろ、と書いてあったので、やってみたが、やっぱりエラー。
  10. それでもだめなら、 /etc/ld.so.conf を書き換えろ、と書いてあるので、開いてみるが、ちょっと、ファイル名といい、デフォルトの内容といい、書き換えに躊躇。
  11. とりあえず、オリジナルを複製しておいて、思い切って書き換え ( /usr/local/lib を追加)
  12. ここで、再度、 ldconfig して、めだたく、io 起動に成功

うーん、インストールがもうちょっとシンプルだと、よかったんだけどなあ。
まあ、おかげで、 Io というシンプルな、言語のパラダイムを試食できたことには、大満足。

ほんと、興味深い言語です