スーパークラスとサブクラス …とクラスとインスタンス復習ちょっと
似たようなクラスを作るとき、すべてを再定義せずとも流用できるようにするためのしくみがスーパークラス、サブクラスです。あるクラスのサブクラスとして新しいクラスを宣言すると、そのクラスは何も定義しなくとも、スーパークラスにあたるクラスと同等の仕様を持つことができます。あとは、スーパークラスにない機能を追加したり、ある機能を別に置き換えたりすれば似て非なるクラスを作ることができるわけです。--sumim - 2002-12-03, 15:43:52
ただ、オーバーライドできるのはメソッドだけで、インスタンス変数は追加しかできません。すでに定義されたインスタンス変数を削除することはできません。--sumim - 2002-12-03, 15:45:21
たとえば、Fraction のサブクラスに MyFraction という名前のクラスを定義したいときは、定義したクラスを置きたいクラスカテゴリをクラスカテゴリペインに呼び出した状態で(必要なら instance ボタンをクリックして)コードペインに、Object subclass: #NameOfSubclass
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Kernel-Numbers'
(最後の行の '' 内は自分の選んだカテゴリ)というようなテンプレートが表示されていることを確認して、Object を Fraction に、NameOfSubclass を今の場合 MyFraction にタイプして置き換え、accept します。--sumim - 2002-12-03, 15:49:23
>すべてを再定義せずとも流用できるようにするためのしくみがスーパークラス、サブクラスです
継承元をスーパークラス,継承されたクラスをサブクラスと呼ぶのですよね.(ところでSmalltalkでも「継承」と言って良いのでしょうか?また,派生とも言いますか?)--人狼 - 2002-12-03, 15:53:42
>オーバーライドできるのはメソッドだけで、インスタンス変数は追加しかできません
了解しました.ところで,メソッドやインスタンス変数にいわゆる「public,private,protected」等と言う概念はありますか?--人狼 - 2002-12-03, 15:54:39
門外漢なもので、どんな概念なのか端的な例を示しながら簡単に説明していただけると助かります。>public、private、protected --sumim - 2002-12-03, 15:56:17
>ところでSmalltalkでも「継承」と言って良いのでしょうか?
継承でよいと思います。派生というのは聞いたことがありません。--sumim - 2002-12-03, 15:57:32
MyFractionを定義しました.これをブラウズしても,instanceVariableNames欄は空欄なのですね.スーパークラスのインスタンス変数やメソッドは,そのスーパークラスをブラウズしなくては判らないのでしょうか?
それと,Kernel-Numbersからではなくて,Fractionを選択した状態でサブクラスを作る方が直感的な気がするのですが,それは不可ですか?--人狼 - 2002-12-03, 15:59:48
>Kernel-Numbersからではなくて,Fractionを選択した状態でサブクラスを作る方が直感的な気がする
その場合は、Fraction の定義を書き換えればできます。具体的には、Number を Fraction へ、Fraction を MyFraction2 へ、instanceVariableNames: 欄を '' つまりカラにします。--sumim - 2002-12-03, 16:03:16
public,protected,privateともに,C++やJavaで出てくる概念です.(Objective-Cは,まだそこまで学習が進んでません)いずれもクラスの変数やメソッドに付随する概念です.
publicと指定された変数やメソッドは,誰でも自由に(存在を知っていれば)使用する事が出来ます.
privateと指定された変数やメソッドは,そのクラス内でのみ利用可能です.外部から利用としてもNotFoundになります.(存在隠蔽)
protectedと指定された変数やメソッドは,そのクラス内及び,自分のサブクラスからのみ利用可能です.サブクラスでprotectedで宣言された変数やメソッドはスーパークラスからは利用出来ません.--人狼 - 2002-12-03, 16:03:39
>スーパークラスのインスタンス変数やメソッドは,そのスーパークラスをブラウズしなくては判らないのでしょうか?
原則としてそうです。どのスーパークラスがどのインスタンス変数を定義しているのかを一覧することはできます。instance と class の間にある ? ボタンを2回ほどクリックすると、その様子を見ることができます。--sumim - 2002-12-03, 16:05:38
継承でよいと思います。派生というのは聞いたことがありません
了解です.継承と言うのは,スーパークラスを引き継いでサブクラスを作る事で,そのサブクラスの事を派生クラスと言ったりします.(本題から逸れますが,多重継承ってあるのでしょうか?)--人狼 - 2002-12-03, 16:06:41
>public、protected、privateともに,C++やJavaで出てくる概念です
だとすると、Smalltalk のメソッドやインスタンス変数はすべて public です。ただ、コンセンサスとして、メッセージカテゴリに private というカテゴリを設けて、そこに分類されているメソッドは外部から使わないようにする…という決まりがあります。--sumim - 2002-12-03, 16:08:54
>多重継承ってあるのでしょうか?
かつては実験的に実装されたことがあったのですが、現在は外されています。--sumim - 2002-12-03, 16:10:03
>Fractionの定義を書き換えればできます
なるほど.Fractionの定義を書き換えてacceptすると新しいクラスが出来るのですね.こちらの方が私にとっては直感的かもしれません.--人狼 - 2002-12-03, 16:10:38
>どのスーパークラスがどのインスタンス変数を定義しているのかを一覧することはできます
これは便利ですね.すごいです.--人狼 - 2002-12-03, 16:11:43
>Smalltalkのメソッドやインスタンス変数はすべてpublicです
了解しました.ただ,直接インスタンス変数へのアクセスする事は推奨されていない,と言うだけなのですね.メッセージを使ってやりましょう,と言う「約束」があるだけだ,と言う事でしょうか?
privateと言うカテゴリについても,約束事で仕様上制限されているわけではない,と言う事でしょうか?--人狼 - 2002-12-03, 16:15:58
>かつては実験的に実装されたことがあったのですが、現在は外されています
了解しました.その方がすっきりしていて良いです(笑)--人狼 - 2002-12-03, 16:16:48
ではちょっと公開トラップをしかけてみましょう。MyFraction の定義の instanceVariableNames: 欄に jinro2 を追加して accept ではなく、全体を選択(cmd-a)して do-it してみてください。--sumim - 2002-12-03, 16:17:27
>直接インスタンス変数へのアクセスする事は推奨されていない
それは外部からアクセスする場合、ということで、インスタンス変数を有するオブジェクトのクラス定義の中ではその限りではありません。--sumim - 2002-12-03, 16:19:34
>約束事で仕様上制限されている
仕様ではなく、メッセージ名が変わるかもしれないから外部からは使用しないほうがいいよ…という程度です。あくまでコンセンサスが成立てばの話で、言語仕様上の制約はありません。--sumim - 2002-12-03, 16:22:59
>公開トラップをしかけて
いや,公開トラップと宣言されても(汗)先程acceptした時と同様に一瞬だけ「リコンパイルしてます」のような感じのメッセージ(一瞬なので全文を読めません)が表示されます.
ところが,何か他をクリックすると「変更が保存されていません」と言うノーティファイヤ(で良いのかな?)が表示されます.これはdo-itしたので,今操作の対象にしているMyFractionインスタンスの記述は変更したけど,その内容はクラス定義として保存されていない,と言う事でしょうか?(こじつけっぽい)--人狼 - 2002-12-03, 16:44:25
>それは外部からアクセスする場合、ということ
了解しました.インスタンス変数を有するクラス定義の中では,確かに一々メッセージを介すると言うのは理にかなっていませんね.--人狼 - 2002-12-03, 16:45:23
>先程acceptした時と同様に
ポイントはそこですね。そもそも do-it って何でしたっけ?--sumim - 2002-12-03, 16:46:51
>コンセンサスが成立てばの話で、言語仕様上の制約はありません
了解です.私の申し上げ方が悪かったようです.すみません.主旨は,「そうしないようにしましょうねと言う約束であって,言語仕様として制限されているわけではない.」と言う事でした.お手間をとらせてすみません.--人狼 - 2002-12-03, 16:47:36
たぶん、文脈からそういう意味でおっしゃっておられるんだろうなとは思いましたが念のため。くどくてすみません(^_^;)。--sumim - 2002-12-03, 16:49:14
>そもそも do-it って何でしたっけ?
選択部分のメッセージ式を評価する事です.--人狼 - 2002-12-03, 16:50:21
>念のため
いえ,私の表現が足りない部分もありますので助かります(汗)それに,くどいくらいの方が誤解しなくて良いと思います.この量で数ページ行ってから誤解に気付くととんでもない事に(大汗)--人狼 - 2002-12-03, 16:51:38
>その内容はクラス定義として保存されていない,と言う事で
いえ、テキストエディタとして内容を“accept”(広義)していないが、破棄して良いか?という意味です。do-it と同時に内容は accept (操作)時と同様にエディタにはともかくシステム側には accept(広義)されている(笑)ので、エディタの警告に Yes と答えて MyFraction の定義を表示しても同じものが出てくるはずです。--sumim - 2002-12-03, 16:52:41
>選択部分のメッセージ式を評価する事
ということですね。つまり、選択部分は“メッセージ式”つまりオブジェクトに対してメッセージの送信を記述したものである、と。ここまできてもピンと来ませんか? それとも「何をいまさら…」的認識事項だったでしょうか?--sumim - 2002-12-03, 16:54:20
>いえ、テキストエディタとして内容を
なるほど.do-itと同時に,内容は反映されているのですね.--人狼 - 2002-12-03, 16:57:42
>選択部分は“メッセージ式”つまりオブジェクトに対してメッセージの送信を記述したものである、と
即ち,クラス定義と言えども,そのクラスへのメッセージによって成されていると言う事ですよね?なので,他のオブジェクトからメッセージを送信する事により,クラス定義の変更は可能になる…と言う事かな?(ここで,クラスがオブジェクトと言う意味が活きてきますね)--人狼 - 2002-12-03, 17:00:11
>ここで,クラスがオブジェクトと言う意味が活きてきますね
そういうことです。つまり、新規クラスの定義や既存のクラス定義変更は、どこからでも可能(たとえば、この定義用のメッセージ式を Workspace にコピペして do-it しても、別のクラスのメソッドに仕込んでメッセージ送信によってメソッド起動しても実行可能)…ということで、これは、PlayerXXX クラスは誰が定義しているの?というあたりとも関わってきます。--sumim - 2002-12-03, 17:02:39
>新規クラスの定義や既存のクラス定義変更は、どこからでも可能
と,言う事になりますね.う〜ん(汗)今までの考え方と,ここで大きく違いますね.が〜んって状態です(汗)
>PlayerXXX クラスは誰が定義しているの?というあたりとも関わって
うん,そうですね.確かに関わりがありますよね.とりあえず「誰が」はまだ未解決ですが「動的に定義」出来そうと言うのが今のところです.--人狼 - 2002-12-03, 17:05:36
ちなみにこれは subclass:instanceVariableNames:classVariableNames:poolDictionaries:category: というメッセージセレクタを用いたメッセージでひとつのシンボルと、4つの文字列を引数にとります。--sumim - 2002-12-03, 17:06:27
>ちなみにこれは
subclass:instanceVariableNames:classVariableNames:poolDictionaries:category: と言うメッセージセレクタですね.#MyFractionが最初の引数でここがシンボル.(ここで,これがシンボルである事からクラス名のユニークが保証される).instanceVariableNames-,classVariableNames,poolDictionaries,categoryに,それぞれ文字列引数となるのですね.このとき,category以外は空文字列が許されるのですか?ちなみに,この時のメッセージのレシーバーはスーパークラスですね.と,言う事はクラスを作る人はスーパークラスですね.--人狼 - 2002-12-03, 17:12:19
いえ、これは便宜上、スーパークラスにメッセージを送っていますが、クラス MyFraction(とそれに対応するメタクラス MyFraction class)を作るのはやはり Metaclass です。Metaclass はまず、メタクラス MyFraciton class を作り、そのメタクラス MyFraction class がクラス MyFraction を作ります。他のオブジェクトと同様に、インスタンスはそのクラスが作るのです。そうして作られたメタクラス MyFraction class とクラス MyFraction“親子”をスーパークラス Fraction は自分(と自分のメタクラス Fraction class の)影響下に置きます。--sumim - 2002-12-03, 17:14:21
>影響下
メタクラス間の継承被継承関係は、クラス間のそれに原則として倣います。--sumim - 2002-12-03, 17:27:19
>クラス(とそれに対応するメタクラス)を作るのはやはり Metaclass
むぅ,やはりそんなに甘くありませんでしたね(泣)
件のメッセージはMetaclassに送られるのですね.(なぜ届くのか,はとりあえずおいておきます.)先程のMyFractionで考えますと,MyFractionと言うクラスを定義しましたが,それは即ちMyFraction classを作成したと言う事で,そのメタクラスを作成した後に,その定義に従いクラスMyFractionのインスタンスが作られると言う事ですよね.--人狼 - 2002-12-03, 17:30:25
>他のオブジェクトと同様に、インスタンスはそのクラスが作るのです
ありゃ,まだ誤解してるな>自分
MyFractionは…クラスですね.失礼.これを設計図としてインスタンスが出来るのですね.MyFraction classはMyFractionのクラスですね.-人狼 - 2002-12-03, 17:34:30
>なぜ届くのか,はとりあえずおいておきます.
これはそんな深い話ではありません。subclass:instanceVariableNames:classVariableNames:poolDictionaries:category: メソッドか、その下流に Metaclass hoge(hoge とは Metaclass のインスタンス、つまり MyFraction class を作るためのメッセージ)というメッセージ式が記述されている…というだけのはなしですから。--sumim - 2002-12-03, 17:37:28
>メタクラス間の継承被継承関係は、クラス間のそれに原則として倣います
えっと親→子と記すならば,Fraction→MyFractionで,Fraction class→MyFraction classとなる.FractionとMyFraction classのような継承関係は無いと言う事ですね?--人狼 - 2002-12-03, 17:38:46
>その定義に従いクラスMyFractionのインスタンスが作られる
クラス MyFraction という MyFraction class のインスタンスが…ですね。--sumim - 2002-12-03, 17:39:54
>これはそんな深い話ではありません。
なるほど.ご説明頂けば「おぉ,そうか」と思いますが(汗)--人狼 - 2002-12-03, 17:40:40
>えっと親→子と記すなら
“親子”という表現はクラス-インスタンスで使ってしまっているので、そのままスーパー→サブとしましょう。--sumim - 2002-12-03, 17:41:42
>クラス MyFraction という MyFraction class のインスタンスが
あいかわらず言葉が足りていません,済みません.--人狼 - 2002-12-03, 17:42:21
>親子”という表現はクラス-インスタンスで使ってしまっているので、そのままスーパー→サブ
了解です.--人狼 - 2002-12-03, 17:42:56
>FractionとMyFraction classのような継承関係は無い
これを「Fraction→MyFraction classのような継承関係は無い」のタイポだとすると、原則としてそういう関係はありません。が、唯一の例外で、ProtoObject class のスーパークラスは Class になります。この結果、ProtoObject がメタクラスを含めたすべてのクラスのスーパークラスになることができるわけです。--sumim - 2002-12-03, 17:44:33
そんなわけで、すべてのオブジェクトにクラスの別なく反応させたいメッセージのメソッドは、ProtoObject かその唯一のサブクラスである Object に定義/記述すればよいことになります。インスタンス変数もしかりで、Object にインスタンス変数を定義すれば、すべてのオブジェクトがそのインスタンス変数を持つことができます。--sumim - 2002-12-03, 17:48:13
>Fraction→MyFraction classのような継承関係は無い
その通りです.ミスタイプです,済みません.原則としてそう言う関係は無いのですね.
>唯一の例外で、ProtoObject class のスーパークラスは Class になります
の件が実は昨日から気になっているところなのですが…その前に今までのところを整理させて下さい.--人狼 - 2002-12-03, 17:48:21
了解です。「すべてのオブジェクトにクラスの別なく反応させたいメッセージ…」の話は忘れてください。--sumim - 2002-12-03, 17:49:23
先程から例に出ているMyFractionについて,整理させてください.
ブラウザでMyFractionと言うサブクラスをFractionを継承して作りましたが,これはMyFraction classなるメタクラスを作成していることである.MyFraction classを作成すると,その定義に従いMyFraction classのインスタンスであるクラスMyFractionが出来る.これでようやくサブクラスが出来た事になる.
クラスの作成はMetaclassにメッセージを送信する事によりなされている.サブクラスを作成するメッセージを送る事=メタクラスを作成して,そのインスタンスたるクラスを作成すること?
この段階ではまだ,MyFractionはクラス定義がされただけで,インスタンスは存在していない.--人狼 - 2002-12-03, 17:54:11
うぅ,会社では時間切れです.帰って体調と相談してアクセスさせて下さい.すみません,熱心にご教授頂いているのに.--人狼 - 2002-12-03, 17:58:02
>この段階ではまだ,MyFractionはクラス定義がされただけで,インスタンスは存在していない.
ええ。していません。証拠に、MyFraction allInstances size を print-it しても 0 と返ってくるはずです。--sumim - 2002-12-03, 18:00:07
>MyFraction allInstances sizeをprint-it
はい,確かに0となりました.
さて,だらだらと整理になったかどうか?な事を書き連ねてみましたが.帰る道すがら,何がしっくりしてないかをず〜っと考えていたのです.つまるところは,メタクラスの存在です.メタクラスが存在する事の意味が今一つ掴み切れていないようです.なぜ,MyFraction classが必要なのか?なぜ,Metaclassから直接MyFractionを作れないのか?ここが原因のようです.--人狼 - 2002-12-03, 19:47:16
つまりこういうことです。通常、考えられるようなオブジェクトだけ扱うなら、その定義を“クラス定義”として記述すれば済むわけです。しかし、Smalltalk ではクラスも、そのインスタンスの定義を情報として保持するオブジェクトとしてクラスのインスタンスと平等に扱うことができたら便利だろうと、そうするための仕組みを整備したわけです。で、実際に便利なことがあることをクラスの動的な生成などの実例を通じて見ていただきました。クラスをオブジェクトとして扱うためにはそのクラス、つまりメタクラスが必要になります。我々はそこにクラスの振る舞いを記述します。たしかに、Metaclass にその役割りを与えることもできますが、何千とあるクラスを Metaclass ひとりに任せるのには荷が重すぎます。そもそも、全クラスに対して画一的な定義を書けたところでどの程度のメリットがありましょうか。そこで、メタクラス-クラス、クラス-インスタンスという二重構造にし、十分抽象化されて、我々が各々に機能を付加する必要のないメタクラスのクラスとして Metaclass を位置づけたのでしょう。で、Metaclass も別格にはせず、そのクラスである Metaclass class は Metaclass のインスタンスとした。こういうくだりだと思います。--sumim - 2002-12-03, 20:55:19
>メタクラス-クラス、クラス-インスタンスという二重構造にし、十分抽象化されて、我々が各々に機能を付加する必要のないメタクラスのクラスとして Metaclass を位置づけたのでしょう
抽象化なのですね.このようにご説明頂くと,まさにその通りで,理解できた気がするのです.確かに先の例でクラスの動的な生成を通じてクラスがオブジェクトである事の利便性も判りました.
メタクラスが存在する事により,Metaclassは十分抽象化された状態で,個々のオブジェクトによらず存在出来るのですね.有り難うございます.--人狼 - 2002-12-03, 21:17:08
さて,そこでまた新たな疑問なのですが.先日SrginはString classの唯一のインスタンスでる,とのご説明を頂きましたが…先程作ったMyFractionもMyFraction classの唯一のインスタンスであるのではないでしょうか?もっと言うと,全てのメタクラスは唯一のインスタンスを持つと言えないでしょうか?--人狼 - 2002-12-03, 21:19:08
>全てのメタクラスは唯一のインスタンスを持つ
そのとおりです。メタクラス Hoge class は、クラス Hoge という唯一のインスタンスを持ちます。例えば、String class allInstances size
MyFraction class allInstances size
は、それぞれ必ず 1 になるはずです。--sumim - 2002-12-03, 21:57:21
>メタクラス Hoge class は、クラス Hoge という唯一のインスタンスを持ちます
なるほど,了解です.allInstances size試してみました.確かにそれぞれ1となりました.--人狼 - 2002-12-03, 22:09:30
おはようございます.
クラスとメタクラスについては,やっと気持ちがすっきりしました.お世話をかけました.
話しを少し戻して…また自分の整理もかねてダラダラ書きますが…
>唯一の例外で、ProtoObject classのスーパークラスはClassになります
はい,これは確認出来ました.確かにClassがスーパークラスになっています.hoge-super→hogeと言う継承関係とhoge-super class→hoge classと言う継承関係が原則なのだけど,ProtoObject classのスーパークラスはClassと言う事,即ちメタクラスで無い物からメタクラスが継承されていると言う事で例外なのですよね.このClassとは何者なのかが判っていないので恐縮なのですが.(Classと言う名前からして怪しいのですが)
>ProtoObject がメタクラスを含めたすべてのクラスのスーパークラスになることができる
なので,Classと言うクラスは何ぞや,と言うところが判らないと,ここへ進めないみたいです.--人狼 - 2002-12-04, 09:16:48
いや。ここは Class に何が記述されているかというよりは、Class → ProtoObject class という例外的スーパー-サブクラス関係を設けることによって、メタクラス間の継承ラインが ProtoObject class でとぎれず、Class より上のクラス間の継承ラインに合流する点に注目していただきたいと思います。メタクラスの存在により、クラスはメッセージを受けたりそれに反応できるように(つまりオブジェクトとして振る舞えるように)なり、Class の存在により、すべてのクラス定義と同様に、メタクラス定義も ProtoObject や Object 定義の継承が可能になる…という話です。繰り返しになりますが、ProtoObject(通常は Object )に記述すれば、そのメソッドは、インスタンスのみならず、クラスでも、とにかくオブジェクトなら誰にでも(オーバーライドされて無効化ないかぎり)起動可能になる…ということがここでは大切なのです。--sumim - 2002-12-04, 10:35:10
論よりコードで、実際に、Object に jinro2 というメッセージを定義してみましょう。ブラウザは開いていると思いますので、クラスカテゴリペインで cmd-f とし、Object と入力して accept します。改めて、メッセージカテゴリペインに squab testing などとしたカテゴリを設け、コードペインにjinro2
^ #jinro2
とタイプして accept してください。これでクラスとそのインスタンスの別なくすべてのオブジェクトが jinro2 というメッセージに応答できるようになったわけです。もし、Class → ProtoObject class という例外がなかったら、Object class にも同じ定義を入れないと、オブジェクトとしてのクラスはこのメッセージに応答できなくなります。--sumim - 2002-12-04, 10:45:22
>ここはClassに何が記述されているかというよりは、Class→ProtoObject classという例外的スーパー-サブクラス関係を設けること
確認なのですが,この「例外的」と言うのは「メタクラスが,クラスから継承されている」と言うことでしょうか?
>Classより上のクラス間の継承ラインに合流する点
上流にも継承関係があると言うのはこの記述から判りました.Class→ProtoObject classという例外的スーパー-サブクラス関係と言う事なので,上流でもクラスはクラスと,メタクラスはメタクラスとの継承関係を保っているのだと推測しているのですが,正しいでしょうか?
>Classの存在により、すべてのクラス定義と同様に、メタクラス定義もProtoObjectやObject定義の継承が可能
ここが未だに「なぜなのか」判らないままです.すみません.Classに記述すれば,メタクラスにもクラスにも継承されると言うのであれば判るのですが,ProtoObjectに記述したとしても,それはクラスの方の継承関係だけで,メタクラスに影響は及ぼさないのではないか…と思うのです.--人狼 - 2002-12-04, 11:24:07
>論よりコード
と言う事でObjectにjinro2を定義してみました.確かにクラスでもメタクラスでも反応します.
MyFraction jinro2 #jinro2
MyFraction class jinro2 #jinro2
となりました.--人狼 - 2002-12-04, 11:27:32
あれ?そもそも.
Classの継承関係は
ProtoObject→Object→Behavior→ClassDescription→Classとなっていて,
ClassがProtoObjectの下流にいますよね?…だから,Class→ProtoObject classと言う継承関係が理解できないみたいです.--人狼 - 2002-12-04, 11:33:51
>この「例外的」と言うのは
原則としてメタクラスの継承関係は、対応するクラスのそれに準じる、に対する例外です。--sumim - 2002-12-04, 11:43:00
>だから,Class→ProtoObject classと言う継承関係が理解できない
すでに申し上げたとおり、ここで“合流”しているのです。--sumim - 2002-12-04, 11:45:38
>原則としてメタクラスの継承関係は、対応するクラスのそれに準じる、に対する例外
了解しました.いや,そうですね.この原則を失念していました.--人狼 - 2002-12-04, 11:51:45
>ここで“合流”しているのです
う〜ん,すみません,一度図を描いて整理してみた方が良さそうです.ちょっと悩んでみます.--人狼 - 2002-12-04, 11:54:40
>上流でもクラスはクラスと,メタクラスはメタクラスとの継承関係を保っている
たぶん、このひとことに象徴されるように、おそらく人狼さんはスーパー-サブクラス関係による“継承”と、クラス-インスタンス(あるいはメタクラス-クラス)の“定義被定義”関係が分離できていないのではないかと…(^_^;)。--sumim - 2002-12-04, 11:55:30
繰り返しになりますが、クラスはオブジェクトの振る舞いを記述する場、メタクラスは、クラスをオブジェクトとして機能させるための工夫。Metaclass は、クラスのクラスの…の無限地獄にならないための工夫。スーパークラスは、おのおののクラスですべてを記述せずにすませるための“差分定義”のための工夫で、Class → ProtoObject class の例外的継承は、ProtoObject(通常は Object )で定義した内容を、先のメタクラスの工夫によってオブジェクトとなったクラスも含めたすべてのオブジェクトに反映させるための工夫です。--sumim - 2002-12-04, 12:02:05
>スーパー-サブクラス関係による“継承”と、クラス-インスタンス(あるいはメタクラス-クラス)の“定義被定義”関係が分離できていないのではないか
いや,あの(^^;
クラス−インスタンスの関係は「クラスが定義して,インスタンスが生成される」ですよね.で,ここで大事なのは「クラスも実はインスタンス」なので,クラスのクラス(=メタクラス)が必要なり…と.ただし,クラス−メタクラスの関係と言うのはクラスをインスタンスとして考えた時にはクラス定義が必要と言うだけで,その本質的な関係はクラス−インスタンスの関係と何ら変わらない.ただし,これではメタクラスのクラスと言う物を考えなくてはならず,さらにはメタクラスのクラスのクラス…と言うように際限ないので,メタクラスのクラスはMetaclassを導入して終わりにした.
スーパー-サブの関係は,スーパークラスの持っているインスタンス変数・メソッドをすべて継承してサブクラスを作成する事により,1からサブクラスを作る必要はなく,サブクラスにはその必要とするインスタンス変数やメソッドのみを追加すれば良いとのアイディア.
ですよね?--人狼 - 2002-12-04, 12:13:02
>Class→ProtoObject classの例外的継承は、ProtoObject(通常はObject)で定義した内容を、先のメタクラスの工夫によってオブジェクトとなったクラスも含めたすべてのオブジェクトに反映させるための工夫
う〜んと…ProtoObjectで定義した内容(いったん,Objectは置いておかせてください,)は,どんどん継承されてClassも継承している.だからこれを継承しているProtoObject classもProtoObjectで定義した内容を継承している.なので,オブジェクトであるクラスも,インスタンスも含めて,すべてのオブジェクトに反映される.ここで,通常はProtoObjectではなくて,Objectに定義を書く…とこう言う事でしょうか?(すみません,長いことかかりまして(汗))--人狼 - 2002-12-04, 12:17:38
まったく問題ないと思います。しっくりいかない部分はありますか?--sumim - 2002-12-04, 12:22:20
いえ,お陰様ですっきりしました.有り難うございます.長々と引っ掛かってすみませんでした.--人狼 - 2002-12-04, 12:52:12
で、この仕組み( Object はすべてのくラスのスーパークラスである)とオーバーライドを利用すると、あるオブジェクトに対して、お前は○○か?という問いかけを、簡単に実装できます。これを試してみましょう。ここで、isJinro というメッセージを想定します。このメッセージを送ると、MyFraction とそのインスタンスは true を、それ以外のオブジェクトは false を返す…という仕様にします。ああ、その前に、MyFraction のインスタンスの作り方を説明しておかないといけませんね。--sumim - 2002-12-04, 13:16:17
MyFraction にメッセージを送ってそのインスタンスを作るには、そのスーパークラスの定義を利用する方法がありますが、ここでは基本から押さえておきましょう。クラスのインスタンスを作るにはクラスに new というメッセージを送ります。MyFraction new
これを inspect-it するとインスペクトできます。--sumim - 2002-12-04, 13:20:10
ここで、new は単純にインスタンスを生成するだけで、そのインスタンス変数になにかを束縛したりする作業はいっさいしない(したがって、それらにはデフォルトの nil がつながっている)という点に注意してください。--sumim - 2002-12-04, 13:21:48
>クラスのインスタンスを作るにはクラスに new というメッセージを送ります
了解です.これでインスタンスが作れるわけですね.inspect-itしてみました.確かに何も束縛されていません.--人狼 - 2002-12-04, 13:25:49
インスペクタには、インスタンス変数に束縛されているオブジェクトを変更する機能があるのでここでそれをすることもできますが、やはりオブジェクトにはメッセージを送って値を設定したいですよね。--sumim - 2002-12-04, 13:26:26
>やはりオブジェクトにはメッセージを送って値を
えぇ,その方がやりがいがあります.--人狼 - 2002-12-04, 13:29:59
インスペクタで self をクリックして選択して、黄ボタンメニューから inst var defs... を選択します。これは、インスタンス変数を列挙して、それに何かを束縛している式(平たく言えば代入文)を含むメソッドを一覧する機能です。4つのインスタンス変数それぞれについて、指定したオブジェクトを束縛するためのメソッドが用意されているかどうかを確認します。すると、jinro2 だけないことが分かります。当たり前ですが(^_^;)。--sumim - 2002-12-04, 13:34:30
>4つのインスタンス変数それぞれについて、指定したオブジェクトを束縛するためのメソッドが用意されているかどうかを確認します。
しました.インスタンス変数が一覧表示される時点で,既にjinro2だけが線で区切られていますね.numeratorとdenominatorはメッセージセレクタになっていて,二つを一緒に引数として渡さなくてはならない事が判ります.(分数ですから,当然ですね)
すると、jinro2だけないことが分かります
はい,先程Objectで定義したのはJinro2の内容を返すメソッドで,何かを束縛させるメソッドは作っていないからですね.--人狼 - 2002-12-04, 13:40:38
そこで、MyFraction に accessing... というカテゴリを作り、jinro2 、jinro2: を定義しましょう。これで、それぞれのメッセージ(メッセージセレクタでいうところの setNumerator:denominator: 、jinro: 、jinro2: )を送ることで、すべてのインスタンス変数に自由な(numerator と denominator には約分されてしまう仕組みがあるので整数に限られ何でも…というわけにはいきませんが)オブジェクトを束縛することが可能になります。--sumim - 2002-12-04, 13:42:13
>先程Objectで定義したのは
え〜と。先ほど Object に定義したのは、jinro2 というメッセージを受けたときに #jinro2 というシンボルを返すメソッドで、MyFraction のインスタンス変数の jinro2 とはいっさい関係ありません。ちなみに MyFraction のインスタンス以外、jinro2 というインスタンス変数を持たないので、Object でおっしゃるとおりのメソッドを組もうとしても「そんなインスタンス変数なんぞしらんよ…」ということで accept 時に修正を迫られてしまいます。--sumim - 2002-12-04, 13:47:40
>MyFraction に accessing... というカテゴリを作り、jinro2 、jinro2: を定義しましょう
これは,Objectで定義したjinro2をオーバーライドすると言う事でしょうか?Objectでは確かシンボルを返していましたよね.--人狼 - 2002-12-04, 13:49:36
>先ほど Object に定義したのは、jinro2 というメッセージを受けたときに #jinro2 というシンボルを返すメソッドで、MyFraction のインスタンス変数の jinro2 とはいっさい関係ありません
あ,なるほど.ここで言うjinro2と言うのは先だって,instanceVariableNames:に追加してdo-itしたあれですね.間抜けだ.上の質問は無視して下さい.--人狼 - 2002-12-04, 13:52:54
>Objectで定義したjinro2をオーバーライドすると言う事でしょうか?
結果的にはそういうことになります。でも、オーバーライドの話は別でしますので、今は特に気になさる必要はないと思います。--sumim - 2002-12-04, 13:53:13
accesccingカテゴリに定義する内容ですが,
jinro2
^ jinro2
と
jinro2: obj
jinro2 _ obj
でよろしいでしょうか?--人狼 - 2002-12-04, 13:57:11
>オーバーライドの話は別でしますので、今は特に気になさる必要はない
はい,了解です.--人狼 - 2002-12-04, 13:57:42
ここでたまたまオーバーライドの話がでてきましたので、メソッドの呼び方を紹介しておきましょう。今、jinro2 というメッセージセレクタを持つメソッドは2つあることになります。これを区別するのに、それを定義したクラス名を付けて、それぞれ、MyFraction >> #jinro2 、Object >> #jinro2 と呼称します。シンボルで表記するのは、メッセージセレクタの正体がシンボルであることに由来します。これで、単に jinro2 の定義の最後に○○というメッセージ式を追加してと言ったときに生じに混乱はなくなるはずです。--sumim - 2002-12-04, 13:58:29
>インスタンス変数が一覧表示される時点で,既にjinro2だけが線で区切られていますね
これは何か別の要因みたいですね.自分の定義したインスタンス変数であるか,継承したインスタンス変数なのか…かな?--人狼 - 2002-12-04, 13:59:42
>MyFraction >> #jinro2 、Object >> #jinro2 と呼称します
了解しました.このように呼称すると混乱せずに済みます.--人狼 - 2002-12-04, 14:00:34
>継承したインスタンス変数なのか…
そうです。--sumim - 2002-12-04, 14:01:10
では先ほど inspect-it した MyFraction のインスタンスの下のメモ用ペインで、self setNumerator: 3 denominator: 4; jinro: 5; jinro2: 6 などとして、それぞれのインスタンス変数に適当なオブジェクト(この場合、整数が無難かと思います)を束縛させてみましょう。--sumim - 2002-12-04, 14:05:26
all inst vars 欄を選んでおくと、結果の確認が楽です。--sumim - 2002-12-04, 14:07:12
>MyFractionのインスタンスの下のメモ用ペインで
整数でdo-it(しなくちゃダメですよね?メッセージを送るのだから当然ですよね.)してみました.おぉっ!束縛されているっ!--人狼 - 2002-12-04, 14:07:53
これを、まだ存在していない、これから新しく作る MyFraction のインスタンスでも試してみましょう。MyFraction new setNumerator: 4 denominator: 5; jinro: 6; jinro2: 7; inspect
を Workspace でタイプして do-it してみてください。--sumim - 2002-12-04, 14:12:08
>これを、まだ存在していない、これから新しく作る MyFraction のインスタンスでも試して
できました.インスペクタのタイトルもちゃんと(4/5)になりました.--人狼 - 2002-12-04, 14:17:53
そうそう。このタイトル部分に表示される物もちょっといたずらしてオーバーライドのサンプルとしてみましょうか。print-it の結果や、インスペクタのタイトルや、self をクリックしたときに表示される文字列は、各クラスに用意されている printOn: というメソッドで定義されています。これをオーバーライドすることで、自由な表記が可能になります。分数の表現は Fraction >> #printOn: にあるので、これを参考にするとよいと思います。--sumim - 2002-12-04, 14:22:44
MyFraction >> #printOn: の定義は、こんなのではどうでしょう?printOn: aStream
aStream nextPut: $(.
numerator printOn: aStream.
aStream nextPut: $/.
denominator printOn: aStream.
aStream nextPutAll: ') "'.
jinro printOn: aStream.
aStream nextPut: $-.
jinro2 printOn: aStream.
aStream nextPut: $"
--sumim - 2002-12-04, 14:25:38
>print-it の結果や、インスペクタのタイトルや、self をクリックしたときに表示される文字列は、各クラスに用意されている printOn: というメソッドで定義
なるほど.実はこれらは同じメソッドの結果なのですね.--人狼 - 2002-12-04, 14:31:45
さて,ではaStreamとは何ぞや,と.文字列のストリームでしょうか?nextPut:と言うメッセージセレクタは,文字(ひょっとして文字列も?)を引数に取ってストリームに出力せよ,と言うメッセージなのかな?numeratorに始まる4つのインスタンス変数にもprintOn:と言うメッセージセレクタがある…と.と,言う事はこのメソッドはObjectあたりがルーツなのかな?と,言う事で見てみました<Object.よく判らなかったです.--人狼 - 2002-12-04, 14:38:33
ObjectのprintOn:を見た感じでは,やはりaStreamは文字列のストリームみたいです.出力先は判りませんが(汗).先程はNextPut:をもしかしたら文字列も出力出来るかも知れないと考えていましたが,ここにnextPutAllとありますので,はやりあちらは一文字出力なのかな.
Objectの方は,titleと言うローカル変数を宣言して,自分のクラス名を束縛しています.その最初の文字が母音ならanを,そうでなければaをaStreamへ送信し,続いてtitle(即ち,クラス名)をaStreamへ送信しているのですね.--人狼 - 2002-12-04, 15:04:00
いや,そこまで戻らなくともNumberかIntegerでいいのかな?さっきは直接数字オブジェクトを束縛したけど,これは整数と判断されているのかな?--人狼 - 2002-12-04, 15:06:53
aStreamをうまく表現出来ないのですが,MyFraction >> #printOn:は次のような意味でしょうか?
aStreamにnextPut: $(を送信.これは,aStreamのメッセージセレクタnextPut:の引数として$(を取ってメッセージを送信した,と言う事になるかと思います.この結果としてaStreamに(が出力された…と言う解釈でいいのかな?
次にnumeratorにprintOn: aStreamを送信.これは,numerator(=Integerのインスタンス)のメッセージセレクタprintOn:の引数としてaStreamを取ってメッセージを送信した,と.これで,MyFractionが使っているaStreamを使い回して,一つのストリームに文字列をためこんでいると言う事になるのかな?
後は同じような事の繰り返しで,最終的には(分子/分母)"jinro-jinro2"と出力される…と.--人狼 - 2002-12-04, 15:26:06
いろいろ調べていただいたようで、ありがとうございます。よくわからないオブジェクトやメッセージは、とりあえずブラックボックス的に捉えて(必要なら「こんなものだろう…」というような適当な抽象化をして)、まずは全体像を鳥瞰する…というのがオブジェクト指向のスタイルです。こまかいところを突き詰めようとすると、プリミティブ(Smalltalk 仮想マシンを直接叩く命令)やバイトコード(マシン語のようなもの)まで行き着いてしまいますので(^_^;)。逆に、そうした鳥瞰や不明点があってもそれを想像で補完するのに役立つような分かりやすいオブジェクト(クラス)名、メッセージ名、変数名を付けるのがソースコードを記述する上でのマナーと言えるでしょう。
で、くだんのメソッドの内容は、ご推察のとおりでよいと思います。なんかしらのストリーム(これは printOn: がどういうシチュエーションで使われるか…で変わるとおもいます)にインスタンス変数の内容を括弧や / などを交えながら次々と出力する…というものです。--sumim - 2002-12-04, 15:33:34
>まずは全体像を鳥瞰する…というのがオブジェクト指向のスタイルです
そうですね,色々とごちゃごちゃと調べてかえって訳が判らなくなっていました(汗)--人狼 - 2002-12-04, 15:38:21
>くだんのメソッドの内容は、ご推察のとおりでよいと思います
ふぃ〜.良かった良かった.--人狼 - 2002-12-04, 15:38:57
ちょうどよいので、ついでに偽変数 super についても触れておきましょう。super は self とまったく同じで、メッセージを受けたオブジェクトを束縛しており、これを参照するためにメソッド定義の際に用います。ただ、self と違うのは、メッセージを送ったとき、そのメソッドが定義されているクラスにそのメッセージのメソッドが定義されていても無視する…というしくみが働きます。オーバーライドするメソッドの定義中に、オーバーライドしたメソッドを使いたいとき(再帰呼び出しにしたくないとき)に使います。--sumim - 2002-12-04, 15:48:07
たとえば、先刻定義した MyFraction >> #printOn: の内容は、Fraction >> #printOn: の内容と重複している部分があります。この部分を端折って、差分だけを記述したい場合、super を使ってprintOn: aStream
super printOn: aStream.
aStream nextPut: $ .
aStream nextPut: $".
jinro printOn: aStream.
aStream nextPut: $-.
jinro2 printOn: aStream.
aStream nextPut: $"
のように記述できます。--sumim - 2002-12-04, 15:53:00
野暮用があって,遅くなりました.すみません.
さて…
>偽変数superについて
このSuperと言う偽変数は,自オブジェクトのスーパークラスを指しますか?あまり気にしなくて良いのかな?
>オーバーライドするメソッドの定義中に、オーバーライドしたメソッドを使いたいとき(再帰呼び出しにしたくないとき)に使います
と,言う事は
printOn; aStream
self printOn: aStream
等と記述すると再帰呼び出し(と,言ってもこの場合は無限ループですが)になるのでしょうか?--人狼 - 2002-12-04, 22:14:04
>自オブジェクトのスーパークラス
たとえば、MyFraction のインスタンスが Fraction に定義されているメソッドを起動したとき、そのメソッド中の self 、super いずれも MyFraction インスタンス自身を束縛しますが、self は受信するメッセージのメソッド検索を、MyFraction から始めるのに対して、super は Fraction のスーパークラスである、Number から始めます。そのクラス(この場合 Fraction )の同名メソッドを無視する…という言い方をしましたが、super が用いられたクラスのスーパークラスからメソッド検索を始める…というべきでしたね。ごめんなさい。--sumim - 2002-12-04, 22:58:29
>再帰呼び出し(と,言ってもこの場合は無限ループですが)になるのでしょうか?
そういうことになります。--sumim - 2002-12-04, 22:59:08
例えば、Fraction >> #jinro3 を次のように定義したとします。jinro3
^ self jinro2
このときMyFraction new jinro3
を pirnt-it するなどして MyFraction のインスタンスにメッセージ jinro3 を送ると、MyFraction >> #jinro2 が起動されて nil を返します。また、Fraction >> #jinro3 を self ではなく super を用い、jinro3
^ super jinro2
と記述した場合は、Object >> #jinro2 が起動し、結果は #jinro2 となります。--sumim - 2002-12-04, 23:11:08
>self は受信するメッセージのメソッド検索を
なるほど.有り難うございます.わかりました.--人狼 - 2002-12-05, 09:37:53
>Fraction >> #jinro3を次のように定義
やってみました.ご教示頂いた通りの結果です.selfとsuperの違いを体感しました.--人狼 - 2002-12-05, 09:42:25
では、話をもとに戻して続けましょう。先ほど、MyFraction new setNumerator: 4 denominator: 5; jinro: 6; jinro2: 7
などとして、新しいインスタンスを生み出し、そのインスタンス変数それぞれに適当なオブジェクトをつなぎとめる作業をしました。こうした作業を、MyFraction にメッセージを送るだけで済ませてしまいたいという欲求がでてきます。MyFraction の振る舞いを決めるための定義ですから、そのクラスであるメタクラスの MyFraction class に記述すればよいことになりますので、MyFraction を browse-it して、class ボタンをクリックするか、MyFraction を inspect-it して self をクリックして改めて browse-it します。'instance creation' というメッセージカテゴリを新設し、MyFraction class >> #numerator:denominator:jinro:jinro2: をnumerator: numeInteger denominator: denoInteger jinro: jnro jinro2: jnro2
^ self new
setNumerator: numeInteger denominator: denoInteger;
jinro: jnro;
jinro2: jnro2;
yourself
などと記述します。ここで、各インスタンス変数への束縛をそのまま記述することができないことをきちんと認識してください。たとえ親(クラス、MyFraction)であっても、子(インスタンス、MyFraction new)の持ち物(インスタンス変数へのオブジェクトの束縛)を自由にする権限はありません。クラスもインスタンスもオブジェクトとしては平等だからです。--sumim - 2002-12-05, 10:59:20
この場合、MyFraction class >> #new やサブクラスを作ってそこで new を再定義しないかぎり、super でも self でも意味は同じです。どちらにしておいたほうがいいのですかね…。ちょっと頭がこんがらがりますね(^_^;)。--sumim - 2002-12-05, 11:11:49
あと、Fraction >> #setNumerator:denominator: が private であることと、すでに Fraction class >> #numerator:denominator: があることから、これを流用して、numerator: numeInteger denominator: denoInteger jinro: jnro jinro2: jnro2
^ (self numerator: numInteger denominator: denInteger)
jinro: jnro;
jinro2: jnro2;
yourself
numerator: numeInteger denominator: denoInteger jinro: jnro jinro2: jnro2
^ (self numerator: numeInteger denominator: denoInteger)
jinro: jnro;
jinro2: jnro2;
yourself
とするほうがよいかも知れません。--sumim - 2002-12-05, 11:19:34
>MyFractionの振る舞いを決めるための定義ですから、そのクラスであるメタクラスのMyFraction classに記述
はい,その仕組みは判りました.ところで,super new setNumerator:denominator: は,Fractionに送信されると言うことでしょうか?
>各インスタンス変数への束縛をそのまま記述することができない
了解しました.インスタンス変数への束縛を記述するのではなくて,メッセージを送れ,と言う事なのですよね?--人狼 - 2002-12-05, 11:20:03
ちょっと書き直したので、読み返してみてください。すみません。--sumim - 2002-12-05, 11:22:10
>super でも self でも意味は同じ
ありゃ,selfになってる(汗)え〜っと,MyFraction class >> #newを作らないとselfとsuperが同じと言うのは,MyFractionにはnewなるメソッドが無いのでselfで呼び出しても,結局はsuperから継承したメソッドを呼ぶから,と言う事ですよね?サブクラスを作って…と言うのがよく判りませんでした(汗)
>どちらにしておいたほうがいいのですかね…
主観ですが,結果的にsuperのメソッドが呼ばれるにせよ,それはselfにおいて継承されたものを呼んでいるわけですから,selfの方がいいかなぁ,と思います.継承関係においては,よほどの事が無ければスーパーを明示的に考える必要はないと思っているのですが…--人狼 - 2002-12-05, 11:25:15
>Fraction >> #setNumerator:denominator:がprivateであることと、すでにFraction class >> #numerator:denominator:があることから、これを流用
privateは使わない事にしているのでしたよね.で,あれば使わない方がいいんでしょうね.この()はどういう意味でしたでしょうか?評価を先にさせる,と言う優先順位でしたでしょうか?それと,最後のyourselfが初出ですね.--人狼 - 2002-12-05, 11:28:55
>よほどの事が無ければスーパーを明示的に考える必要はない
そうですね。そのように伺うと self のほうがずっとよいような気がしてきました(^_^;)--sumim - 2002-12-05, 11:30:48
>numerator: numeInteger denominator: denoInteger jinro: jnro jinro2: jnro2
重隅っぽくて申し訳ないのですが,ここで定義してある引数と,selfに渡す引数は同じ名前にするのですよね?--人狼 - 2002-12-05, 11:31:20
>ここで定義してある引数と,selfに渡す引数は同じ名前にする
すみません。具体的にはどんな話でしょう?--sumim - 2002-12-05, 11:35:08
>具体的にはどんな話でしょう
すみません,ほんとに細かい話しなのですが.
numerator: numeInteger denominator: denoInteger jinro: jnro jinro2: jnro2
^ (self numerator: numInteger denominator: denInteger)
で定義の方はnumeIntegerですが,selfへはnumIntegerを渡しています.スペルが1字違いなので(汗)--人狼 - 2002-12-05, 11:41:26
>selfのほうがずっとよいような気がしてきました
あう.sumimさんにそうおっしゃっていただくと,妙にプレッシャーと言うか責任感が(大汗)--人狼 - 2002-12-05, 11:42:26
>最後のyourselfが初出
Object >> #yourself を見ていただくとおわかりいただけるように、レシーバ(メッセージを受信したオブジェクト)を単に返すだけのメソッドです。最終的にはレシーバを返したいけど、カスケードで送っているメッセージの返値がレシーバでない可能性があるときに使います。--sumim - 2002-12-05, 11:42:41
>スペルが1字違い
あ、ほんとだ(^_^;)。なおしておきました。結構、重要です。--sumim - 2002-12-05, 11:45:29
>レシーバ(メッセージを受信したオブジェクト)を単に返すだけ
この場合はMyFractionと言う事ですね.
>カスケードで送っているメッセージの返値
この場合のカスケードは,メッセージを受けたオブジェクトが他のオブジェクトにメッセージを送信して,階層的にメッセージが送信されている事を指していらっしゃいますか?--人狼 - 2002-12-05, 11:49:24
>なおしておきました。
おしい(汗)numeInteger→numoIntegerで,eとoが(汗)denoIntegerはOKです.--人狼 - 2002-12-05, 11:51:47
>この場合はMyFractionと言う事ですね.
いえ。違います。前者は self new、後者は self numerator: numeInteger denominator: denoInteger で返ってくるオブジェクト(MyFraction のインスタンス)です。ただ、ここのところは混乱を避けるために私も用いないように心がけていますが、クラス名をして文脈上特定できるインスタンスを呼称する習慣もありますので、それに則っておられるなら問題はありません。--sumim - 2002-12-05, 11:57:17
>メッセージを受けたオブジェクトが他のオブジェクトにメッセージを送信して,階層的にメッセージが送信されている事
( TOSTEM 『スーパーウォール工法』の菊池桃子風…に)いえ、違います。(もしかしてこれってローカル?) ; でメッセージを連ねることで同じオブジェクトに畳みかけるように(返値を無視しつつ)メッセージを送信していることを表わしています。--sumim - 2002-12-05, 12:03:24
>返ってくるオブジェクト(MyFractionのインスタンス)です
なるほど.誤解しておりました.言われてみればその通り.ここでMyFractionが返ってきても仕方ないですね.MyFractionのインスタンス,誤解の原因を考えてみると,MyFraction classのメソッドを定義しているので,その内容が影響を与えるのはMyFractionクラスと言う事に気を取られてしまっていました.MyFrationの振る舞いの結果生成されるインスタンスを失念していました.元々はインスタンスを作ろう,が出発点でしたね.--人狼 - 2002-12-05, 13:08:01
>TOSTEM『スーパーウォール工法』の菊池桃子風…に)
菊池桃子ですか,一文字間違えると大変な事に(笑)
>(もしかしてこれってローカル?)
いや,私が単に地上波を見ない事が原因のような(汗)おかげでHotPepperのCMも見た事が無いのです.噂の「た〜べ〜ま〜し〜た〜」を見たいのですが(泣)誰かビデオ持ってないっすかね(苦笑)あ,話しが逸れたついでに.AC4やってみますか?今私のPS2は修理中ですので,お貸し出来ますよ.
>;でメッセージを連ねることで同じオブジェクトに畳みかけるように(返値を無視しつつ)メッセージを送信していることを表わしています。
なるほど.了解しました.この場合は,各々のメッセージにより,どのような辺値を返してくるか判らないので,最後に「君自身を返しなさい」と言うメッセージを送るのですね.--人狼 - 2002-12-05, 13:11:51
>各々のメッセージにより
より正確には、最後の jinro2: が…ですね。言い方が悪かったみたいです。カスケードは途中の返値は無視されます。--sumim - 2002-12-05, 13:59:00
>HotPepperのCMも見た事が無い
それはいけません。こんど見つけたらとっておきます。--sumim - 2002-12-05, 14:00:57
>AC4やってみますか?
是非! AC でも F-16 は乗れるんでしたっけっか?--sumim - 2002-12-05, 14:04:35
一緒に観たり、プレイするぶんには違法ではないんですよね? …と誰へとはなく(笑)--sumim - 2002-12-05, 14:05:32
>より正確には、最後の jinro2: が
あ,そうですか.いや,当然ですね.おっしゃる通り,途中の辺値を無視していないとカスケードにならないですね.--人狼 - 2002-12-05, 14:11:14
>こんど見つけたらとっておきます
よろしくお願い致しますm(__)m--人狼 - 2002-12-05, 14:11:49
>AC でも F-16 は乗れるんでしたっけっか?
もちろんです.最近お気に入りでいらっしゃるラプターもありです.13日でよろしいですか?(攻略本付きです)--人狼 - 2002-12-05, 14:12:50
>13日で
よろしくお願いします。--sumim - 2002-12-05, 14:14:26
>一緒に観たり、プレイするぶんには違法ではないんですよね
だったと思います.コントローラー2個あれば対戦出来ますね.(私のは修理中)PS2がマルチモニタだったらすごいだろうなぁ.--人狼 - 2002-12-05, 14:15:44
では本論に戻って、new としたときに、numerator 、denominator は無視して nil のままで、jinro と jinro2 だけデフォルトで nil 以外の適当なオブジェクトが束縛されている状態でインスタンスを作りたいと思います(つまり new のオーバーライドですね)。たとえば、jinro には 1 を、jinro2 には 2 をつなげておくことにしましょうか。そうした定義をするには、どういったメソッド(まあ、メッセージセレクタは必然的に new ということになりますが)をどこに組めばよいでしょうか。super の応用問題です。--sumim - 2002-12-05, 14:18:59
>どういったメソッド(まあ、メッセージセレクタは必然的に new ということになりますが)をどこに組めばよいでしょうか。
まず,どこに,の点ですが.MyFraction classのinstance creationcategoryだと思います.
どういったコード,の点ですが
new
^(super new)
jinro: 1;
jinro2: 2;
yourself
と考えました.かなり自信なさげ(汗)--人狼 - 2002-12-05, 14:41:14
いえ。オッケーだと思います。細かいことをいうと 単項メッセージ(new)はキーワードメッセージ(jinro:)に優先するのでこの場合、括弧は無用です。もちろん、読みやすくする配慮なら、余計なことでした。ごめんなさい。さて、すでに MyFraction new で動作を確認していただけているとは思いますが、MyFraction numerator: 3 denominator: 4
も試してください。このとき、jinro 、jinro2 が初期化されている理由を難なく説明していただけるようでしたら、super 周りは問題なしかと存じます。--sumim - 2002-12-05, 14:58:10
>単項メッセージ(new)はキーワードメッセージ(jinro:)に優先するのでこの場合、括弧は無用です
了解です.すみません,そこまで配慮していませんでした.優先順位に自信が無かったので.動作はちゃんと確認しました.
>このとき、jinro 、jinro2 が初期化されている理由
MyFraction class >> #numerator:denominator:は定義されていないので,Fraction classから継承したメソッドの呼び出しになります.このメソッド内で^self new setNumerator: numInteger denominator: denIntegerと言うメッセージ式がありますが,ここでselfはMyFractionのインスタンスですので,先程定義したばかりのnewが実行され,まずjinroとjinro2を初期化して,そのインスタンスに対してsetNumerator:denominator:が実行される.かな?--人狼 - 2002-12-05, 15:13:17
すばらしいですね。まったく問題なさそうです。では、ぼちぼち開発まわりの操作も増えてきましたから、開発者用の UI も紹介しておきましょうか。--sumim - 2002-12-05, 15:18:35
このページを編集 (63685 bytes)
|
以下の 1 ページから参照されています。 |
This page has been visited 6171 times.