vieweditattachhistorytopchangessearchhelp

クラスとインスタンス

Smalltalk の世界ではオブジェクトがすべてを構成していて(「すべてがオブジェクトで構成されている」じゃなくてこう言えばいいんだ(笑) …あんまし変わらんか(^_^;))、オブジェクトはすべてインスタンスです。インスタンスは、必ずなにかしらのクラスに属していて、同じクラスに属すインスタンスは同じ数のインスタンス変数を持ち、同じメッセージに同じように振る舞います。インスタンス変数にどんなオブジェクト(つまり他のインスタンス)を束縛するかはインスタンスごとに自由にできて、この点が同じクラスに属するオブジェクトの“表面上の個性”ということになります。ただ、Smalltalk のオブジェクトは、他のオブジェクトからそのインスタンス変数を直接参照したり、値を変更することを推奨されていません(いちおうできないことになっています)。そこで、他のオブジェクトから、そのオブジェクトの内部状態(インスタンス変数にどんなオブジェクトを束縛しているか)については、注目するインスタンスのクラス定義において、インスタンス変数にアクセスするためのメッセージが登録され、相応のメソッドを用意されている場合のみ(つまり設計仕様でアクセスが許している場合のみ)、そのメッセージを使って知り得る…ということになります。これはセキュリティというよりは、プログラムの保守性や機能の拡張性に重きを置いた仕組みだと考えるほうがよいでしょう。--sumim - 2002-12-02, 10:10:40

すみません.いきなりごちゃごちゃになってしまいました(大汗)
オブジェクトですべてが構成されている→オブジェクトはすべてインスタンス→インスタンスは必ずクラスに属す→フレーム型の立場はどこへ?
(あ,ここでクラスもオブジェクトよね?と言う疑問はここでのテーマなのでとりあえず忘れておいてます)
ん〜と,オブジェクト・インスタンス・インスタンス型・フレーム型・クラスの用語定義が曖昧なのかしら?>自分--人狼 - 2002-12-02, 10:26:17

Smalltalk のオブジェクトはすべてインスタンス型(Smalltalk 型)です。フレーム型はありません。モーフ-プレイヤのしくみは、インスタンス型の枠組みでフレーム型のオブジェクト(の特徴のひとつであるスロットを自由に追加できる仕様)を再現しようとした苦肉の策で、けっしてフレーム型のオブジェクトが存在するわけではありません。--sumim - 2002-12-02, 10:30:28

>Smalltalk のオブジェクトはすべてインスタンス型(Smalltalk 型)です
了解しました.フレーム型のオブジェクトは無いのですね.
念の為に用語定義を再確認させて下さいm(__)m
オブジェクト=ソフトウェアコンポーネント
インスタンス=実体を持つオブジェクト
クラス=オブジェクトの設計図
と,言う認識で誤りはないでしょうか?--人狼 - 2002-12-02, 10:42:30

実体を持つオブジェクトと実体を持たないオブジェクトの違いをお願いします。--sumim - 2002-12-02, 10:48:00

そうそう,もう少し確認したい事がありました.
メッセージ=オブジェクトに送られるもので,オブジェクトに何かの反応を指示するもの
メソッド=オブジェクトがメッセージを受け取った時にどう反応するかを記述したコード
メッセージセレクタ=引数たるオブジェクトを伴いメッセージとなる.
で,良いのでしょうか?--人狼 - 2002-12-02, 10:48:54

そうです。--sumim - 2002-12-02, 10:50:15

>実体を持つオブジェクトと実体を持たないオブジェクトの違い
実体を持つオブジェクト=クラス定義に基づき生成され,メモリ空間を占有する.
実体を持たないオブジェクト=クラス定義そのもの.実体がどう振る舞うかを規定しているだけ.
と考えていました.--人狼 - 2002-12-02, 10:56:57

分かりました。では、
クラス=オブジェクトの設計図
インスタンス=クラス定義に基づき生成されたオブジェクト
といういニュアンスですね。

オブジェクトは「ソフトウエアコンポーネント」だと心許ないので、
とでもしておきましょうか。--sumim
- 2002-12-02, 11:00:42


>クラス=オブジェクトの設計図
>インスタンス=クラス定義に基づき生成されたオブジェクト

はい,その通りです.なんかsumimさんに僕の考えも整理して頂いたようで.有り難うございます.すっきりしました.

>オブジェクトは「ソフトウエアコンポーネント」だと心許ないので、
了解です.--人狼 - 2002-12-02, 11:05:33

では、話を戻して、オブジェクトはかならずクラスに属する、つまり設計図を持つというところから。

class というメッセージをオブジェクトに送るとそのオブジェクトがどのクラスに属しているかを知ることができます。Workspace を開いて、次のメッセージ式を一行ずつ選択し print-it(cmd-p)してみてください。
'string' class
$c class
#symbol class
3 class
true class
false class
nil class
[] class
{} class
#('this' #is $a 10) class
それぞれのオブジェクトがどのクラスに属しているかを知ることができます。--sumim
- 2002-12-02, 11:07:31

>オブジェクトはかならずクラスに属する
了解です.これは大丈夫です.
classはオブジェクトがどのクラスに属しているかを知るメッセージなのですね.今後も多用しそうです.

'string' class String
$c class Character
#symbol class Symbol
3 class SmallInteger
true class True
false class False
nil class UndefinedObject
#('this' #is $a 10) class Array

でした.あらかた予想通りの感じでしたが,nilが違ってました.てっきりNSObjectみたいなのが返ってくると思ったのですが…「何も無い」事を示すオブジェクトでも帰ってくるのか…と.あ,でも考えてみたらsymbolと言うクラスも正体不明です(汗)--人狼 - 2002-12-02, 11:16:03

Symbol は String とよく似ていますが、同じ内容のものはひとつしかないことを保証されたオブジェクトです。--sumim - 2002-12-02, 11:20:13

ありゃ追加が(汗)
[] class BlockContext
{} class Array

となりました.{}は配列なのですね.上の
#('this' #is $a 10)
も配列でしたね,そう言えば.これはどう解釈するんだろう.
BlockContext
は以前ifTrue:ifFalse: の時に出てきましたね.--人狼 - 2002-12-02, 11:20:34

nil は文字通り、何もないことを示し、そのクラス名が示すとおり、未定義のオブジェクトとしてそこここで見かけます。たとえば、変数を定義するとそれはデフォルトで nil を束縛しています。--sumim - 2002-12-02, 11:22:10

>SymbolはStringとよく似ていますが、同じ内容のものはひとつしかないことを保証
ある文字列は,あるSymbolオブジェクトと一対一に対応すると言う事でよろしいのでしょうか?--人狼 - 2002-12-02, 11:29:21

上で挙げた class を送信した記述は、いわばリテラル式、リテラル(見方を変えれば偽変数)と言えます。つまり、文字列、文字、シンボル、数値、真偽値、未定義値、ブロック、配列はそのものを記述できます。他に分数、座標についてはメッセージ式ではありますが、リテラル感覚で記述できます。
(3/4) class
(3@4) class
オブジェクトにはたいてい名前などによって参照する方法がないので、自身を書き下せるこれらは特殊な例だと考えてよいでしょう。--sumim
- 2002-12-02, 11:29:22

nilについては了解です.未定義のオブジェクトであり,何もないことを示すのですね.
>変数を定義するとそれはデフォルトで nil を束縛
この「束縛」と言うのがよく判らないのですが…--人狼  - 2002-12-02, 11:31:11

ある文字列は,あるSymbolオブジェクトと一対一に対応する
いえ、文字列とシンボルは別物です。たとえば 'string' という文字列は、同じ 'string' と表現できるインスタンスの共存を許しますが、#stirng というシンボルはこれひとつしかない、ということです。つまり #string と書けば、唯一無二の #string を指し示すことができるわけです。--sumim
- 2002-12-02, 11:31:57

>文字列、文字、シンボル、数値、真偽値、未定義値、ブロック、配列はそのものを記述
これらだけがリテラル式として表す事が出来る.そして分数と座標についてはリテラル風にメッセージ式で記述出来る.と,言うことですね.文字リテラルの囲みはシングルクォーテーションですね.--人狼 - 2002-12-02, 11:34:08

代入というと変数の数だけ nil があるようなニュアンスが生じてしまいますが、世の中に nil はひとつだけなので、nil につながっている、を参照できるようになっている…というニュアンスで束縛という言葉を使っています。もうひとつ、Smalltalk ではオブジェクトは、他のオブジェクトから参照されていないかぎり、消滅する運命にあります。つまり束縛されていると安泰だということです。--sumim - 2002-12-02, 11:35:37

>つまり#stringと書けば、唯一無二の#string
う〜んと,'string'は文字列であるので,他に'string'と表現出来るインスタンスの共存を許す.インスタンスだから当然.
#stringと書けば,唯一無二の#string.「#」から始まるのがシンボルですよね.この場合,#stringは名前になるのでしょうか?それとも値?--人狼 - 2002-12-02, 11:38:06

文字リテラルの囲みはシングルクォーテーション
そうです。ちなみにダブルクオーテーションはコメントになります。自分のくくりの中で自分を表わすには重複して記述します。
'''this'' is a pen'
"that ""is"" a pencil"
という具合です。お互いではお互いを普通にに使えます。
'"this" is a pen'
"that 'is' a pencil"
こんな感じに。--sumim
- 2002-12-02, 11:38:47

#stringは名前になるのでしょうか?それとも値?
値です。リテラルなので名前とも言えます。--sumim
- 2002-12-02, 11:40:28

nilにつながっている、を参照できるようになっている…というニュアンスで束縛という言葉を使って
nilを束縛=nilを参照(またはnilと関係がある)と言う解釈でよろしいのでしょうか?
>他のオブジェクトから参照されていないかぎり、消滅する運命
他のオブジェクト(クラスでも,インスタンスでもなく,オブジェクト?)から参照されていないと消滅してしまうんですね.どのタイミングで消滅するかはシステム任せなのですね.あれ?でもクラスまで消えてしまっては,ダメですよね.--人狼 - 2002-12-02, 11:43:07
>ちなみにダブルクオーテーションはコメント
了解しました.
>自分のくくりの中で自分を表わすには重複して記述
これも了解しました.
'''this'' is a pen'は文字列としては'this' is a penになるのですね.
>お互いではお互いを普通にに使えます
了解しました.--人狼 - 2002-12-02, 11:46:32
>値です。リテラルなので名前とも言えます。
了解しました.リテラルですものね.リテラルもオブジェクトですものね.--人狼 - 2002-12-02, 11:47:37

nilを束縛=nilを参照(またはnilと関係がある)と言う解釈
私は手を伸ばして物をがっちり掴んでいるイメージでいます。--sumim
- 2002-12-02, 11:51:36

でもクラスまで消えてしまっては,ダメですよね.
では、そのクラスに話をもってゆきましょう。すでに意識しておられるように Smalltalk ではクラスもオブジェクトです。すなわちインスタンスです(笑)。--sumim
- 2002-12-02, 11:55:18

>私は手を伸ばして物をがっちり掴んでいるイメージ
う〜む,まさしく束縛ですね.そのイメージで考えていきます.--人狼 - 2002-12-02, 11:59:44

>Smalltalk ではクラスもオブジェクトです。すなわちインスタンスです
う〜,ここです,ここ!これでクラスとオブジェクトとインスタンスの関係が判らなくなってるんです(号泣)と,これから病院です.風邪が悪くなってきました.--人狼 - 2002-12-02, 12:00:39

おだいじに。適当に進めておきます(笑)。--sumim - 2002-12-02, 12:01:43

こんがらがったときは、もういちど、オブジェクトとインスタンスとは何だったかを考えてみましょう。オブジェクトはメッセージに反応できるデータでしたね。クラスがオブジェクトであるということは、クラスがメッセージを受信でき、それに反応を返すことができることを示します。もうひとつ、Smalltalk ではオブジェクトはすべてインスタンスであることから、すべてのオブジェクトはその定義を記述した何かを持つことを意味します。オブジェクトであるクラスもしかりで、その定義を記述した何かの存在が示唆されるわけです。--sumim - 2002-12-02, 12:10:00

クラスがメッセージを受信できる例はいろいろありますが、身近なところで、
(SketchMorph withForm: Form fromUser) openInHand
なんかどうでしょう。--sumim
- 2002-12-02, 12:18:11

Form は fromUser というメッセージを受けて、画面の一部を切り取ったフォーム(画像情報、Form のインスタンス)を返します。これを引数にして、SketchMorph は withForm: というメッセージを受けて、SketchMorph のインスタンス、スケッチモーフ(SketchMorph のインスタンス)を返します。このスケッチモーフに openInHand というピックアップするためのメッセージを送ると、試してみていただいた通りの状況になります。--sumim - 2002-12-02, 12:20:54

他方、定義を記述した“何か”の存在ですが、インスタンスにおいてそれはクラスですから、クラスにおいてもしかりで、インスタンスとしてのクラスのクラス、とうことになります。クラスのクラスですからメタクラスと呼ぶことががあります、が、本質的にはインスタンスの定義を記述したものがクラスであるように、メタクラスもインスタンスとしてのクラスの定義を記述してあるものにすぎず、クラスそれ自身となんら変わらない位置づけにあります。--sumim - 2002-12-02, 12:26:27

クラスも class というメッセージを受け付けますので、メタクラスがなんであるかを知ることはできますが、多くのオブジェクトに名前がないのに倣って、そしてクラスと違ってメタクラスには名前がありません。
String class
Charactor clsss
Symbol class
SmallInteger class
True class
False class
UndefinedObject class
BlockContext class
Array class
いずれを print-it しても Hoge class としか返ってこないと思います。つまり、メタクラスは、そのクラス名+ class で表記し、これはそのままメッセージ式になっていて評価することでそのオブジェクト(当然メタクラスもオブジェクトなので)を参照できるからくりになっています。--sumim
- 2002-12-02, 12:30:42

まず…クラスがオブジェクトである事は事実として受け入れてはいるんです.(それが,どう有効または有用であるかは,まだ判っていません.)
>クラスがオブジェクトであるということは、クラスがメッセージを受信でき、それに反応を返すことができる
これは判ります.問題は,
>オブジェクトであるクラスもしかりで、その定義を記述した何か
にあるのです.ご説明頂いたように,インスタンスとしてのクラスのクラス(=メタクラス)である,と.そしてメタクラスもオブジェクトであるのですよね.
と,なるとメタクラスの定義はどこに?と,言う疑問になってしまいます.ここでループになっています.卵が先か鶏が先か…に似たループなのかなぁ.--人狼 - 2002-12-02, 13:12:07

メタクラスの定義はどこに?
是非、調べてみてください。オブジェクトは class というメッセージを受けて、そのクラスを返します。--sumim
- 2002-12-02, 14:25:51

是非、調べてみてください。
う〜ん,理解が全然足りてないですねぇ.
String classclassを送るとMetaclassが返ってきます.このMetaclassclassを送ると返ってくるのはMetaclass classMetaclass classclassを送るとMetaclassが返って来て,手詰まりになってしまいます.

ちなみに,試しにMetaclassbrowse-itしてみるとClassDescriptionでした.これを更にbrowse-itするとBehaviorです.更にObjectとなり,ProtoObjectに辿り着きます.しかし,この時は
ProtoObject subclass: #Object
instanceVariableNames: ''
classVariableNames: 'DependentsFields EventsFields '
poolDictionaries: ''
category: 'Kernel-Objects'
となりますが,これを再度browse-itすると
ProtoObject subclass: #ProtoObject
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Kernel-Objects'.
ProtoObject superclass: nil
となり微妙に違うのも気になります.--人狼 - 2002-12-02, 14:47:48
>試しにMetaclassをbrowse-itしてみると
さらに(それが,良い事か悪い事かはおいといて)興味があったのでInspect-itしてsuperclassを追いかけてみました.MetaclassClassDescriptionBehaviorObjectProtoObjectnilとなりました.nil?--人狼 - 2002-12-02, 15:20:29
browse-itの場合はProtoObjectが2回出てくるのにInspect-itの場合は1回と言うのも謎です.最後はnilに行き着くのもなんか怪しいし.手法が違うのかなぁ.--人狼 - 2002-12-02, 15:22:47

スーパークラスの説明はまだしていないので、たぶんごっちゃになっています。どんづまり以下は忘れてそこまでで議論してみてください。--sumim - 2002-12-02, 15:34:30

>どんづまり以下は忘れてそこまでで議論してみてください。
オブジェクトにclassメッセージを送ると,そのオブジェクトがどのクラスに属しているか判る.'string' classStringにより,リテラル文字列がStringクラスに属している事が判る.
クラスもオブジェクトなので,classメッセージを受ける.これにより,「オブジェクトであるクラス」がどのクラス(=メタクラス)に属しているかを調べられる.String classString classにより,StringクラスのメタクラスがString classである事が判る.
このメタクラスもオブジェクトであるので,classメッセージを送り,そのメタクラスを知る事が可能.
String class classMetaclassにより,String classのメタクラスはMetaclassである事が判る.このMetaclassもオブジェクトであるので,classメッセージを送るとMetaclass classが返ってくる.これにより,MetaclassオブジェクトはMetaclassクラスのインスタンスである事になり,Metaclassの上位のクラスは存在しない.
と,言う風になりましょうか?--人狼 - 2002-12-02, 15:58:48

さいごがちょっと。今のところのテーマは、オブジェクトはすべからくその定義を記述した何かがあるかどうか、ということでしたよね? 一般的なオブジェクト、Hoge のインスタンスには Hoge というクラスがある。この Hoge クラスもまたインスタンスで、そのクラスは Hoge class である。Hoge class もまたインスタンスで、そのクラスは Metaclass である。Metaclass もインスタンスで、そのクラスは Metaclass class である。Metaclass class もまたインスタンスでそのクラス(ではないけれども…、その定義を記述している何か)は Metaclass である、と。よって、すべてのオブジェクトには(Metaclass class を例外にして)必ずクラス、つまり定義を記述している何か(これは Metaclass class にも存在する)があり、すべてのオブジェクトはインスタンスだと言える。ってのはどうでしょうか?--sumim - 2002-12-02, 16:08:45

あと、すべてのメタクラス(Metaclass class を含めて)のクラスは Metaclass である、という図式もありますね。そう考えると、Metaclass class のクラスが Metaclass というのも一概には例外だとは言えない、とも。--sumim - 2002-12-02, 16:12:53

>オブジェクトはすべからくその定義を記述した何かがあるかどうか
はい,そうでした.「定義をした何か」と言う事を失念してクラスにこだわりすぎたみたいです.
ご説明を読んだのですが,MetaclassのクラスがMetaclss classであるところまでは判ったのですが,Metaclss classの定義を記述している何かがMetaclassである,と言う事ですよね?そうなるとMetaclassの定義がMetaclss classにあって,Metaclss classの定義がMetaclassにあるとなり,ここが循環参照みたいな感じで自分の中で解決出来ていません.
>すべてのメタクラス(Metaclss classを含めて)のクラスはMetaclassである
これは,突き詰めて行けばどのクラスのメタクラスもMetaclassに行き着くと言う事でしょうか?--人狼 - 2002-12-02, 16:26:33

突き詰めて行けば
突き詰める…というあたりに感じるのはたぶん、スーパークラスの継承とごっちゃになっているんじゃないかなぁ…と。今はクラスとインスタンスの話なので、どんなオブジェクトにもクラスがある…っていう親子一対だけの話で、巡回とか突き詰める必要はないと思いますが、いかがでしょう。--sumim
- 2002-12-02, 16:55:52

で、大切なことは、メソッドやインスタンス変数を定義する場所は、そのオブジェクトのクラスである…というごく当たり前の文章(でも当初のご理解とは意味が異なる…はず)に集約されるわけです。--sumim - 2002-12-02, 17:08:11

>突き詰める…というあたりに感じるのはたぶん、スーパークラスの継承とごっちゃになっている
そうなのでしょうか?(汗)う〜んと…StringクラスのメタクラスがString classで,このメタクラスのクラスはMetaclassですものねぇ.そう言われてみればメタクラスのクラスはこの場合はMetaclssですね.あ,ここで「もう一階層あったら」と考えるのが,そもそも継承を意識してるって事なんですよね(大汗)
>どんなオブジェクトにもクラスがある
すべてのオブジェクトには,その定義をしている何かがある,までは判るのです.ただ,やはりMetaclassのクラスがMetaclass classで,Metaclass classのクラスMetaclassと言うところが悩ましいのです.とは言え,
>親子一対だけの話で、巡回とか突き詰める必要はないと思いますが、いかがでしょう
と,ありますのでMetaclassから見ると定義はMetaclass classにある.そこで終わり.同様にMetaclass classから見ると定義はMetaclassにある.そこで終わり.と一対で打ち切ってしまえば,とりあえずは「どんなオブジェクトにもクラスがある」となりますので,OKです.--人狼 - 2002-12-02, 17:16:43

OKです
何より(笑)。--sumim
- 2002-12-02, 17:19:09

で、練習問題ですが、どんなメタクラスに jinro というメッセージを送っても #jinro というシンボルを返すメソッドを仕込みたいと思います。どこに定義したらよいでしょう?--sumim - 2002-12-02, 17:22:49

>メソッドやインスタンス変数を定義する場所は、そのオブジェクトのクラスである…というごく当たり前の文章(でも当初のご理解とは意味が異なる…はず)に集約される
文章としては確かに当たり前なのですが,そもそもクラスもオブジェクトなわけですから…オブジェクトに定義と言う事になるのでしょうか?当初はクラスは設計図と言う認識でしたから,ソースコードを直して,コンパイルして,クラスが利用されて初めて新しい定義が生きると思っていたのですが,そうでもなさそうな気がします.
>すべてのメタクラスに jinro というメッセージを送ると #jinro というシンボルを返すメソッドを仕込みたい
すべてのメタクラスに,と言う事であればMetaclassに定義しなくてはならないのではないでしょうか?--人狼 - 2002-12-02, 17:28:12

当初はクラスは設計図と言う認識
設計情報を保持したオブジェクトなんです。--sumim
- 2002-12-02, 17:30:52

Metaclassに定義しなくてはならない
そうです。では実際にやってみましょう。まず、適当なメタクラス SketchMorph class でも、String class でも構いませんので、それに jinro というメッセージを送ってもノーティファイアが出てしまうことを確認します。次に、Metaclass を browse-it し、メッセージカテゴリリストの黄ボタンメニューから new category... を選択、ポップアップメニューから new... を選び、squab testing などととして accept します。続けて、コードペインで、
jinro
    ^ #jinro
と入力し、accept します。accept と同時にコンパイルとリンクが終わってすべてのメタクラスは jinro というメッセージに応対できるようになりますので print-it で確認してみてください。--sumim
- 2002-12-02, 17:35:29

^ はそうタイプすると、画面には ↑ と表示されます。これは(続くメッセージ式があってもそれを無視して)^ 以下のメッセージ式の評価結果を返してメソッド終了、という意味があります。--sumim - 2002-12-02, 17:37:44

>設計情報を保持したオブジェクト
ですね,おっしゃる通りだと思います.クラスは定義を記述したものであり,クラスもオブジェクトなわけですから,そう言う事になりますね.--人狼 - 2002-12-02, 17:36:44

jinroというメッセージを送ってもノーティファイアが出てしまうこと
は確認できました.その後,指示通りにやったつもりなのですが,String jinroprint-itするとMessageNotUnderstood: jinroと言うタイトルのウィンドウが表示されます.内容は…まだ読み解けません(汗)--人狼 - 2002-12-02, 17:47:36

いや、Metaclass にメソッドを仕込んだので、そのインスタンスであるメタクラス、この場合なら String ではなく String class にメッセージを送る必要があります。--sumim - 2002-12-02, 17:49:08

あぁ,そうですね.失礼しました.String classで,#jinroが表示されました.Metaclass classCharacter classでも確認しました.
Metaclassにメソッドを仕込んだので,そのインスタンスにメッセージを送らなくてはならないのですね.--人狼 - 2002-12-02, 17:53:16

そうです。まだ大丈夫ですか?>お時間。--sumim - 2002-12-02, 17:53:57

すみません,そろそろ帰り支度を始めようかと(汗)今日は薬を飲んでゆっくり寝ようと思っています.--人狼 - 2002-12-02, 17:56:37

了解です。適当に書き進めておきますので、明日にでも。 おだいじに。--sumim

申し訳ありません,また明日よろしくお願いします.明日は元気に復活したいと思います.--人狼 - 2002-12-02, 17:59:35

inspect-it(cmd-i)で開く、インスペクタは、そのオブジェクトの内部情報、具体的にはインスタンス変数の数、名前、それらが束縛しているオブジェクトの一覧を表示したり変更するツールです。--sumim - 2002-12-02, 17:56:56

これは人狼さんの言葉を借りれば「実体を持ったオブジェクト」のブラウザということになります。ちなみに、このウインドウのタイトルは、インスペクトしているオブジェクトの属するクラス…ということになります。また、self を選択して browse-it(cmd-b)すると、システムブラウザを開き、定義を見る(つまり、クラスをブラウズする)ことができます。Workspace などではメタクラスの browse-it はできない(browse メッセージの送信、つまり String class browse などと記述したものの do-it は可能です)ので、理解が進むまでインスペクタを介して browse-it するのもよいかも知れません。--sumim - 2002-12-02, 18:22:51

External Image

External Image

で、システムブラウザですが、これは「実体を持たないオブジェクト」つまり、オブジェクトの定義をブラウズするためのツールと言えます。気を付けなければいけないのは、ここでの定義や記述内容は、クラス自身ではなく、そのクラスのインスタンスに反映されるということです。クラス自身に影響を及ぼす定義はそのメタクラスに記述しなければなりません。ちなみにこれはクラスブラウザですが、メタクラスについては、クラスリストペインには出ていません。メタクラスをブラウズするにはどうしたらよいかというと、クラスリストペインの下にある class ボタンを押します。これで以右のメッセージカテゴリペインと、メッセージリストペインは同名クラスのメタクラスの内容を反映します。クラスを inspect-it して self を browse-it すると、自動的に class ボタンが選択されていることに気付かれると思います。--sumim - 2002-12-02, 18:27:34

External Image

では、分数(Fraction)を例に、クラス定義を見てゆきましょう。(3/4) を inspect-it すると、分数のインスタンスの中身を見ることができます。そこには2つのインスタンス変数が定義され、それぞれに、分子(numerator)と分母(denominator)と名付けられ、それぞれに整数を束縛しています。self をクリックして選択し、browse-it するとそのクラス定義を見ることができます。--sumim - 2002-12-02, 18:39:26

External Image

External Image


instanceVariableNames: 'numerator denominator ' とあるのがそうですね。例えばここに、jinro と書き足して accept すると、Fraction はコンパイルしなおされて、その結果がすぐに分数全インスタンスに反映されます。後ろのインスペクト中の (3/4) にも jinro というインスタンス変数が追加されたのが分かると思います。別に (1/2) をインスペクトしても jinro が現われます。jinro は未定義なので、デフォルトの nil が束縛されています。--sumim - 2002-12-02, 18:45:10

External Image

余談ですが、このインスペクタがなければ、我々は通常、この jinro インスタンス変数が追加されたこと、それに束縛されているオブジェクトが何かを知ることや、それに別のオブジェクトを束縛させ換えることなどはできません。こうした作業が簡単にできてしまうインスペクタがいかに特殊な能力を備えたツールであるかが分かります。逆にこの程度のことがオブジェクトを扱ううえでの基本的なサービスとして提供できていないオブジェクト指向環境とは関わり合いになりたくない…というのも正直なところです。なお、このインスペクタも当然 Smalltalk コードで記述されていることから、オブジェクトのインスタンス変数に通常の(クラスに定義されているメッセージを送信する)方法以外でアクセスすることも実は可能なわけなのですが、それはまた別の機会のお話ということで。--sumim - 2002-12-02, 19:10:30

おはようございます.少し体調が回復しました.今日もよろしくお願いします.
>オブジェクトの内部情報、具体的にはインスタンス変数の数、名前、それらが束縛しているオブジェクトの一覧を表示したり変更するツール
インスペクタは,インスタンスのブラウズと言う理解でよろしいでしょうか?ここでselfを選んでbrowse-itすると,今度はクラスのブラウズになる…と.
Stringクラスをinspect-itすると,ウィンドウタイトルがString classとなりました.これは
>このウインドウのタイトルは、インスペクトしているオブジェクトの属するクラス
の通りですから,ここでインスペクトしているクラスはStringクラスですね.selfbrowse-itすると,String classのブラウズになるのですね.
browseメッセージの送信、つまりString class browseなどと記述したもののdo-itは可能
この時に出てくるのは,先にinspect-itselfを選択→browse-itの時のシステムブラウザではなくて,クラスブラウザなのですね.
>理解が進むまでインスペクタを介してbrowse-itする
えぇ,その方が良さそうです(汗)--人狼 - 2002-12-03, 09:07:29
システムブラウザは,先の説明通りクラス定義(オブジェクト)のブラウザですね.
>ここでの定義や記述内容は、クラス自身ではなく、そのクラスのインスタンスに反映されるということ
先の私の例で言うならば,ここでの定義の修正や変更はString classに行われるので,その内容はインスタンスであるStringに反映される.と言う事でしょうか?昨日の実験通り,何らかの変更をacceptしたら,全てのStringインスタンスに反映されるのでしょうか?
>クラス自身に影響を及ぼす定義はそのメタクラスに記述しなければなりません。
これは,String classをインスタンスと考えてあげると,当然にそのクラス(=メタクラス)に記述する必要があると言う事でしょうか?
メタクラスのブラウズについては試してみました.最初にシステムブラウザで開いていたのがString classだったので,元々classのボタンが選択されていましたinstanceのボタンを押すとStringになりました.--人狼 - 2002-12-03, 09:18:29
さて,分数です.inspect-itしてみました.
>そこには2つのインスタンス変数が定義され、それぞれに、分子(numerator)と分母(denominator)と名付けられ、それぞれに整数を束縛
ちょっと引用が長くなってしまいましたがご容赦を.2つのインスタンス変数がnumeratorとdenominatorですね.そして,それぞれに束縛している3と4も整数オブジェクトですよね.では続いてクラス定義へ.--人狼 - 2002-12-03, 09:37:20
instanceVariableNames: 'numerator denominator 'とある
ここでインスタンス変数を定義しているのですね.試しに書き足してみました.acceptしたら一瞬リコンパイルしてるよ,と言う感じのメッセージが表示されて,消えたと思ったらインスペクタの方にも反映されました.すごい.クラスを書き換えてacceptしたら同時にインスタンスが変更されるのですね.も一つ別な分数のインスタンスをインスペクトしても二つ同時でした.驚きです.未定義の場合はnilがデフォルトで束縛されるのですね.--人狼 - 2002-12-03, 09:47:00
>このインスペクタがなければ…
確かに,このようなツールは見た事がありません.インスタンス変数の追加と言うのは,ソースを修正してコンパイルするものでした.こんなダイナミックにインスタンスが存在している状態で書き換えてコンパイルできて,さらに反映される,と言うのは驚きです.まして,束縛しているオブジェクトを知る事や,別なオブジェクトを束縛させ換える等と言うのは知る術がありませんでした.ソースが頼りだったわけです.これはインスペクタが特殊なツールなのか,それともSmalltalkと言う環境のなせるわざなのか…
で,あればこそsumimさんがオブジェクト指向環境に求める物も何となく判るような気がします.
通常以外の方法でインスタンス変数にアクセスするのは,その内に.とりあえず通常の方法を学びたいと(汗)--人狼 - 2002-12-03, 10:00:43

先にinspect-it→selfを選択→browse-itの時のシステムブラウザではなくて,クラスブラウザなのですね.
いえ。システムブラウザはいわば“クラス”ブラウザだというニュアンスです。しかしメタクラスもクラスなのに、ここには出てこない…と。--sumim
- 2002-12-03, 10:42:02

何らかの変更をacceptしたら,全てのStringインスタンスに反映されるのでしょうか?
そういうことになります。が、String は String class の唯一のインスタンスなので(念のため申し上げておくとサブクラスはこの際、この“親子”関係には係わりがありません)影響を受けるのは String だけ…ということになります。クラスが名前を持つ珍しいインスタンスでありうることも(実際ははじめにクラスありき…でに過ぎないのでしょうが)この唯一のインスタンスであることと無関係ではなさそうですね。--sumim
- 2002-12-03, 10:46:49

String classをインスタンスと考えてあげると,当然にそのクラス(=メタクラス)に記述する必要がある
そうです。メタクラス、すなわち String class です。あるオブジェクトを捕まえたとき、そのオブジェクトの設計に関わることをどこに書けばよいのか…ということを即座に判断できるようにしていただくことが、ここでの第一のテーマです。--sumim
- 2002-12-03, 10:50:21

>システムブラウザはいわば“クラス”ブラウザだというニュアンスです。
そのニュアンスは了解しております.私が申し上げたかったのは,inspect-itselfを選択→browse-itした時は「システムブラウザ」が表示されていると言う事です.両者のウィンドウのレイアウトは若干事なっております.--人狼 - 2002-12-03, 11:00:02

とりあえず通常の方法を学びたいと(汗)
たしかに…(笑)。まだ、それをやっていませんでしたもんね(笑)。では、そのまま Fraction のメッセージカテゴリペインで、適当な名前のカテゴリ(squab testing とでもしておきましょうか)を追加して、コードペインで
jinro
^ jinro
を accept してください。これで、jinro というメッセージを分数に送ると、インスタンス変数 jinro の内容を“通常の方法”で知ることができます。と、申しましても、例えば、
(4/3) jinro
を print-it すると、ノーティファイアが出ずに nil が返ります。まだ束縛するオブジェクトを決めることができないので返ってくるのは nil だけですが。--sumim
- 2002-12-03, 11:04:46

StringString classの唯一のインスタンス
ありゃ,そうでしたか<唯一のインスタンス.とは言え,分数の時には二つのインスタンスに反映されるのが確認出来ましたので大丈夫です.
ここは,クラス−インスタンスの関係なので,サブクラスまでは考えておりませんので大丈夫です(苦笑)サブクラス・スーパークラスはとりあえず忘れました.クラスとメタクラスの関係は派生関係でない事は昨日理解できたつもりです(汗)--人狼 - 2002-12-03, 11:04:59

>メタクラス、すなわちString classです。
あれ,質問が悪かったみたいです(汗)私がお聞きしたかったのはString classの定義を追加したら,それはStringインスタンスに反映されるのですよね?ではString classに反映されるような記述はString classのメタクラスでよろしいのでしょうか?と言う事でした.

>あるオブジェクトを捕まえたとき、そのオブジェクトの設計に関わることをどこに書けばよいのか
常にそのオブジェクトのクラスと認識しています.--人狼 - 2002-12-03, 11:09:31

両者のウィンドウのレイアウトは若干事なっております.
ああ、そのことでしたか。システムブラウザはフルブラウズから部分ブラウズザ、階層ブラウズなど用途に合わせていくつかの形態があります。ご指摘のとおり、呼び出されたときにシチュエーションによってレイアウトが変わるので、注意してください。クラスリストペインから browse full を選択することでフルブラウズ用のウインドウを改めて開いて使うことができます。--sumim
- 2002-12-03, 11:09:47

String classに反映されるような記述はString classのメタクラスでよろしいのでしょうか?
メタクラスというと、クラスのクラスということなので、メタメタクラスとでも申しましょうか。String class のクラスは Metaclass で、これはすでに実験済だと思います。--sumim
- 2002-12-03, 11:13:02

えぇっと.Fractionをinspect-itで見えているのは,(4/3)と言うインスタンスそのもの.そのselfbrowse-itして見えるのがそのクラス定義であるところのオブジェクトであるFractionですよね.これに修正を加えるので,結果は(4/3)を始めとする分数のインスタンスに及ぼされる…と.
確かに(4/3)でも(1/2)でもnilが返ってきました.--人狼 - 2002-12-03, 11:13:55

ああ。分かりました。私はここで、Metaclass とメタクラスは使い分けています。メタクラスはクラスのクラスという意味で Hoge class などがそれに当たります。Metaclass は Hoge class のクラス、メタクラスのクラス、メタメタクラスという意味で使っています。--sumim - 2002-12-03, 11:16:47

>システムブラウザはフルブラウズから部分ブラウズザ、階層ブラウズなど用途に合わせていくつかの形態があります。
そう言う事でしたか.システムブラウザの一形態だったのですね.browse fullを選択そて降るブラウズ用のウィンドウを表示できました.--人狼 - 2002-12-03, 11:19:18
え〜っと(汗)
クラス→インスタンスの定義の存在するオブジェクト.:'string' のクラスはString
メタクラス→クラス(をインスタンスとして考えた時)のクラス(=定義の存在するオブジェクト).:StringのメタクラスはString class
Metaclass→メタクラス(をインスタンスとして考えた時)のクラス(=定義の存在するオブジェクト).:String classのメタクラスはMetaclass
Metaclassと書かれた場合はクラス名であって,概念としてのメタクラスと混同しないように.--人狼 - 2002-12-03, 11:25:29
>メタクラスというと、クラスのクラスということ
はい,そうですそうです.
String classのクラスはMetaclassで、これはすでに実験済だと思います
昨日やりましたね.大変失礼しました.--人狼 - 2002-12-03, 11:29:06

Metaclassと書かれた場合はクラス名であって,概念としてのメタクラスと混同しないように.
メタメタクラスなのに Metaclass とはこれいかに…ってなもんですね(笑)。--sumim
- 2002-12-03, 11:54:28

>メタメタクラスなのに Metaclass とはこれいかに
「メタメタ」だとなんか「ダメダメ」っぽいから(苦笑)--人狼 - 2002-12-03, 11:59:47

では、Fraction にメッセージ jinro を加えたのと同様の方法で、インスタンス変数 jinro に別のオブジェクトを束縛するためのメソッドを追加してみましょう。squab testing カテゴリをクリックして選択し、コードペインに
jinro: obj
    jinro _ obj
とタイプして accept します。これで、分数は jinro: #jinro などと言ったメッセージを受け付け、インスタンス変数 jinro に引数として与えられたオブジェクトを束縛することが可能になります。(8/3) jinro: #jinro を print-it ではなく inspect-it してみてください。(8/3) のインスタンス変数 jinro#jinro というシンボルが束縛されているはずです。--sumim
- 2002-12-03, 12:07:07

_ は画面では ← と表示されます。左辺の変数に右辺のメッセージ式の結果を束縛することを意味意味します。--sumim - 2002-12-03, 12:17:34

このメソッドのように ^ 文が記述されていないときや、記述されていても評価されないときメソッドは ^ self をメソッドに暗示的にメソッドの最後に追加して実行します。このようなインスタンス変数にオブジェクトを束縛するタイプのメソッドの返値をどうするか、というのは実装者のセンスの問題ですが、コンセンサスとしては self が配列タイプのオブジェクトの場合、追加もしくは置き換えたオブジェクト自身(この場合、obj )を、そうでなければ特に記述せず self を返すのがよいようです。--sumim - 2002-12-03, 12:37:50

>Fraction にメッセージjinroを加えたのと同様の方法で
え?さっきFractionに加えたjinrouはインスタンス変数ではありませんでしたっけ?(汗)それなのに,ここではメッセージと書かれています.いや,まてよ.さっき(4/3) jinroprint-it,って事はjinroはメッセージだよなぁ.試しに…,numeratordenominatorもちゃんと,束縛されているオブジェクトを返して来ますね.ん〜とインスタンス変数を定義する=インスタンス変数名のメッセージを受け取ると言う事なのでしょうか?デフォルトでその束縛しているオブジェクトを返すと言うメソッドなのかしら?-人狼 - 2002-12-03, 13:05:27

jinroはメッセージだよなぁ.
じつはこれ、トラップです。同じ jinro を文脈からインスタンス変数か、メッセージかを区別できるかどうかをはかるため、わざと分かりにくいように同じ文字列を使っています(もうひとつは、インスタンス変数の参照用メッセージは、インスタンス変数と同名に、設定用はインスタンス変数名+ : とする…というコンセンサスがあるというのもあります)。--sumim
- 2002-12-03, 13:13:46

>インスタンス変数 jinro に引数として与えられたオブジェクトを束縛する
結果をinspect-itして確認しました.ところで上の式の読み解きなのですが,今一つ理解出来ていないみたいです.1行目の:の前のjinroはメソッド名なのか,メッセージ名なのか,インスタンス変数名なのかが判りません.また,:の後ろのobjとは「オブジェクトを受け取る」と言う意味にも読めますし,objと言う単語に特別な意味がありそうな気もします.2行目のご説明で「左辺の変数に右辺のメッセージ式の結果を束縛」とありますので,左辺のjinroはここではインスタンス変数でしょうか.右辺のobjがメッセージ式になると言うことでしょうか?--人狼 - 2002-12-03, 13:19:03

まず、obj ですが、これは偽変数です。参照はできるけど束縛するオブジェクトを別の物には換えられないというやつ。メソッドを起動したとき、引数として添えられたオブジェクトがこの obj に束縛されます。メッセージ式ではありませんが、評価すると束縛しているオブジェクトを返します。--sumim - 2002-12-03, 13:22:01

>じつはこれ、トラップです。
あいたたた(汗)
>同じ jinro を文脈からインスタンス変数か、メッセージかを区別できるかどうか
いや,それ以前の問題みたいです.ごめんなさい.インスタンス変数を追加した記憶はあるんですが,メッセージとしてjinrouを定義した記憶がないので,どこから出てきたやら困惑しております.(4/3) jinroなんて場合は例の「オブジェクト メッセージ」ですからjinroがメッセージだと言うのは良いのですが,どこから出てきたメッセージなものかが判らないのです(大汗)--人狼 - 2002-12-03, 13:23:16

メッセージ名に関しては、
jinro
    ^ jinro
を、
getJinro
    ^ jinro
に書き換えて accept 、
jinro: obj
    jinro _ obj
を、
setJinro: obj
    Jinro _ obj
に書き換えて accept すると状況がよく分かると思います。--sumim
- 2002-12-03, 13:25:20

メッセージとしてjinrouを定義した記憶がない
あたたたた(^_^;)。コードペインで accept した
jinro
    ^ jinro
がそのメソッドの定義です。一行目がメッセージ名(と必要なら引数を束縛する偽変数の書式)ですね。--sumim
- 2002-12-03, 13:27:33

あ,失礼しました.まずjinroと言うインスタンス変数を追加しましたよね.次に
jinro
^ jinro
acceptしてますよね.ここでjinroと言うメッセージを受けるとインスタンス変数jinroの内容を返すと言うメッセージを定義したことになるのですよね?--人狼 - 2002-12-03, 13:39:18
>メッセージを定義
違う,メッセージではなくてメソッドだ>自分--人狼 - 2002-12-03, 13:40:25

メッセージを定義したことになるのですよね?
そうです。メソッドもメッセージも同時に定義しています。--sumim
- 2002-12-03, 13:42:49

>一行目がメッセージ名(と必要なら引数を束縛する偽変数の書式)です
なるほど.先に定義したメソッドが受け取るメッセージはjinroで,次に定義したメソッドが受け取るメッセージはjinro: objectとなりオブジェクトを引数として要すると言う事なのですね.ここでjinro:はメッセージセレクタと言う事になりましょうか?
「^」は,先に「これは(続くメッセージ式があってもそれを無視して)^ 以下のメッセージ式の評価結果を返してメソッド終了」とご説明頂きましたが,括弧内の「続く」は何に続く事をおっしゃってますでしょう?--人狼 - 2002-12-03, 13:47:14

objですが、これは偽変数です
これは了解しました.--人狼 - 2002-12-03, 13:48:18
メソッドとメッセージの件,大変失礼&お騒がせしました.OKですので,setとかgetは外して,元のまま続けられますでしょうか?(その方が,誤解をしたとしても最終的には良い理解につながりそうです)--人狼 - 2002-12-03, 13:50:34
^文が記述されていないとき
できるだけ,^文は記述した方が良いのでしょうか?^文はメソッド終了の意も含んでましたよね.
>コンセンサスとしてはselfが配列タイプのオブジェクトの場合、追加もしくは置き換えたオブジェクト自身(この場合、obj)を、そうでなければ特に記述せずselfを返すのがよいようです
このメソッドの場合はselfは配列ではありませんよね?--人狼 - 2002-12-03, 13:55:31

たとえばこんな場合です。
jinro
    jinro ifNotNil: [^ jinro].
    ^ jinro _ #jinro

インスタンス変数 jinro が nil を束縛していないなら、jinro に束縛されているオブジェクトを返す(ここでメソッド終了)。jinro が nil ならば、ブロック内は評価されないので、jinro に #jinro というシンボルを束縛してそれをを返す、と。もし、先のブロック内で ^ を記述し忘れると ^ jinro _ #jinro が常に評価され、#jinro しか返らなくなります。--sumim
- 2002-12-03, 13:56:29

setとかgetは外して,元のまま続けられますでしょうか?
setJinro: や getJinro は追加されるだけなので問題ないと思います。
- 2002-12-03, 13:58:47
>たとえばこんな場合です
なるほど,有り難うございます.大変判りやすい例です.構文としてブロック式やピリオドがあったり,なかったり,と言うのがまだ慣れていませんが(汗)慣れてないと言えばifNotNilもそうですね(大汗)インスタンス変数は代入ではなくて束縛だと言うのは判ったつもりでも,この式をぱっと見たら「jinronilでなかったら」と読み解きそうになります.気を付けないと…--人狼 - 2002-12-03, 14:01:06
>setJinro: や getJinro は追加されるだけ
了解しました.追加されて正しいのですね.先程の書き換えをやってみたら,二つメソッドが増えたので焦っておりました--人狼 - 2002-12-03, 14:02:15
そう言えば,インスタンス変数の内容を返すメソッドと,インスタンス変数にオブジェクトを束縛するメソッドは,どちらもjinroを使っていますが,前者がjinro なのに対して,後者は引数を伴う事から,メッセージ名ではなくてメッセージセレクタ名になっているので,jinro:となっているので両者は区別されている,と言う解釈は当たりですか?--人狼 - 2002-12-03, 14:07:59

ifNotNil: は受信者が nil でない場合、引数のブロック内のメッセージ式を評価します。ピリオドはメッセージ式の区切りです。なので、
jinro
 jinro ifNotNil: [ ^
jinro ]. ^ jinro _ 
  #jinro
と書いても同じ意味になります。--sumim
- 2002-12-03, 14:08:20

重複スペース、タブ、改行(ただし2行目以降)は文字列内で用いない限りコードに影響を与えないのですね。もっともこんなソースを書いていたらぶん殴られますが(笑)。--sumim - 2002-12-03, 14:09:22

jinro:となっているので両者は区別されている
当たりです。たまたま : を用いることから両者を区別することができた(メッセージ名の正体はシンボルですが、#jinro と #jinro: は別物という)わけですね。そうでなければたぶん、set、get を付けるなどの習慣に置き換わっていたと思います。--sumim
- 2002-12-03, 14:13:52

ifNotNil:は受信者がnilでない場合、引数のブロック内のメッセージ式を評価します。ピリオドはメッセージ式の区切りです。
ifNotNil:browse-itしてみますと,ifNotNilBlockを引数にとるメッセージセレクタである事が判りました.ここでブロックコンテキストが再登場するわけですね.先の説明で「遅延評価」と言う言葉が出てきたと記憶しておりますが,実はこの言葉は存じ上げません.その後色々と調べてみたのですが,未だによく判っていません(汗)
ところで,説明を読んでも,nilでなければブロック内を実行する,と言う事が書かれていますので,ここは必ずブロックである必要があると言う事ですね.--人狼 - 2002-12-03, 14:25:05

ピリオドをメッセージ式の区切りに使う関係で、1 以下の小数の表記の際、.123 のような 0 を省略した記述はできません。--sumim - 2002-12-03, 14:26:59

ピリオドが,メッセージ式の区切りと言うことですが
jinro ifNotNil: [^ jinro].
    ^ jinro _ #jinro

において,1行目にはピリオドがあるけど2行目には無いのは,2行目の後にはメッセージ式が無いので,区切らなくても終わりは明白だからでしょうか?--人狼 - 2002-12-03, 14:29:04
>1 以下の小数の表記の際、.123 のような 0 を省略した記述はできません
0.123と書くと大丈夫なのですね?0でメッセージ式が終わり,と言う誤解は無いですよね(汗) - 2002-12-03, 14:30:13

そうです。遅延評価(笑)の必要がある処理を引数にとったり、受信オブジェクトにするメッセージではブロックを使います。例えば、永久ループの
[true] whileTrue
は、true whileTure ではだめで、ブロックを使わなければいけません。それは、ループのたびに受信オブジェクトであるブロック内のメッセージ式の評価が true であることを確認する必要があるからです。--sumim
- 2002-12-03, 14:31:03

>当たりです。たまたま:を用いることから両者を区別することができた(メッセージ名の正体はシンボルですが、#jinro#jinro:は別物という)わけです
了解です.いや,久し振りの当たりなので,ちょっと嬉しいです(^-^)--人狼 - 2002-12-03, 14:31:16

遅延評価は、Lisp のλ式と通じるものがあるので、難しい概念かもしれません。ブロックは名前のない関数とでも申しましょうか、処理をデータとして扱うためのものです。--sumim - 2002-12-03, 14:33:16

ブロックは [] の中にメッセージ式を含み、value というメッセージを受けて、その評価内容(複数のメッセージ式が含まれている場合、その最後のもの)を返します。
[ 'this'. #is. $a. 10 ] value
を print-it すると、10 が返ります。遅延評価のニュアンスは、こんなコードから感じ取っていただけるのではないでしょうか。たとえば、
| temp1 temp2 result |
temp1 _ 1.
temp2 _ 2.
result _ temp1 + temp2.
temp1 _ 3.
^ result
の print-it の結果は 3 ですが、
| temp1 temp2 result |
temp1 _ 1.
temp2 _ 2.
result _ [temp1 + temp2].
temp1 _ 3.
^ result value
の結果は、5 になります。--sumim
- 2002-12-03, 14:41:25

また、ブロックは関数と同じように独自の引数をとることができます。そのときは、
[ :arg1 :arg2 | メッセージ式 ]
のように各引数(として与えられたオブジェクトを束縛するための偽変数)名の前にコロンを付けて宣言、直後に | をメッセージ式との区切りとして挿入します。評価のための value メッセージセレクタもこの場合は、value:value: を使います。ちなみに、引数がひとつのときは value: 、3つのときは value:value:value: です。--sumim
- 2002-12-03, 14:44:44

1行目にはピリオドがあるけど2行目には無い
そのメッセージ式の“終わり”を示す物ではなく、次のメッセージ式との“区切り”を示す物だからです。でも最後にピリオドを付ける人も大勢いますし、無害です。--sumim
- 2002-12-03, 14:46:49

>true whileTure ではだめで、ブロックを使わなければいけません。それは、ループのたびに受信オブジェクトであるブロック内のメッセージ式の評価が true であることを確認する必要があるから
なるほど.この例ではtrueですから永遠にtrueであるのでしょうが,そこにメッセージ式があると,true/falseを確認しなくてはならないからですね.--人狼 - 2002-12-03, 14:55:59

できるだけ,^文は記述した方が良いのでしょうか?
何を返すのか明示的にしたいときに使います。あと、メソッドを途中の条件文で強制的に終了させたいときに ^ self などとして使います。それ以外は、わざわざ ^ self などとメソッドの最後に記述する必要はないでしょう。--sumim
- 2002-12-03, 14:57:48

valueというメッセージを受けて、その評価内容(複数のメッセージ式が含まれている場合、その最後のもの)を返し
複数の場合は最後のものを返すので,[ 'this'. #is. $a. 10 ] valueprint-itは最後の10が返って来ているのですね.
その次に結果が3となる例と5となる例をお示し頂きましたが,次のような読み解きでよろしいのでしょうか?
temp1に1を束縛
temp2に2を束縛
resulttemp1 + temp2の結果を束縛
temp1に3を束縛(既にresultの式の評価は終わっているので影響を及ぼさない)
よって,resultは3を返す

temp1に1を束縛
temp2に2を束縛
resulttemp1 + temp2の結果であるとする(ニュアンスが難しいですが)
temp1に3を束縛
resultvalueメッセージを受けたのでブロックの中の式を評価して5を返す
--人狼 - 2002-12-03, 15:03:04

大丈夫です。遅延評価のニュアンスを実感していただけましたでしょうか。--sumim - 2002-12-03, 15:05:03

ところで「|」は変数の宣言かなにかですか?--人狼 - 2002-12-03, 15:05:23

そうです。これで括ると続くメッセージ式での使用する一時変数を宣言できます。一時変数とその束縛状況は、一連のメッセージを評価し終わったときに消滅します。--sumim - 2002-12-03, 15:07:59

>ブロックは関数と同じように独自の引数をとることができます
すみません,引数とメッセージの関係が判らないのですが,この場合の引数は,何に対する引数(と,言うか引数を使うのは誰?)になるのでしょう?
valueメッセージセレクタ
ありゃ?そうか,引数が付くからvalueメッセージではなくて,メッセージセレクタとなるのですね.--人狼 - 2002-12-03, 15:09:29

>そのメッセージ式の“終わり”を示す物ではなく、次のメッセージ式との“区切り”を示す物
了解しました.であれば最後のメッセージ式に無いのは判りました.そう言う意味であれば,論理的には最後にピリオドが無い方が美しいのかな…と思います.--人狼 - 2002-12-03, 15:11:47

引数はメッセージセレクタの : の後に順次挿入します。
[ :arg1 :arg2 :arg3 | arg1 + arg2 + arg3 ] value: 1 value: 2 value: 3
という具合です。--sumim
- 2002-12-03, 15:12:29

>何を返すのか明示的にしたいときに使います。あと、メソッドを途中の条件文で強制的に終了させたいときに^ selfなどとして使います。
了解しました.明示的に返却するオブジェクトを示したい時に使うのですね.条件文の途中で強制終了させる時に使う事も出来るのですね.selfと言うのは自分自身の メッセージを受信したオブジェクトの事ですよね?(今なら jinro、jinro: を受けた Fraction のインスタンス)条件分岐の途中で特定のオブジェクトを返して終了と言うのも「そう言う仕様ならば」ありでしょうか?つまり,必ずしもselfを返さなくてはならない,と言う訳ではないですよね?--人狼 - 2002-12-03, 15:14:44 赤字追記はsumim

>大丈夫です。
今日,2回目なので嬉しいかも.(何回呆れられたかは,この際置いておいた方が吉かも)

>遅延評価のニュアンスを実感していただけましたでしょうか。
はい,たぶん判ったと思います.この場合はvalueがトリガーとなって評価がされてますが,先程の例等ではifNotNil:では,レシーバーがnilでないと評価された後に,ブロック内が評価されるのですね.--人狼 - 2002-12-03, 15:18:35

>これで括ると続くメッセージ式での使用する一時変数を宣言できます。一時変数とその束縛状況は、一連のメッセージを評価し終わったときに消滅します。
一時変数と言うのですね.先程の例ですと^文が出現して終了を宣言されたので消滅する,と言う事ですね.--人狼 - 2002-12-03, 15:21:49

>引数はメッセージセレクタの : の後に順次挿入します。
あ,なるほど.了解しました.ブロック内のメッセージ式に引数を渡せるのですね.--人狼 - 2002-12-03, 15:23:37

「そう言う仕様ならば」ありでしょうか?
ありです。--sumim
- 2002-12-03, 15:25:57

^」文の赤字補足有り難うございます.追記頂く前だと曖昧な表現になっていました.--人狼 - 2002-12-03, 15:27:09

self はこの場合、メッセージを受信したオブジェクトを束縛する偽変数として機能します。--sumim - 2002-12-03, 15:30:11

このページを編集 (63570 bytes)


Congratulations! 以下の 2 ページから参照されています。

This page has been visited 7653 times.