本連載では、名前はよく耳にしていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。今回は前回提示した短いペイントスクリプトの内容に順を追って解説を加えます。前回のプログラムは次のようなものでした。便宜的に、行頭にはコメントのかたちで行番号を振ってあります。position]]Smalltalkのプログラムコードは、目が慣れてしまえば、自然言語(英語)の文章を読むように、比較的容易にその内容を理解できるのがその特徴です。変数名やメソッド名(セレクタ)を考える際に、それを使って書いたコードが、平易で読み下し易いものになるよう心がけることが推奨されており、ユーザー(プログラマ)がそれを遵守することが前提です。Builderにおける、Objective-C/CocoaプログラミングやAppleScriptプログラミングのときのようなストレスを心配する必要はないでしょう。1行目は、一時変数「pen」の宣言です。ちなみに、複数の一時変数を宣言したいときは、スペースで区切って列挙します。FORTRANやALGOLの流れを汲む言語でよく見られる「,」(コンマ)を区切り記号に使わないのは、Smalltalkが前二者よりLISPからの影響を強く受けているからだと思います。余談ですが、コンマは「コレクション」と呼ばれる配列の仲間(文字列を含む)のオブジェクト同士を連結するときに用いる二項セレクタ(関数名)として登録されているので、項目列挙の際に区切りのつもりでうっかり使うとエラーになったり、思わぬ結果が生じることもあるので気を付けてください。”話を戻して、2行目は宣言した一時変数「pen」に、クラス「Pen」のインスタンスを束縛(代入)しています。Smalltalkの変数は型を持たないため、中にデータを入れる“箱”というよりは、本来無名のオブジェクトに付ける“名前”になぞらえたほうがしっくりきます。ここで「代入」や「命名」ではなく「束縛」という言い回しをするのは、変数への束縛が、単に名前を付けるというだけでなく、オブジェクトの寿命を決定づける意味合いも持つからです。new」を評価してオブジェクトを生じさせても、そのまま放っておけばガベージコレクタに瞬殺されてしまいます。誕生させたオブジェクトを確保し、続く式でメッセージを送って何らかの振る舞いをさせるための参照と延命のための作業が、変数への“束縛”、というわけです。new」は、クラス「Pen」にメッセージ「new」を送信してオブジェクトを生成するための式です。クラスはオブジェクトの設計図と言うべき存在で、そのクラスに属するオブジェクト(インスタンス)が内部にいくつのメモリ(インスタンス変数)を持ち、どんなメッセージに応答でき(セレクタ)そのときどんな振る舞いをするか(メソッド)を定義します。システムは、クラスの定義記述に従ってオブジェクトを生みだし、しかるべく振る舞わせます。Smalltalkでは、クラスもまたオブジェクト(クラスのクラスの唯一のインスタンス)なので、メッセージを受けることができ、それに相応しい決められた振る舞いをします。メッセージ「new」は、そのクラスに属するインスタンス(オブジェクト)を生成するために送る一般的なメッセージです。transfer)クラスのサブクラスで、LOGOの“タートル”のような振る舞いをするオブジェクトを定義します。二つ以上の式を区切って区別するには「.」(ピリオド)を用います。これは終端記号ではないので、最終行には付ける必要はありません(あってもエラーにはなりません)。改行や余計なスペース、タブは式の解釈には影響を与えないので、主に可読性向上を目指した整形のために用います。3行目と4行目では一時変数「pen」に束縛した、Penのインスタンスに対してメッセージを送ることで、その“状態”を変化させています。red」はペンの色を赤に変えるためのものです。red」の返値となります。red」自体もメッセージ式で、クラス「Color」に「red」というメッセージを送りColorに属する“赤い色”というオブジェクトを生じさせています。green」とすれば“緑色”を指定できます。これでペン「pen」の準備ができたので、あとはマウスの動きにpenの動きを、マウスボタン操作にpenの上げ下げ連動させればお手軽ペイントソフトを機能させることができます。この部分を記述したのが5行目以降です。次回は、ループやif-then-elseといった条件分岐を、通常のプログラミング言語がするような「構文」ではなく、どのようにして「式」で表現しているのかを解説します。#50突然思い出したが、WWDCに行ったサンフランシスコでいきなりタカハシさんに「フジモトさん、OOP入門はどうなったんですか」と訊かれたのだった。「え、あれで終わりだけど」と答えると、チッチッと言う感じで指を振り「全然終わってないですよ」と。いやあのその別にC++とかObjective-Cの教科書みたいに網羅的にやるつもりは最初からなくて、あの最中にも書いたと思うけれどもオブジェクト指向プログラミングの、なんつうか取っ付きの悪い概念とか仕組みについて地に足がついたコトバで解説してみたかっただけなのでその、オレとしては当初の目論見は達したというかしどろもどろ、と言い訳をしたんだが、「でも例えば多重継承とかは......」とタカハシさんは追及するのだった。継承についてはしつこく説明したけれども多重継承については一言も書いてない。オレはキライなのだあの「多重継承」というヤツが。「キライったってお前、そういうもんぢゃないだろう」と口をトンガラかすキミの顔が目に浮かぶ......わけもないが、とにかくそういうことなので、今回は、オレがなんでコイツを嫌うか、という理由を通して多重継承についての説明を試みたいと思う。基本的なコトなんだけど、多重継承というのはつまり、あるクラスが互いに継承関係のない複数のスーパークラスを持っている状態のことである。C++では例えば以下のように書く。};上の場合、BatというクラスはAnimalおよびBirdをスーパークラスとして持つ。両方ともpublicであるから(難しい言葉では「公開派生」とか言う)、Animalの持つメソッドもBird固有のメソッドもBatに対してコールすることができる......。サイテーである(いや、個人的見解だからね)。オレが気に入らないのは、これが文字通り「コーモリはケモノである,でも空を飛ばなくちゃヘンだからトリでもある」ということを可能にしてしまう仕組みだからである。「現実世界を模式化することでプログラムの構造を簡潔にできる」ことがウリのオブジェクト指向の理念に反して、この機構は「現実世界にはあり得ないモノを作り出してしまえる」のだ。有り体に言えばこの多重継承という機構には「設計をちゃんとできないプログラマの味方」という側面があるのだよ。できたオブジェクト指向のプログラムはパーツパーツが独立していながら総体として一つのシステムを為している。前にも書いたと思うが、我々が意識しなくても心筋は脈動し全身に血液を行き渡らせるし、ランゲルハンス島は血糖値に応じてインシュリンを分泌するわけだ。ところがそういううまい設計をしなくてもなんとかなってしまうヤリカタがある。心筋からランゲルハンス島まで全ての機能をサブクラスして1つのクラスを作るのだ。多重継承というのは使いようひとつでオブジェクト指向をオブジェクト指向でなくしてしまうことのできる(そしてヘタなプログラマはそういう風に使いがちな)困った機構なのである。正直に言うとオレ自身,かつてC++で書いたプログラムの中に「苦し紛れにやった多重継承」が散見できる。言い訳はあって、最初からそんなヌエみたいなオブジェクトがゴロゴロあったわけではなく、バージョンアップとかのときにオブジェクト相互の関係をできるだけ壊さないで(つまり構造を変えないで)、要求されている新機能を加えようとしてそうなっちゃったんだが、それを見るたび全部書き直したくて胃が焼けるような思いだった(今はもう多重継承のできないObjective-Cで書き直したので胃は痛くない)。いうわけでワタシは多重継承がキライなんであり、多重継承というのはそういうものなんであった。わかっていただけたであろうか。(2004_07_30)高橋真人の「プログラミング指南」第49回オブジェクト指向のとっかかり(34)〜Macにおけるオブジェクト指向(続)〜こんにちは、高橋真人です。Foundationで最も使われるのはCFStringでしょう。これは文字列のための仕組みで、単なる文字の配列で作られるCの文字列とは違って、いくらかの応用力を持っています。Foundationの文字列関係の機能を使うことで直接呼び出す必要がなくなります。JISで作られたファイルをEUCに書き出すというケースを考えてみます。JISのデータである」と指定してCFStringに読み込ませます。JISの処理に付きものだった「上位バイト、下位バイト」といったことにもわずらわされずに文字列処理をすることができます。処理が終わって書き出す段になったら「EUCのデータとして書き出せ」と指示してやればよいというわけです。CFStringを使って文字列の処理をする場合、文字列の比較はどうするかということで、比較関数を探してみます。http://developer.apple.com/documentation/CoreFoundation/Reference/CFStringRef/Reference/FunctionGroupIndex.htmlを見てみますと、CFStringCompare()というAPIがあることが分かります。以下のような感じで使います。Cでいうところのprintf()方式で新たにCFStringの文字列を生成するAPIです。従って、str1とstr2には結果的に同じ文字列が格納されることになるので、比較の結果は「同じ」となるわけです。ところで、CFStringに極めて似た役割を持ち、文字列の代わりにバイト列を保持するCFDataというのがあります。http://developer.apple.com/documentation/CoreFoundation/Reference/CFDataRef/Reference/FunctionGroupIndex.htmlにAPIの一覧がありますが、CFStringに比べると極端に数が少ないですね。実は、CFDataRefで保持しているバイト列同士を比較する場合、CFEqual()というAPIが使えます。「そんなもの、さっきのところにはなかった」って?確かにその通り。CFEqual()なんてAPIはどこにあるのでしょう?ここにあります。http://developer.apple.com/documentation/CoreFoundation/Reference/CFTypeRef/Reference/FunctionGroupIndex.html#//apple_ref/c/func/CFEqualあれ、このAPI、引数として取るのはCFTypeRefってなってますね。CFTypeこんなやつです。実は、ここのCFTypeってのがまさにそれなんです。CFDataはCFPropertyListというのを経由して、CFTypeから派生していることになっていますから、CFTypeとしての性質も併せ持っているために、CFEqual()に引数として与えることができるって具合なんです。すれば、考えればお分かりの通り、同じ理屈でCFStringに関しても、CFEqual()を使って比較ができることになります。0」と、ゼロと比較することで「文字列が同じである」と表すのよりももっと直接的な表現になりますね。C/C++コンパイラの販売を開始しました。X開発環境としてもうひとつの選択肢が提供されることになったわけで、デベロッパーにとっては大変喜ばしいことです。PowerPCを設計しているIBMのC/C++コンパイラですから、その信頼性の高さについては疑問の余地がないでしょう(長年自社内で使用しているでしょうし)。実は、WWDC2004においても、64ビットコンピューティングのセッションでIBMの技術社がゲストスピーカーとして壇上に上り、このコンパイラについての詳しい解説を行いました。