2006年5月 8日 (月)

連載: Smalltalk use: better《1》始めの一歩、末の千里★

キーワード ◆ autoboxing・James Gosling・NullPointerException・Oak・unboxing・アジァイル開発・イディオム・オブジェクト指向・クラス・コレクションフレームワーク・コンストラクター・コンポーネントウェア・デザインパターン・メソッド・モデリング・リファクタリング・概念モデル・基本データ型・制御構造・統合開発環境

60500 ※ Smalltalk use: better《SeasonⅠ》site map ⇒ 「piyo60500.pdf」をダウンロード

※ PDF でご覧になるなら ⇒ 「piyo60508.pdf」をダウンロード

------------ 序 ------------

例えばね。                       
19世紀の終わりにね。
電子っていうものが、素粒子が発見されて、
そのときに、それが大きな産業を作るなんて、
誰も思わなかったでしょ。

ところが、
五十年も経って、二十世紀の半ば頃になると、
エレクトロニクス産業って物凄いものができたのね。

基礎科学の研究っていうのはね。
ある程度は山勘になっちゃう。

ひとつのことをね。
もうトコトンまで、もうギリギリ考えて考えて、考え抜いて、
ああでもない、こうでもない、こうしたらどうだろうって、
もうトコトン考え抜くとね。
山勘って当たりが良くなる。
そういうふうに、僕は思いますよ。

NHK「プロジェクトX~挑戦者たち~」小柴昌俊

◆ 1970 年代の初頭「オブジェクト指向」は産声を上げました。その四半世紀後に「オブジェクト指向」が広く知されるようになることを、彼らは予測していたのかしら。

------------ 本文 ------------

◆ この連載「Smalltalk use: better」では、究極のオブジェクト指向の世界を紹介します。

◆ アナログ世代の Java/C# のようなオブジェクト指向擬と違って、ディジタル世代の Python/Ruby のように、本物のオブジェクト指向ならではの世界を体感できるような話題を提供します。Smalltalk が提供する「すべてがオブジェクト、オブジェクトにメッセージを送る」という、簡潔で強力な概念モデルによって、プログラミングの可能性が広がります。

◆「すべてがオブジェクト」というのは、基本データ型だけでなく、クラスやメソッドまでもオブジェクトと見なせるということです。また「オブジェクトにメッセージを送る」というのは、プログラムを記述するコードの世界だけではなく、開発環境における操作(コンパイラーやデバッガーを起動する、作業履歴を管理復元するなど)までを含めて、すべてを統一的に扱えるということです。コードと開発環境とは表裏一体と見なす、真の「統合開発環境」へと誘います。例えて言うなら「Java のコードと Eclipse とを統一的に扱う概念モデルを提供する」ということです。

◆ この連載では、プログラミング技法を紹介することが目的ではありません。ともすると、Smalltalk に限らず、プログラミング言語としての側面に注目されがちです。むしろ、自然言語と同様に、その背景にある文化や思想について、理解することを目的としています。外国の人が日本語を学ぶときに、漢字や平仮名を覚え、難しいとされる「てにをは」を習得するだけでなく、その背景にある伝統文化を知ることで、言語に対するより深い理解が得られます。コードの断片を提示するのは、その手段のひとつにすぎません。それによって、イディオム、リファクタリング、デザインパターン、コンポーネントウェア、モデリング、アジァイル開発など、今では広く認知されているキーワードを頼りに、そのルーツを探る旅へと誘います。

◆ この連載は、1988〜1990年に開催した Smalltalk のセミナー用テキスト(原稿)および講義ノート(ネタ帳)をもとに、再構成したものです。当時と、基本的な枠組みは変りません。その中から、C++ と比較した記述などを、Java に変更しています。翌1991年には、James Gosling さんが(Java に改称する前の)オブジェクト指向言語 Oak の開発に着手したとされています。つまり、その時点では、Java はまだ存在すらしていませんでした。新しくて旧い Java とは異なる、旧くて新しい Smalltalk が提供する、究極のオブジェクト指向の世界へ、さあご一緒にどうぞ。

【Oh! ススメ】Squeakland
世代や国籍を超越した Squeak の世界へようこそ

自由自在Squeakプログラミング Book 自由自在Squeakプログラミング

著者:梅沢 真史
販売元:ソフトリサーチセンター
Amazon.co.jpで詳細を確認する

【参考文献】梅沢 真史, 2004
自由自在Squeakプログラミング, ISBN4883732037

プログラミング言語 Squeak/Smalltalk の詳細を知りたいなら、こちらがおススメです。パソコンを傍らに置いて、実際に手を動かしながら体験学習するときの、良きパートナーとなるでしょう。通勤 のお伴にするには、ちょっとその厚みに圧倒されるかもしれません。しかし、内容はサクサクと読みやすく「気が付いたらここまで来てしまった」ということに もなりかねません。熱中するあまり、降りるべき駅を乗り過ごしてしまわないように、ご用心、ご用心。

◆ この連載における最初の目標は、次の図に示す概念モデルを理解できるようになることです。

60508a_1◆ 図は、Java と Smalltalk との世界観の違いを端的に表現したものです(ただし、Smalltalk の世界を表現するときにも、あえて比較のために Java の表記を使っています)。Java と違って、その背景に、簡潔で統一された概念モデルが存在することが分ります。

基本データ型も、オブジェクトとして実現されます。これは、他のオブジェクトと同様に、メソッド呼び出しが可能になることを意味します。Java では、3.toString() という記述ができません。また、null.toString() は、例外 NullPointerException を生じます。基本データ型や null などは、オブジェクトとしては認められていないのです。Smalltalk では、これらに相当する 3 printString および nil printString という記述が可能です。統一された概念モデルがその背景にあるので、基本データ型だけでなく null さえも、他のオブジェクトと同様に、一人前のオブジェクトとして扱われます。そのため、コレクションフレームワークを利用するときにも、autoboxing/unboxing という冗長な処理は不要です。

メソッドでさえ、オブジェクトとして実現されます。これは、他のオブジェクトと同様に、メソッド自身を他のメソッド呼び出しの引数やリターンにできることを意味します。すると、より柔軟なコードを記述できるので、コードの再利用やリファクタリングを促進します。

クラスは、ただの型紙(設計図)ではありません。クラスも、他のオブジェクトと同様に、実体を持つ一人前のオブジェクトです。すると、次のようなことが可能となります。クラスを定義して、そのインスタンスを生成します。次に、メソッドを再定義すると、それ以前に生成されたインスタンスは、再定義されたメソッドに応答します。インスタンスを再生成する必要はありません。このような特徴は、アジャイル開発(真の統合開発環境)では、強力な武器となります。

コンストラクターのために特別な構文を必要としません。なぜなら、コンストラクターは、普通のメソッドと本質的な違いがないからです。これによって、メソッド呼び出しと同じフレームワークの中で、コンストラクターを扱えるようになります。特別な演算子 new は不要です。つまり、new Class() ではなく、Class.new() となります。そこにはただ、new() というメソッド呼び出しがあるだけです。これは、メソッド呼び出しと同じ構文です。クラスもオブジェクトの一種なので、これも驚くに値しません。

制御構造でさえ、メソッドとして実現されます。これは、if や for のような構造化プログラミングの基本とされる制御構造も、特定のクラスのメソッドとして実現されることを意味します。つまり、if() というメソッドを定義するのです。これによって、すべて統一された簡潔で強力な概念モデルが完成します。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年5月 9日 (火)

連載: Smalltalk use: better《2》3つの基本構文★

キーワード ◆ オブジェクト・オブジェクト指向・キーワードメッセージ式・セレクター・メッセージ・リターンオブジェクト・引数・単項メッセージ式・二項メッセージ式

※ PDF でご覧になるなら ⇒ 「piyo60509.pdf」をダウンロード

------------ 序 ------------

県民を満足させる政治ではなくて             
県民が満足できるサービスだ
県民は主語だ

「21世紀臨調」代表 北川正恭

◆ オブジェクト指向の基本的な概念は「オブジェクトにメッセージを送ると、オブジェクトが得られる」という言葉で説明できます。これは「オブジェクトにある依頼をして、必要なサービスを享受する」ための行為と見なせます。つまり、「オブジェクトが、必要なサービスを提供する」ということです。オブジェクトが語となり、そこに、オブジェクトの主体性が期待されるのです。

◆ 千里の道も一歩から。まず、基本構文から学びます。何事も基本が大切ですので、しばらくはご辛抱ください。

------------ 本文 ------------

◆ Smalltalk は、言語仕様がとても小さく、理解するのも容易です。単に文法を説明するだけなら、A4サイズの紙一枚もあれば十分です。すべてが「オブジェクトとメッセージ」で構成されているので、とても単純かつ強力で、その概念が首尾一貫しています。それは、体脂肪率を一桁にまで絞り込んだ、アスリートの肉体美を彷彿とさせます。

60509a_2 ◆ Smalltalk には、英語の5文型に相当するものとして、3つの文型があります。まず、これを理解することから始めます。

  1. 単項メッセージ式
  2. 二項メッセージ式
  3. キーワードメッセージ式

これらに共通するのは「オブジェクトにメッセージを送ると、オブジェクトが得られる」ということです。

単項メッセージ式 ◆ Smalltalk

3 factorial          "6"

60509b

二項メッセージ式 ◆ Smalltalk

3 + 4          "7"

60509c_1

キーワードメッセージ式 ◆ Smalltalk

3 lcm: 4          "12"

60509d_3

3 between: 2 and: 4          "true"

60509e

※ これらを Java 擬で表現すると、次のようになります。

  3.factorial()
  3.+(4)
  3.lcm_(4)
  3.between_and_(2,4)

メッセージは、(1つの)セレクターと(任意の)引数によって構成されます。単項メッセージ式では、引数を必要としません。二項メッセージ式では、1つの引数を必要とします。キーワードメッセージ式では、任意の数(:と同じ数)の引数を必要とします。

セレクターには、さまざまな書式が規定されています。単項メッセージ式では、任意の識別子を指定します。二項メッセージ式では、1つまたは2つの記号を指定します。キーワードメッセージ式では、任意の識別子と「:」とを指定します。

引数には、任意のオブジェクトを指定します。

※ メッセージ式を評価して得られるオブジェクトは、コメントとして記述しています。たとえば、メッセージ式 3 factorial を評価する場合、オブジェクト 3 にメッセージ factorial を送ると、オブジェクト 6 が得られます。コメントとして "6" と記述してあるのは、このリターンオブジェクトを示したものです。

【Tips】基本文型

60509f ◆ 英語の基本文型で最も簡単なのは S+V です。3 factorial というメッセージ式は「3 に factorial を計算するように依頼する」とも読めますし「3 が factorial を計算する」とも読めます。すると、3 が主語(S)なら、factorial を動詞(V)と見なせます。

60509g_2 ◆ 3 lcm: 4 というメッセージ式は「3 に 4 との lcm を計算するように依頼する」とも読めますし「3 が 4 との lcm を計算する」とも読めます。すると、3 が主語(S)なら、lcm を動詞(V)、4 を目的語(O)と見なせます。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年5月10日 (水)

連載: Smalltalk use: better《3》3つの基本要素:リテラル★

キーワード ◆ Alan Kay・Character・Float・LargePositiveInteger・SmallInteger・String・センダー・メッセージ式・リテラル・レシーバー・変数

※ PDF でご覧になるなら ⇒ 「piyo60510.pdf」をダウンロード

------------ 序 ------------

先代と同じ味を作り上げても、誰も認めてはくれない、
先代と違う味を出してはじめて「先代と似てきた」そう言われる。

料理人 徳岡

◆ Alan Kay さんが描いた夢は、四半世紀の時空を越えて、Squeak という形で転生しました。Smalltalk とはひとを違う Squeak の今後の展開が楽しみです。わくわく。

------------ 本文 ------------

◆ Smalltalk のプログラムを構成するのは、次の3つの基本要素です。

  1. リテラル
  2. 変数
  3. メッセージ式

共通するのは「これらを評価すると、オブジェクトが得られる」ということです。

リテラル ◆ よく使われるリテラルを紹介します。

3 class          "SmallInteger"

60510a_1 ◆ すべてのオブジェクトには、それが属するクラスが存在します。メッセージ class を送ると、そのクラスが得られます。メッセージ式 3 class から、整数 3 のクラスは、SmallInteger であることが分ります。

3 sqrt          "1.732050807568877"
3 sqrt class          "Float"

60510b_1 ◆ オブジェクトにメッセージを送ると、オブジェクトが得られます。すると、得られたオブジェクトに、再びメッセージを送ることができます。メッセージ式 3 sqrt を評価すると、3 の平方根 1.732050807568877 が得られます。さらに、メッセージ式 3 sqrt class を評価すると、得られた実数のクラスは、Float であることが分ります。

13 factorial          "6227020800"
13 factorial class          "LargePositiveInteger"

◆ メッセージ式 13 factorial class から、13 の階乗は普通の整数ではなく、不定長の桁数を表現できる整数 LargePositiveInteger であることが分ります。

3 printString          "'3'"
3 printString class          "String"

60510c_1 ◆ メッセージ printString を送ると、その文字列表記が得られます。メッセージ式 3 printString を評価すると、文字列 '3' が得られます。さらに、メッセージ式 3 printString class を評価すると、得られた文字列のクラスは、String であることが分ります。

'ABCDE' at: 3          "$C"
$C class          "Character"

60510d_1 ◆ メッセージ at: を送ると、指定された位置の要素が得られます。文字列 'ABCDE' の先頭から数えて3番目の文字 $C が得られます。また、メッセージ式 $C class を評価すると、得られた文字のクラスは、Character であることが分ります。

【課題】どうすればいい
次の式を評価するとエラーとなります。その理由を説明してください。

'ABCDE' at: 3 class

また、どうすれば、このエラーを回避できますか。正解は、ひとつとは限りません。

【Tips】メッセージによる情報の伝達

60510e◆ オブジェクトがメッセージをやり取りする様子は、手紙や電子メールのやり取りと比較すると分りやすいでしょう。

Smalltalk Best Practice Patterns Book Smalltalk Best Practice Patterns

著者:Kent Beck
販売元:Prentice Hall
Amazon.co.jpで詳細を確認する

ケント・ベックのSmalltalkベストプラクティス・パターン―シンプル・デザインへの宝石集 Book ケント・ベックのSmalltalkベストプラクティス・パターン―シンプル・デザインへの宝石集

著者:ケント ベック
販売元:ピアソンエデュケーション
Amazon.co.jpで詳細を確認


【参考文献】Kent Beck, 1996
Smalltalk Best Practice Patterns, ISBN013476904X

XP の提唱者でもある、Kent Beck さんのルーツは、Smalltalk にあった。イディオムの宝庫です。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年5月11日 (木)

連載: Smalltalk use: better《4》3つの基本要素:変数★

キーワー ◆ メッセージ式・リテラル・型・識別子・宣言・束縛・代入・評価・変数

※ PDF でご覧になるなら ⇒ 「piyo60511.pdf」をダウンロード

------------ 序 ------------

何のために作られたかではなく
に使えるかだ
頑張ってやり遂げようじゃないか

「Apollo 13」1995年・アメリカ

◆ Smalltalk では、変数の型を宣言する必要がありません。しかし、これは型を無視してよいという意味ではありません。法律で規制されていないから、何をやってもかまわ ないというのは、社会通念として許されるものではありません。同様に、文法で規定されていないからといって、どのような使い方も許されるというものでもあ りません。ルールが明文化されていない環境の下で、暗黙のルールを守るのが、Smalltalk コミュニティーにおけるマナーと言えるでしょう。

------------ 本文 ------------

◆ Smalltalk のプログラムを構成するのは、次の3つの基本要素です。

  1. リテラル
  2. 変数
  3. メッセージ式

共通するのは「これらを評価すると、オブジェクトが得られる」ということです。

変数 ◆ Smalltalk では、変数の型を宣言する必要はありません。ただし、その識別子が変数を表すことだけは、明確に宣言しておく必要があります(Squeak の場合には、やや事情が異なります)。

| s |
s := 3.          "3"
s printString          "'3'"

60511a_1 宣言 ◆ 変数を宣言するには、| と | との間に、識別子 s を記述します。

代入 ◆ 変数に代入するには、:= の左辺に識別子 s を、その右辺に(オブジェクトを表す式)3 を記述します。すると、変数 s によって、オブジェクト 3 を参照できます。

※ 厳密には「束縛」と表現するべきところですが、ここではあえて「代入」と表現しています。これらの違いを正しく理解することは重要なので、別の機会にじっくりと腰を据えて解説します。

式の区切り ◆ 複数の式を列挙するときには、式と式との間に「 . 」を記述します。英語の文の区切りと似ていますが、違いは、文(式)の終わりを示すのではなく、式と式との区切りを表すというところです。

式の評価 ◆ メッセージ式 s printString を評価すると、変数 s が束縛する 3 に、メッセージ printString が送られます。すると、3 の文字列表記が得られます。

| a b |
a := 3.          "3"
b := 4.          "4"
a + b          "7"

60511b_1 式の評価 ◆ メッセージ式 a + b を評価すると、変数 a が束縛する 3 に、メッセージ +b が送られます。このとき、変数 b が束縛する 4 が、引数として渡されます。すると、リターンオブジェクトとして、7 が得られます。

※ Java では、式の後に ; を付けることで文となりますが、Smalltalk では、単なる区切り文字として扱われます。そのため、最後の式の後には . を付けなくてもかまいません。もし . を付けると、これに続く式がないことを意味します。エラーにはなりませんが、その1文字が無駄になるだけのことです。

| c |
c := 'ABCDE' at: 3.          "$C"
c class          "Character"

60511c_1 代入 ◆ 変数 c には、メッセージ式 'ABCDE' at: 3 を評価して得られる文字 $C が代入されます。すると、変数 c によって、オブジェクト $C を参照できます。

式の評価 ◆ メッセージ式 c class を評価すると、変数 c が束縛する $C に、メッセージ class が送られます。すると、$C のクラスが得られます。

| a b |
a := b := 3.
a printString.          "'3'"
b printString.          "'3'"

60511d_1 ◆ この例では、異なる変数 a および b が、同じオブジェクト 3 を、それぞれ束縛しています。

| x |
x := 3 factorial.                    "6"
x class.                    "SmallInteger"
x := x / 4.                    "(3/2)"
x class.                    "Fraction"

60511e ◆ この例では、同じ変数 x が、異なるクラス SmallInteger および Fraction のインスタンスを、それぞれ束縛しています。

| x |
x := 'ABCDE'.
x class.                    "String"
x := x at: 3.                    "$C"
x class.                    "Character"

60511f_1 ◆ この例では、同じ変数 x が、異なるクラス String および Character のインスタンスを、それぞれ束縛しています。

※ 変数 x の事例は、型を無視した反面教師の姿を体現したものです。x は、×(バツ)とも読めます。あえてこれを識別子に使ったのには、そうような意味合いが含まれていたのです。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年5月12日 (金)

連載: Smalltalk use: better《5》3つの基本要素:式★

キーワード ◆ キーワード ◆ キーワードセレクター・セレクター・メッセージ式・リテラル・括弧・単項セレクター・二項セレクター・変数・優先順位

※ PDF でご覧になるなら ⇒ 「piyo60512.pdf」をダウンロード

------------ 序 ------------

多ければいいというわけではない
だからといって少なすぎても良くない

Kent Beck

◆ 英語には、基本となる5文型があります。古典的なニュートン力学には、運動に関する3つの法則があります。素粒子物理学の世界では、3つの基本的な力(強い力、弱い力、電磁)を統一する理論の構築が期待されています。かつて、電気と磁気とは別物として扱われていました。やがて、電磁相互作用が解明されると、これらは電磁気として統合されました。つまり、より単純で強力な概念モデルが構築されるに至ったのです。それぞれを区別するものは何か。

◆ オブジェクトを表現する3つの要素は、リテラル、変数、メッセージ式です。それぞれの違いは何か。これらに共通するものは何か。これらを正確に把握することが、真の理解へと繋がります。

------------ 本文 ------------

◆ Smalltalk のプログラムを構成するのは、次の3つの基本要素です。

  1. リテラル
  2. 変数
  3. メッセージ式

共通するのは「これらを評価すると、オブジェクトが得られる」ということです。

◆ すべてのメッセージ式は、セレクターの種類によって3つに分類できます。セレクターとは、メッセージを識別するための情報で、関数やメソッドの名前とは、似て非なるものです。一般に、メッセージは、(1つの)セレクターと(任意の)引数との組み合せによって構成されます。これらは、優先順位の高いほうから順に、単項セレクター二項セレクターキーワードセレクターに分類されます。

3 + 4 factorial          "27"

60512a_1 単項と二項 ◆ この式には、2つのセレクターが存在します。単項セレクターの方が優先順位が高いので、先に、factorial が評価されます。式 4 factorial を評価すると、24 が得られます。次に、+ が評価されます。式 3 + 24 を評価すると、27 が得られます。

(3 + 4) factorial          "5040"

60512b_1 括弧 ◆ ()を使うと、式を評価するときの優先順位を変更できます。まず、式 3 + 4 を評価すると、7 が得られます。次に、式 7 factorial を評価すると、5040 が得られます。

3 lcm: 4 factorial          "24"

60512c_2 単項とキーワード ◆ 単項セレクターの方が優先順位が高いので、先に、式 4 factorial を評価すると、24 が得られます。次に、式 3 lcm: 24 を評価すると、24 が得られます。

3 lcm: 4 + 5          "9"

60512d_2 二項とキーワード ◆ 二項セレクターの方が優先順位が高いので、先に、式 4 + 5 を評価すると、9 が得られます。次に、式 3 lcm: 9 を評価すると、9 が得られます。

3 + 4 * 2          "14"

60512e_1 二項と二項 ◆ 二項セレクターの間では優先順位が等しいので、左から右へと順に評価されます。先に、式 3 + 4 を評価すると、7 が得られます。次に、式 7 * 2 を評価すると、14 が得られます。

3 lcm: 4 factorial - 5          "57"

60512f_1 単項と二項とキーワード ◆ 先に、式 4 factorial を評価すると、24 が得られます。次に、式 24 - 5 を評価すると、19 が得られます。さらに、式 3 lcm: 19 を評価すると、57 が得られます。

(3 lcm: 4) gcd: 18          "6"

キーワードとキーワード ◆ 複数のキーワードセレクターを記述するときには、括弧を使って、それぞれの区切りを明記します。先に、式 3 lcm: 4 を評価すると、12 が得られます。次に、式 12 gcd: 18 を評価すると、6 が得られます。括弧を省略すると、これらは単一のキーワードセレクター lcm:gcd: が記述されたものと見なされ、エラーとなります。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年5月15日 (月)

連載: Smalltalk use: better《6》万能メソッド★

キーワード ◆ perform:・perform:with:・perform:with:with:・perform:with:with:with:・オブジェクト・シンボル・セレクター・メッセージ・メッセージ式・引数・演算子・関数名・文字列・万能メソッド

※ PDF でご覧になるなら ⇒ 「piyo60515.pdf」をダウンロード

------------ 序 ------------

クリスマスプレゼントに金槌をもらった子どもは、
何でも叩きたがる。

Gerald M. Weinberg

◆ 今週も、先週に続いて、Smalltalk で記述されたコードの断片を示しながら、その背景にある文化や思想を理解するための、予備知識の習得を目指します。また、この連載は、プログラミング技法の習得が主たる目的ではありません。むしろ、そちらの話題に興味があるみなさんは、参考文献をお楽しみください。説明の都合(話の展開)から、Smalltalk の構文やその要素について、解説を続けます。何事も基本が大切です。もうしばらくのご辛抱を…。m(_o_)m

◆ 万能メソッドは、さまざまな場面で利用できます。玩具のピコピコトンカチと同様に、実害はないので、何でも叩いて(試して)みるにはピッタリの存在です。

------------ 本文 ------------

万能メソッド ◆ さまざまな場面で利用できる、汎用性の高い「万能」メソッドを紹介します。

3 perform: #factorial          "6"

60515a_1 ◆ 式 3 perform: #factorial を評価すると、6 が得られます。このとき、オブジェクト 3 は、メッセージ perform: #factorial を受取ると、引数に指定された factorial をセレクターとして、自身にメッセージを転送します。つまり、式 3 factorial を評価するのと、同じ結果が得られます。このように、セレクターと、関数名および演算子とは、似て非なるものであることが分ります。

| selector |
selector := #negated.
3 perform: selector.          "-3"
selector := #factorial.
3 perform: selector          "6"

60515b_1 シンボル ◆ # で始まるリテラルは、特殊な文字列でシンボルと呼ばれます。

'abc' == 'abc' copy          "false"
#abc == #abc copy          "true"

◆ 文字列は、同じ内容を持つインスタンスが多数存在しますが、シンボルは、唯一無二の存在であることが分ります。perform: などは、メソッド辞書の中から、これらのシンボルをキーとしてメソッドの実体(コンパイル済みのメソッド)を参照します。そのため、文字列とは別に、キーが重複しないことを保証できるシンボルを必要とするのです。

セレクター ◆ 一般に、メッセージ式は、1つのセレクターと複数の引数によって構成されます。メッセージ式を構成する factorial や lcm: などのセレクターは、特殊な文字列(シンボル)であり、メソッドを起動するためのトリガーとして働きます。+ も同様です。これは、演算子とは似て非なるものです。単なる文字列(シンボル)にすぎません。

3 perform: #+ with: 4          "7"

60515c_1 ◆ 式 3 perform: #+ with: 4 を評価すると、7 が得られます。このとき、オブジェクト 3 は、メッセージ perform: #+ with: 4 を受取ると、引数に指定された + をセレクター、4 を引数として、自身にメッセージを転送します。つまり、式 3 + 4 を評価するのと、同じ結果が得られます。

3 perform: #lcm: with: 4          "12"

60515d ◆ 式 3 perform: #lcm: with: 4 を評価すると、4 が得られます。このとき、オブジェクト 3 は、メッセージ perform: #lcm: with: 4 を受取ると、引数に指定された lcm: をセレクター、4 を引数として、自身にメッセージを転送します。つまり、式 3 lcm: 4 を評価するのと、同じ結果が得られます。

◆ このように「演算子とは似て非なるもの」ということが理解できると、次のような記述も可能であることが分ります。

#(+ - * /) collect: [:op |
    3 perform: op with: 4]          "#(7 -1 12 (3/4))"

これは、2つの数 3 と 4 との、和差積商を求めるものです。詳細は、今後の連載で明らかにします。

【課題】次の式を評価すると、それぞれに何が得られますか。

3 perform: #perform: with: #factorial
3 perform: #perform:with: with: #+ with: 4
3 perform: #perform:with:with: with: #between:and: with: 2 with: 4

また、その理由を説明してください。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年5月16日 (火)

連載: Smalltalk use: better《7》プロッククロージャー★

キーワード ◆ BlockClosure・BlockContext・value・value:・value:value:・クロージャー・クロージャー・コンテキスト・フィールド属性・ブロック引数・ブロック式・メソッド呼び出し・メソッド操作・メソッド定義

※ PDF でご覧になるなら ⇒ 「piyo60516.pdf」をダウンロード

------------ 序 ------------

グラスの底に顔があってもいいじゃないか

岡本太郎

◆ 親に連れられて大阪万博で見た「太陽の塔」は、幼心にも衝撃的でした。その当時、賛否両論が渦巻いていたのを知ったのは、大人になってからのことです。一見すると奇妙にも思えることから、拒否反応を示す人も少なからずいたようです。海外では賞賛されながら、日本ではあまり評価されないという事例には、枚挙に暇がありません。本物と偽物との違いが分るか、むしろ私たちの見識が問われるところです。

◆ オブジェクト指向についても同じかもしれません。メソッドがオブジェクトでもいいじゃないか。今日は、クロージャーについて考察します。一人前のオブジェクトであるクロージャーをメソッドと見なすなら、ブロック内で束縛される外部変数は「オブジェクトたるメソッド」の状態を示す、フィールド属性と見なせます。そして、クロージャーに送信できるメッセージ群は「オブジェクトたるメソッド」の状態変化を促す、メソッド操作と見なせます。インスタンスごとに異なる状態を持つように、クロージャーごとに異なる状態を持ちます。

◆ クロージャーのリテラル表記をメソッド定義と見なすなら、value などのメッセージを送ることはメソッド呼び出しに相当します。

------------ 本文 ------------

ブロッククロージャー ◆「すべてがオブジェクト」とするオブジェクト指向の世界では、メソッドもその例外ではありません。ブロッククロージャーは、その概念を理解するのに役立ちます。

[3 factorial] value          "6"
[3 factorial] class          "BlockContext"

60516a_2 ◆ ブロック内に記述されたメッセージ式(以下、ブロック式)が表すオブジェクトは、クラス BlockContext のインスタンスです。ブロック式はリテラルであり、オブジェクトとしての素朴な表現を提供します。また、変数に代入したり、メッセージを受け取ったりできます。よって、ブロッククロージャーは、名前を持たないメソッドと見なせます。

※ Squeak における BlockContext は、当時の Smalltalk では、BlockClosure となっています。この連載は、1988 年に作成した、Smalltalk セミナーの原稿をもとにしているので、クロージャーという表現を使っています。連載を機に、コンテキストに統一しても良かったのですが、あえて旧来の表現を使っています。その理由のひとつは、Ruby/Groovy など、他にクロージャーを使える環境と比較しやすいようにとの配慮です。

| block |
block := [3 factorial].
block value          "6"

60516b ブロック式の評価 ◆ block は、メッセージ value を受け取ると、ブロック内に記述されたメッセージ式 3 factorial を評価します。すると、その結果として 6 が得られます。

| block |
block := [:n | n factorial].
block value: 3          "6"

60516c ブロック引数 ◆ block は、メッセージ value: 3 を受け取ると、ブロック引数 n に、3 を代入します。すると、3 factorial を評価したのと同じ結果 6 が得られます。◆ ここで、ブロック引数というのは、それが出現するブロック内で有効な変数です。変数を宣言するときには「:」に続けて識別子を記述します。変数を参照するときには、単にその識別子を記述します。

| block |
block := [:a :b | a + b].
block value: 3 value: 4          "7"

60516d ◆ block は、メッセージ value: 3 value: 4 を受け取ると、ブロック引数 a および b に、それぞれ 3 および 4 を代入します。すると、3+4 を評価したのと同じ結果 7 が得られます。

| block |
block := [:op | 3 perform: op with: 4].
block value: #+          "7"

60516e ◆ block は、メッセージ value: #+ を受け取ると、ブロック引数 op に、#+ を代入します。すると、3 perform: #+ with: 4 を、つまり、3+4 を評価したのと同じ結果 7 が得られます。

| block1 block2 |
block1 := [:a :b | a + b].
block2 := [:n | n factorial].
block1 value: 3 value: (block2 value: 4)          "27"

60516f ◆ block2 は、メッセージ value: 4 を受け取ると、ブロック引数 n に、4 を代入します。すると、4 factorial を評価したのと同じ結果 24 が得られます。◆ block1 は、メッセージ value: 3 value: 24 を受け取ると、ブロック引数 a および b に、それぞれ 3 および 24 を代入します。すると、3+24 を評価したのと同じ結果 27 が得られます。

Java 擬で表現すると、次のようになります。

  block.(3)
  block.(3,4)
  block.(+)
  block1.(3,block2.(4))

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年5月17日 (水)

連載: Smalltalk use: better《8》基本要素の意義:リテラルとは★

キーワード ◆ BlockContext・Character・Float・LargePositiveInteger・SmallInteger・static メソッド・String・Symbol・コンストラクター・シンボル・ブロック・リテラル・空白文字・実数・整数・配列・不定長整数・文字・文字列

※ PDF でご覧になるなら ⇒ 「piyo60517.pdf」をダウンロード

------------ 序 ------------

大工と話すときは
大工の言葉を使わなければならない

Socrates (469?-399 B.C.)

◆ オブジェクト指向のルーツをたどると、キリスト生誕のはるか以前まで遡ることができます。オブジェクト指向の概念をソフトウェア開発に適用する試みは、まだ30年余りの歴史でしかありません。「旧(ふる)きを温(たず)ねて新しきを知る」。オブジェクト指向のルーツをたどると、オブジェクト指向の未来が見えてきます。

◆ ところで、オブジェクトのルーツをたどると、そこにリテラルの存在意義を知ることができます。クラスと話すときにはクラスが理解できるメッセージを使って、インスタンスと話すときにはインスタンスが理解できるメッセージを使って、それぞれ対話を図る必要があります。

------------ 本文 ------------

リテラルとは ◆ いくつかのリテラルを紹介しました。復習を兼ねて列挙すると、次のようになります。

3 class                    "SmallInteger"
3 sqrt class                    "Float"
13 factorial class                    "LargePositiveInteger"
3 printString class                    "String"
$C class                    "Character"
#factorial class                    "Symbol"
[3 factorial] class                    "BlockContext"

  1. 整数 … SmallInteger
  2. 実数 … Float
  3. 不定長整数 … LargePositiveInteger
  4. 文字列 … String
  5. 文字 … Character
  6. シンボル … Symbol
  7. ブロック … BlockContext

これ以外にも、まだ紹介していないリテラルが存在します。リテラルについて再考する前に、次の問題を考えてみてください。

◆「オブジェクトにメッセージを送ると、オブジェクトが得られる」というのが、オブジェクト指向の原則のひとつでした。では、そのメッセージを送るべき最初のオブジェクトは、どのようにして得られるのでしょう。

60517a_2◆ この例では、オブジェクト 3 にメッセージ factorial を送ると、オブジェクト 6 が得られます。では、そのもとになるオブジェクト 3 を得るには、どうしたらいいのでしょう。オブジェクト 3 も、何かオブジェクトにメッセージを送って得られたはずです。さらに、そのもとになるオブジェクトを得るには。どうやら、何か根本となるメカニズムが必要になりそうです。

◆ そこで必須となるのが、リテラルの存在です。なぜなら、メッセージを送らなくても得られるオブジェクトが存在しないなら、何事も始まらないからです。`3 ` と表記すると、文字どおり 3 という値を持つ整数オブジェクトの実体を表します。`$C` と表記すると、文字どおりの表記を持つ文字オブジェクトの実体を表します。さらに、ブロック [3 factorial] というのは、文字どおりの表記を持つメソッドオブジェクトの実体を表します。そのため、ブロックは、アルゴリズム定数とも呼ばれます。

◆ 空白を含む文字列およびシンボルは、次のように記述します。

| s t |
s := #'hello world'.                    "#'hello world'"
s at: 6.                    "$ "
t := 'hello world'.                    "'hello world'"
(s at: 6) == (t at: 6).                    "true"

◆ # に続けて ' で囲まれた文字列の中に空白を記述すると、空白を含むシンボルが得られます。すると、6番目の文字は空白 `$ ` となることが分ります。しかし、これを記述したコードで目視するのは困難です。

$  asciiValue          "32"
Character value: 32          "$ "

60517b ◆ 空白文字を表すリテラル `$ ` に、メッセージ asciiValue を送ると、そのアスキーコードを表す数値 32 が得られます。クラス Character に、メッセージ value: 32 を送ると、そのコードが表す空白文字 `$ ` が得られます。クラスもオブジェクトなので、これにメッセージを送ることは、自然な対話です。

 Java/C# におけるコンストラクターや static メソッドなど、モデルを複雑にするだけの構文要素は不要です。そこには「オブジェクトにメッセージを送ると、オブジェクトが得られる」という、統一されたモデルが存在するだけです。

Character space asciiValue          "32"
(#'A C' at: 2) == Character space          "true"

60517c◆ クラス Character に、メッセージ space を送ると、空白文字が得られます。シンボル #'A C' の2番目の文字が、この空白文字であることが分ります。

| s |
s := #'A C' asArray.          "#($A $  $C)"
s collect: [:c | c asciiValue].          "#(65 32 67)"

60517d 配列 ◆ まだ紹介していないリテラルのひとつが配列です。空白を含むシンボル #'A C' に、メッセージ asArray を送ると、文字を要素とする配列 #($A $  $C) が得られます。# に続けて () で囲まれた中に任意のリテラル(ただし、ブロックを除く)を記述すると、これらを要素とする配列オブジェクトが得られます。

Refactoring: Improving the Design of Existing Code (Addison-Wesley Object Technology Series) Book Refactoring: Improving the Design of Existing Code (Addison-Wesley Object Technology Series)

著者:Martin Fowler,Kent Beck,John Brant,William Opdyke,Don Roberts
販売元:Addison-Wesley Pub (Sd)
Amazon.co.jpで詳細を確認する


リファクタリング―プログラムの体質改善テクニック Book リファクタリング―プログラムの体質改善テクニック

著者:マーチン ファウラー
販売元:ピアソンエデュケーション
Amazon.co.jpで詳細を確認する


【参考文献】Martin Fowler, 1999
Refactoring: Improving the Design of Existing Code  ISBN0201485672

Refactoring の功労者でもある、Martin Fowler さんのルーツは、Smalltalk にあった。イディオムの宝庫です。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年5月18日 (木)

連載: Smalltalk use: better《9》基本要素の意義:変数とは★

キーワード ◆ Smap・テレパシー・ドラえもん・阿吽の呼吸・以心伝心・会話・固有名詞・四次元ポケット・指示代名詞・主語・変数・目的語

※ PDF でご覧になるなら ⇒ 「piyo60518.pdf」をダウンロード

------------ 序 ------------

すべては、以前だれかが考えたことがある。
難しいのは、それを思い出すことだ。

Goethe, Johann Wolfgang von (1749-1832)

◆ 年齢を重ねると、固有名詞がなかなか出て来なくなるという話を聞きます。「これ、それ、あれ」など、指示代名詞が多くなるという話も聞きます。先日、親友と話をする様を端で見ていた人が「よく話が通じますね」という感想を漏らしました。つまり、主語や目的語もなしに、テレパシーで会話をしているかのような奇異な感じがしたというのです。残念ながら、親友も私も、超能力や霊能力は持っていません。しかし、何を話したいのかは、阿吽の呼吸なのでしょう。以心伝心は、理屈ではうまく説明できそうにありません。

◆ 以心伝心をソフトウェア開発に導入する方法論が見つかるまでは、開発チームで主語や目的語を明確にしておく必要があります。そのとき役立つのが変数です。しかし、使い方を誤ると混乱のもととなります。

------------ 本文 ------------

変数とは ◆ プログラミング言語の違いはあっても、これらの多くに共通して存在するのが変数です。Smalltalk では、変数を宣言するときに、型を指定する必要はありません。変数には、任意のオブジェクトを代入できます。例えるなら、Smalltalk における変数は、固定長のセルではなく、何でも取り出せるドラえもんの次元ポケットのような存在なのです。

3 class          "SmallInteger"

◆ このメッセージ式は、すでに何度も登場しています。オブジェクト 3 にメッセージ class を送ると、SmallInteger が得られます。ところで、SmallInteger の正体は何でしょうか。メッセージ class は、その名前から分るように、クラスを得るために使います。よって、SmallInteger がクラスであるのは確かです。ここで問題にしたいのは、識別子 SmallInteger が表すモノの体は何かということです。「オブジェクトにメッセージを送ると、オブジェクトが得られる」のが原則です。これに従うと、メッセージ class を送ると、SmallInteger が得られる。ゆえに SmallInteger はオブジェクトである。これは、キリスト生誕の前から存在する、三段論法を適用しなくても明らかです。SmallInteger がオブジェクトである証拠に、変数に代入したり、メッセージを送ったりできます。メッセージ(セレクター)やアルゴリズム(ブロック)さえ、変数に代入できるのですから、クラスを代入できることに、驚きはないでしょう。

| class |
class := SmallInteger.
class printString          "'SmallInteger'"

◆ 変数 class に、クラス SmallInteger を代入します。メッセージ式 class printString を評価すると、変数 class が束縛するクラス SmallInteger にメッセージ printString が送られ、文字列オブジェクト 'SmallInteger' が得られます。よって、クラス SmallInteger の正体は、メッセージを受信できる、オブジェクトと見なして間違いないようです。

◆ しかし、ここで問題としているのは、クラスオブジェクトを表す、SmallInteger という識別子の体です。もしかすると、これはリテラルなのでしょうか。リテラルなら、変数に代入したり、これにメッセージを送ったりできます。なにより、リテラルというのは、オブジェクトを表現する本質的な手段のひとつです。しかし、残念ながら、SmallInteger は、リテラルではありません。では、その正体は何でしょうか。

60518a_3 ◆ 結論から先に言うと、SmallInteger という識別子の正体は、変数です。SmallInteger が変数名なら、それが参照するのは、クラスの体そのものです。つまり、変数 SmallInteger は、クラスオブジェクトを参照するために用意されたものなのです。これは、リテラル表記を持たないクラスオブジェクトを参照するために、変数が必要とされることを意味します。

◆ SmallInteger の正体は、単なる変数であることが分りました。それなら、この変数に、何か適当なものを代入できるはずです。ただし、これはあまりオススメできません。どうしても…という受講者は、自己責任のもとで、お試しください。

SmallInteger := ???

【Tips】Smap の概要
60518b_6 ◆ この連載で登場する Smap の概要を示します。これによって、メッセージ式を評価したときに得られる、オブジェクト間の相互作用が明らかになります。

 ==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年5月19日 (金)

連載: Smalltalk use: better《10》基本要素の意義:式とは★

キーワード ◆ インスタンス・クラス・メタクラス・メッセージ式・リテラル・変数

※ PDF でご覧になるなら ⇒ 「piyo60519.pdf」をダウンロード

------------ 序 ------------

間違いを笑うことと、間違えた人を笑うこととは、
同じではない。

Andrew Koenig

◆ ひととおり簡単な文法を紹介するのも、今日が最後です。これで、プログラミング言語の背景にある概念や文化について学ぶための、最低限の準備が整うことになります。

------------ 本文 ------------

式とは ◆ メッセージ式について再考する前に、次の例について考察します。

3 class          "SmallInteger"

◆ このメッセージ式は、すでに何度も登場しているので「そろそろ見飽きた」という声が聞こえてきそうです。オブジェクト 3 にメッセージ class を送ると、クラスオブジェクト SmallInteger が得られます。識別子 SmallInteger は変数名であり、これによって整数を表現するクラスの実体を参照できます。クラスもオブジェクトなので、これを変数に代入したり、これにメッセージを送ったりできます。

3 class class          "SmallInteger class"

◆ では、オブジェクト 3 にメッセージ class を送ると得られる、クラスオブジェクト SmallInteger に、さらにメッセージ class を送ると、何が得られるでしょうか。クラスもオブジェクトなら、これにメッセージを送ると、オブジェクトが得られるはずです。クラスにクラスを獲得するためのメッセージ class を送ると、クラスのクラスが得られるはずです。クラスもオブジェクトなら、そのクラス(オブジェクト)をインスタンスとするクラスがあってもいいはずです。これを、メタクラスと言います。そして、その結果として得られたのが SmallInteger class でした。では、この体は何でしょうか。

SmallInteger class          "SmallInteger class"

◆ 同様に、クラスの実体を束縛するクラス名(変数)にメッセージ class を送っても、やはり同じ結果 SmallInteger class が得られます。ここで注目して欲しいのは、このメッセージ式とその結果を見ると、どちらも同じ式 SmallInteger class であることが分ります。いったい、何が起こっているというのでしょう。

◆ オブジェクトを参照するには、リテラルを使って直接的に表現するか、変数を使って間接的に参照するという方法があることを、すでに紹介しました。そして、第3の方法が、これから示すメッセージ式です。

60519b_1 ◆ 結論から先に言うと、SmallInteger class の正体は、メッセージ式です。「すべてがオブジェクト」というのが原則です。これに従うと、メタクラスもオブジェクトなので、その体がどこかに存在します。クラスの場合には、それを参照する変数(クラス名)が用意されています。しかし、メタクラスの場合には、そのような変数やリテラル表記が用意してありません。そこで、メッセージ式として、つまり「メッセージを送ったときに得られるオブジェクト」という間接的な方法で、これを参照するのです。

◆ 実際のソフトウェア開発では、新たに作成したオブジェクトの大半は、リテラル表記を持ちません。必要なら、それを参照する変数を宣言したり、メッセージ式を記述して、そのオブジェクトを参照します。たとえば、獲得したメタクラスを任意の変数で束縛しておくと、これをいつでも好きなときに参照できます。

metaclass := SmallInteger class

◆ まとめると、オブジェクトを(直接間接を問わず)参照するには、3つの方法
 (1) リテラル (2) 変数 (3) メッセージ式
があります。

【Tips】リテラル、変数、メッセージ式

3 + 4 factorial

60519c ◆ メッセージ式 3 + 4 factorial を見ると、表面的には、2つのオブジェクト 3 および 4 が存在するだけです。しかし、この式を評価する過程において、オブジェクト 24 および 27 が生成されていることが分ります。オブジェクト 24 は、引数として、メッセージ +24 を形成します。オブジェクト 27 は、リターンとして、メッセージ式 3 + 24 を評価したときに得られます。ただし、これらのオブジェクトは、式を評価した後では、これらを直接的に参照する方法がありません。

a := 4 factorial
b := 3 + a

◆ そのため、変数を使って間接的に参照するか、再びメッセージ式を評価して、そのリターンを間接的に参照するしか術がありません。

60519a ◆ オブジェクト 6 を表現するには、3つの方法があります。まず、リテラルを使って、直接的に 6 と表記することです。次に、変数 n を使って、間接的に参照することです。最後に、メッセージ式 3 factorial を使って、そのリターンを間接的に参照することです。どの方法を使っても、同じ整数オブジェクト 6 を参照できます。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年5月22日 (月)

連載: Smalltalk use: better《11》はやくオブジェクトになりたいっ

キーワード ◆ Boolean・class・false・False・nil・not・pseudo variable・self・sole instance・super・superclass・thisContext・true・True・グリーンカード・コンパイラー・メソッド呼び出し・メタクラス・ラッパー・基本データ型・疑似変数・妖怪人間ベム 

 ※ PDF でご覧になるなら ⇒ 「piyo60522.pdf」をダウンロード

------------ 序 ------------

はやく人間になりたいっ!

「妖怪人間ベム」1968〜1969年・フジテレビ系列

◆ ひととおり簡単に文法を紹介したので、今週からは、プログラミング言語の背景にある概念や文化について紹介します。最初は、true/false について再考します。何が真であり何が偽であるかは、すべての根幹をなす概念のひとつですので、これを避けては通れません。

◆ Java の世界では、true/false はオブジェクトとは認めてもらえない半人前の存在です。それが証拠に、メソッド呼び出しには応じてくれません。Smalltalk の世界では、true/false は一人前のオブジェクトとして扱われます。それが証拠に、メッセージを投げかけると返事をしてくれます。「はやくオブジェクトになりたいっ!」今日は、そんな true/false の声に耳を傾けてみます。

------------ 本文 ------------

true/false ◆「すべてがオブジェクト」という世界では、true/false もその例外ではありません。

true class                    "True"
false class                    "False"
True superclass                    "Boolean"
False superclass                    "Boolean"

60522a◆ true/false がオブジェクトなら、そのクラスの実体が存在するはずです。任意のインスタンスが属するクラスの実体を得るには、メッセージ class を送るだけです。すると、true のクラスは True であり、false のクラスは False であることが分ります。もちろん、識別子 True/False は変数名であり、クラスの実体を束縛するので、これらを容易に参照できます。

◆ True/False は、オブジェクトでもあり、クラスとしての特徴も持ちます。クラスなら、親クラスが存在するはずです。メッセージ superclass を送ると、その親クラスが得られます。すると、True/False に共通の親クラスは、Boolean であることが分ります。

◆ Java の(非)常識からすると、true/false は、Boolean のインスタンスでも良さそうなものです。True/False など冗長ではないか…との声が聞こえてきそうな気配です。もちろん、それにはそれなりの理由があります。そして、それを理解することが、真のオブジェクト指向の世界へと導きます。ただひとつのオブジェクトのために、クラスを個別に用意するとは、なんて贅沢なのでしょう。でも、こうすると、if 文をメソッドとしてスマートに定義できるのです。

◆ それでは、クラス True には、ほかにどのようなインスタンスがあるのでしょうか。残念ながら、true 以外にはインスタンスを持ちません。このように、あるクラスに属する、ただひとつのインスタンスを sole instance と言います。sole instance の例には、true, false, nil などがあります。

※ Java の世界では、true/false は一人前のオブジェクトとは認めてもらえず、半人前の存在です。それが証拠に、true.toString() はエラーとなり、オブジェクト市民には与えられている権利である、メソッド呼び出しさえままなりません。System.out.println("true: "+true) では、コンパイラーの介護によって、オブジェクト市民(ここでは、グリーンカードを持つ String インスタンス)との同席が許されます。基本データ型は、オブジェクト指向の世界では、オブジェクト市民の子供たちに紛れて、みそっかすとして扱われます。たとえば、この指とまれと言われてコレクションごっこをしようとしても、親切なラッパーの加護がなければ、仲間に混ぜてもらえません。気配りの勧めを常とする autoboxing は、そんな形見の狭い思いをさせたくないので、基本データ型が傷つかないように、陰日向になってかばってあげてくれるのです。

※ C# の世界では、基本データ型にもグリーンカードが与えられ、一人前のオブジェクトとの同席が許されます。しかし、null などのみそっかすには、平等の権利が与えられていません。

◆ オブジェクトを参照するには、3つの方法がありました。
 (1) リテラル (2) 変数 (3) メッセージ式
では、true/false は、どれに相当するのでしょうか。正解は、変数です。つまり、変数 true/false は、それぞれ真偽を表すオブジェクトを束縛します。これらの変数は、疑似変数〔pseudo variable〕と呼ばれます。ただし、これらは変数でありながら、代入ができません。代入できないなら定数と同じでは…という声が聞こえてきそうですが、残念ながらリテラルではありません。これらの疑似変数には、Smalltalk が起動されたときに、対象となるオブジェクトが代入され、それ以降の代入は許されないのです。true/false は物事の真理であり、プログラマーが安易に犯してはならない領域なのです。

※ すべてのクラスオブジェクトも、それぞれのメタクラスの sole instance です。たとえば、クラス String は、メタクラス String class の sole instance です。

60522b

※ 他に、nil、self、super、thisContext などの疑似変数があります。thisContext について理解することが、開発環境のみならず、プログラマー自身もオブジェクトと見なすという、真の統合開発環境へと誘います。

true not          "false"
false not          "true"

60522c◆ メッセージ not は、論理否定を表すものです。オブジェクト true にメッセージ not を送ると、その否定を表すオブジェクト false が得られます。オブジェクト false にメッセージ not を送ると、その否定を表すオブジェクト true が得られます。ここで注目して欲しいのは、メッセージを受け取ったオブジェクト true/false が、どのオブジェクトを返すべきかを決定しているということです。つまり、メッセージ not に対応するメソッドは、true/false が属するクラスで定義されることが期待されます。

3 < 4                    "true"
(3 < 4) not          "false"

60522d ◆ メッセージ < は、大小比較を表すものです。オブジェクト 3 にメッセージ < 4 を送ると、大小を比較した結果を表すオブジェクト true が得られます。すると、メッセージ not を送るべき相手は、true となることが分ります。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年5月23日 (火)

【準備中】連載: Smalltalk use: better《12》はやくメッセージになりたいっ

キーワード ◆ Smap・コンパイラー・ブロック・ブロック引数・メッセージ式・一時変数・演算子 ?:・回文・階乗・制御構造

※ PDF でご覧になるなら ⇒ 公開日まで、しばらくお待ちください。

------------ 序 ------------

臨死のマック抱く妻の心理
りんしのまつくだくつまのしんり

「またたび浴びたタマ」村上春樹

◆ 回文というのは、逆から読んでも成立する文を表します。よく知られた例文には「竹屋が焼けた」というのがあります。英文には "Madam, I'm Adam." というのもあります。他にも「ビキニの下は私のニキビ」というのが…。

◆ フランス大会(1998年)のときに創作したものです。回文に、解説が必要ということ自体、出来が良くないことの証ですが…。これを機に成仏させるべく、恥を忍んでここに残しておきます。

力士「え〜!この二枚はレヤ…」ジダン「駄洒落は、いまに!」の声しきり。

りきしえこのにまいはれやじだんだじやれはいまにのこえしきり

【解説】力士だって人の子。本場所を抜け出しても、ワールドカップを見に行きたぁ〜い。タニマチから、二枚のレヤものプラチナチケットをゲ〜ット。金星と同伴で、意気揚々とチャンコ屋へ繰り出します。そこで、何気にテレビを見ていると、フランス代表のジダン選手を起用したコマーシャルが…。しかし、彼が口にした駄洒落は、いまいちというか、いまにというか…。彼のプレーは超一流なだけに、ちょっと拍子抜けがする思いなのでした。

------------ 本文 ------------ 

◆ Smalltalk には、コンパイラーに組み込みの制御構造はありません。つまり、制御構造も、メッセージ式を使って表現するのです。

| min |
min := [:a :b | a < b ifTrue: [a] ifFalse: [b]].
min value: 3 value: 4.          "3" 
min value: 5 value: 4.          "4"   

60523a ◆ 最小値を求めるブロック min を用意します。これにメッセージ value: 3 value: 4 を送ると、2つの引数の最小値 3 が得られます。ブロック内に記述された次のメッセージ式は、

a < b ifTrue: [a] ifFalse: [b]


Java で記述されたコードの断片を彷彿とさせます。

a < b ? a : b

キーワードセレクター ifTrue:ifFalse: の引数には、それぞれブロック式を指定します。ここで`ブロック式`と表現したのは、リテラルだけでなく、変数、およびメッセージ式を評価したときにブロックが得られるものを、引数として指定できることを意味します。

◆ 再び、ブロック内に記述されたメッセージ式に着目してください。このとき、ifTrue:ifFalse: を伴うメッセージを受け取る相手は何でしょうか。二項セレクターの方が優先順位が高いので、先に a < b が評価されます。すると、このメッセージ式を評価したときに得られるオブジェクトに対して、メッセージ ifTrue: [a] ifFalse: [b] が送られるものと期待されます。

a < b ifTrue: [a] ifFalse: [b]

60523b ◆ オブジェクト a にメッセージ < b を送ると、オブジェクト true または false が得られます。これに、メッセージ ifTrue: [a] ifFalse: [b] を送ると、オブジェクト a または b が得られます。

| factorial |
factorial := [:n | | m |
    n < 0 ifTrue:[m := n negated] ifFalse: [m := n].
    m factorial].
factorial value: 3.          "6"
factorial value: 0.          "1"
factorial value: -3.          "6"

◆ 階乗を求めるブロック factorial を用意します。これにメッセージ value: -3 を送ると、負号を取り除いた数 3 の階乗である 6 が得られます。その定義により、0 の階乗は 1 となるので、注意が必要です。負数の階乗は未定義なので、この事例は、ifTrue:ifFalse: を説明するための便宜的なものと考えてください。

◆ ブロック内だけで有効な一時変数を宣言するには、| と | との間に、識別子 m を記述します。ブロック引数 :n に続く | は、その宣言部とブロック本体に記述するメッセージ式との区切りを表します。最初は奇異な感じがするかもしれませんが、これも慣れの問題で、それまでは少し注意が必要です。

| factorial |
factorial := [:n | | m |
    m := n < 0 ifTrue:[n negated] ifFalse: [n].
    m factorial].

◆ ifTrue:ifFalse: を使うときには、ブロック式を評価して得られるオブジェクトを、そのまま変数に代入できます。そのため、ブロック内で個別に変数 m に代入するのではなく、ifTrue:ifFalse: を伴うメッセージ式を評価して得られるオブジェクトを変数 m に代入すると、より簡潔なコードを記述できます。これは、Java で記述された、次のコードの断片を彷彿とさせます。

m = n < 0 ? -n : n

【課題】負数の階乗
負数の階乗を、その絶対値の階乗に負号を付加したものとする、別の factorial を定義してください。

【補足】

| min |
min := [:a :b | a < b ifTrue: [a] ifFalse: [b]].
min value: 3 value: 4.          "3"

60523c_1 ブロック内外に記述されたコードを展開した形で表現すると、その Smap はこのようになります。

【補足】次のメッセージ式は、

min value: 3 value: 4
factorial value: 3

Java 擬で表現すると、次のようになります。

min.(3,4)
factorial.(3)

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年5月24日 (水)

連載: Smalltalk use: better《13》true/false が Boolean だったら

キーワード ◆ Boolean・False・ifTrue:・ifTrue:ifFalse:・not・True

※ PDF でご覧になるなら ⇒ 「piyo60524.pdf」をダウンロード

------------ 序 ------------

難しいのは
二通りのやり方の違いがすぐには表面化しないことだ
違いはそのプログラムを
保守あるいは変更する段になって見えてくる

Brian Richter, 1994

◆ 引き続き、true/false を Boolean のインスタンスではなく、True/False のインスタンスとする場合について考察します。これら二通りのやり方の違いを理解することで、クラス「思考」から、オブジェクト「思考」への扉を開きます。

------------ 本文 ------------
 

◆ メッセージ not の使い方は、すでに紹介しました。今度は、これをどのように実現するかについて考察します。true/false は、Boolean のインスタンスではなく、それぞれ True/False のインスタンスです。ここで、true/false が、Boolean のインスタンスであると定します。すると、メッセージ not は、どのように実現されるでしょうか。

not := [:bool | | result |
    bool == true ifTrue: [result := false].
    bool == false ifTrue: [result := true].
    result].
not value: true.          "false" 
not value: false.          "true"

true not          "false" 
false not          "true"

60524a_4 ◆ メッセージ not に相当するブロック not を用意します。これにメッセージ value: true を送ると、その否定を表す false が得られます。このとき、メッセージ式 not value: true は、true not に相当します。

  1. ブロック引数 bool は、Boolean のインスタンスと仮定した true/false を束縛します。
  2. bool が参照するオブジェクトが true か false かを判定して、その結果として得られるオブジェクト true/false に、ifTrue: を伴うメッセージを送ります。
  3. 一時変数 result は、true/false を束縛するので、どちらかがリターンオブジェクトとなります。

◆ ここで注意して欲しいのは、リターンオブジェクトを用意するのは、true/false の役割であるということです。これは、クラス Boolean において、ifTrue: が実現されるべきであることを示唆します。

not := [:bool | bool ifTrue: [false] ifFalse: [true]].
not value: true.          "false" 
not value: false.          "true"   

true not          "false" 
false not          "true"

60524b_2◆ ifTrue: の代わりに、ifTrue:ifFalse: を使って実現すると、どうなるでしょう。

  1. ブロック引数 bool は、Boolean のインスタンスと仮定した true/false を束縛します。
  2. bool が参照するオブジェクトに、ifTrue:ifFalse: を伴うメッセージを送ります。
  3. true/false のどちらかがリターンオブジェクトとなります。

◆ ここで注意して欲しいのは、リターンオブジェクトを用意するのは、true/false の役割であるということです。これは、クラス Boolean において、ifTrue:ifFalse: が実現されるべきであることを示唆します。

◆ このように、クラス Boolean において実現しようとすると、true/false のどちらであるかを識別する必要があります。では、true/false が、それぞれ True/False のインスタンスならどうなるでしょう。

60524c◆ まず、クラス True で実現する場合について考えます。このとき、false について考慮する必要はありません。true が、そのクラスの唯一のインスタンスなので、ごく自然であり必然です。すると、メッセージ value: true を受け取ったときに、単に、リターンオブジェクト false を用意するだけでよくなります。

60524d◆ 次に、クラス False で実現する場合について考えます。このとき、true について考慮する必要はありません。false が、そのクラスの唯一のインスタンスなので、ごく自然であり必然です。すると、メッセージ value: false を受け取ったときに、単に、リターンオブジェクト true を用意するだけでよくなります。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年5月25日 (木)

連載: Smalltalk use: better《14》true/false が Boolean でないのは

キーワード ◆ 3+4・Boolean・False・hello world・ifTrue:・ifTrue:ifFalse:・not・True

※ PDF でご覧になるなら ⇒ 「piyo60525.pdf」をダウンロード

------------ 序 ------------

失敗ですって。失敗なんかしてないわ。 
まだ成功してないだけよ。

"Slack", Tom DeMarco

◆ 生まれて初めての Smalltalk プログラミング。世界で最も有名なプログラムと言えば "hello world" を表示させることでしょうか。では、Smalltalk の場合にも、やはり "hello world" なのでしょうか。そうとは限りません。ここで "3+4" を実行してみるのが、お洒落なところです。個人的な意見ですが、これが Smalltalker の嗜みというものです。

この次はもっとうまく失敗しましょう。
もしそれがたまたま成功したら、ラッキーじゃないの。

小泉ひよ子・談

◆ Workspace に 3+4 と入力して do it すると、そこにはちゃんと "7" が現れるではありませんか。感激のあまり (@_@); うるうる。あらそんな冷やかな目で、私を見ないで…。だったら "3+4=7" を証明してみせましょう。その詳細は "Computer Today," 1995/11 をご覧ください。

------------ 本文 ------------

ifTrue := [:bool :block |
    bool ifTrue: [block value] ifFalse: []].
ifTrue value: true value: [3 factorial].          "6" 
ifTrue value: false value: [3 factorial].          "nil"

true ifTrue: [3 factorial]          "6"   
false ifTrue: [3 factorial]          "nil"

60525a_2 ◆ メッセージ ifTrue: に相当するブロック ifTrue を用意します。すると、メッセージ式 ifTrue value: true value: [3 factorial] は、true ifTrue: [3 factorial] に相当します。

◆ まず、クラス Boolean で実現する場合について考えます。(1)ブロック引数 bool は、Boolean のインスタンスと仮定した true/false を束縛します。(2)bool が参照するオブジェクトに、ifTrue:ifFalse: を伴うメッセージを送ります。(3)true なら、ブロック引数 block が束縛するブロックを評価します。(4)false なら、nil をリターンオブジェクトとします。

ifTrue := [:block | block value].
ifTrue value: [3 factorial].          "6"

60525c_1 ◆ 次に、クラス True で実現する場合について考えます。このとき、false について考慮する必要はありません。なぜなら、true が、そのクラスの唯一のインスタンスだからです。すると、メッセージ value: [3 factorial] を受け取ったときに、単に、ブロック式を評価するだけとなります。

ifFalse := [:bool :block |
    bool ifTrue: [] ifFalse: [block value]].
ifFalse value: true value: [3 factorial].          "nil" 
ifFalse value: false value: [3 factorial].          "6" 

true ifFalse: [3 factorial]          "nil"   
false ifFalse: [3 factorial]          "6"

60525b_2 ◆ メッセージ ifFalse: に相当するブロック ifFalse を用意します。すると、メッセージ式 ifFalse value: true value: [3 factorial] は、true ifFalse: [3 factorial] に相当します。

◆ まず、クラス Boolean で実現する場合について考えます。(1)ブロック引数 bool は、Boolean のインスタンスと仮定した true/false を束縛します。(2)bool が参照するオブジェクトに、ifTrue:ifFalse: を伴うメッセージを送ります。(3)true なら、nil をリターンオブジェクトとします。(4)false なら、ブロック引数 block が束縛するブロックを評価します。

ifFalse := [:block | nil].
ifFalse value: [3 factorial].          "nil"

60525d_1 ◆ 次に、クラス False で実現する場合について考えます。このとき、true について考慮する必要はありません。なぜなら、false が、そのクラスの唯一のインスタンスだからです。すると、メッセージ value: [3 factorial] を受け取ったときに、単に、リターンオブジェクト nil を用意するだけとなります。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年5月26日 (金)

連載: Smalltalk use: better《15》そして True/False が生まれる

キーワード ◆ Boolean・False・ifTrue:ifFalse:・True・パッチワーク・思考フレーム・統合開発環境

※ PDF でご覧になるなら ⇒ 「piyo60526.pdf」をダウンロード

------------ 序 ------------

高橋「テレビと高橋の講義には気を付けよう…ということだと思います」

放送大学・国際政治(’04)高橋和夫
第1回 テレビと国際政治〜もうだまされないために〜

◆ 韓流ブームの火付け役ともなった「冬ソナ現象」は、まだ記憶に新しいところです。しかし、その内容には、昭和40年代に放映されたドラマを寄せ集めた、パッチワークを見せられる思いがします。かと思えば、日本沈没 (1973)、犬神家の一族(1976)、戦国自衛隊(1979)、南極物語(1983) など、さまざまな作品がリメイクされています。私などは、つい懐かしさが先行して見入ってしまいますが、その当時を知らない人たちには、新鮮な感動を誘うのでしょうか。

◆ 格差社会は、IT 業界も例外ではありません。Java/Eclipse や C#/VisualStudio の生産性の低さには居た堪れず、先祖返りを見せられる思いがします。これらの開発環境を見ていると、南極物語と同じ年に公開された Smalltalk-80 には遠く及ばず、その格差には愕然とする思いです。本来の統合開発環境は、このような際物ではなかったはずです。もう騙されないためにも…。もちろん、Smalltalk だけがその選択肢ではなく、Allegro Common Lisp など、真の統合開発環境と呼べるものも、いくつか存在します。知ってる人だけが得をする。知らないあなたは…。

◆ 十数年前(1988-1990年)に作成したセミナー資料をもとに、連載記事(復刻改訂版)として公開しました。当時のセミナー受講者のみなさんも、今では最前線でご活躍のことと思います。初めてご覧になったみなさんは、十数年前に作成した記事を見て、どのように感じられたでしょうか。この連載が、旧くて新しい Squeak/Smalltalk を知る一助となれば幸いです。

------------ 本文 ------------

ifTrueifFalse := [:bool :trueBlock :falseBlock |
    bool    ifTrue: [trueBlock value]
        ifFalse: [falseBlock value]].
ifTrueifFalse value: true
    value: [3 factorial] value: [3 negated].        "6"
ifTrueifFalse value: false
    value: [3 factorial] value: [3 negated].        "-3"

true
    ifTrue: [3 factorial] ifFalse: [3 negated]      "6" 
false
    ifTrue: [3 factorial] ifFalse: [3 negated]      "-3"

60526a_2 ◆ メッセージ ifTrue:ifFalse: に相当するブロック ifTrueifFalse を用意します。すると、メッセージ式 ifTrueifFalse value: true value: [3 factorial] value: [3 negated] は、true ifTrue: [3 factorial] ifFalse: [3 negated] に相当します。

◆ クラス Boolean で実現する場合について考えます。(1)ブロック引数 bool は、Boolean のインスタンスと仮定した true/false を束縛します。(2)bool が参照するオブジェクトに、ifTrue:ifFalse: を伴うメッセージを送ります。(3)true なら、ブロック引数 trueBlock が束縛するブロックを評価します。(4)false なら、ブロック引数 falseBlock が束縛するブロックを評価します。

◆ と、ここまでは、これまでの話とさして変りはありません。では、問題です。今、ここで用意したブロック ifTrueifFalse は、に相当するものでしょう。その答えは、まさに、ifTrue:ifFalse: そのものです。つまり、自身を実現するために、自身の実現が前提となっているのです。この「鶏が先かタマゴが先か」その解決策のひとつとなるのが、true/false を Boolean のインスタンスにしないということです。こうして、クラス True/False の存在意義が生まれます。

ifTrueifFalse := [:trueBlock :falseBlock | trueBlock value].
ifTrueifFalse
    value: [3 factorial] value: [3 negated].        "6" 

true
    ifTrue: [3 factorial] ifFalse: [3 negated]      "6" 

60526b_1 ◆ クラス True で実現する場合について考えます。このとき、false について考慮する必要はありません。なぜなら、true が、そのクラスの唯一のインスタンスだからです。

◆ すると、メッセージ value: [3 factorial] value: [3 negated] を受け取ったときに、単に、1番目のブロック式を評価するだけでよくなります。

◆ ブロック ifTrueifFalse は、true のために用意したものです。メッセージが正しく伝達されることを保証するのが、オブジェクト true 自身の存在なのです。

ifTrueifFalse := [:trueBlock :falseBlock | falseBlock value].
ifTrueifFalse
    value: [3 factorial] value: [3 negated].        "-3"

false
    ifTrue: [3 factorial] ifFalse: [3 negated]      "-3"

60526c_1 ◆ クラス False で実現する場合について考えます。このとき、true について考慮する必要はありません。なぜなら、false が、そのクラスの唯一のインスタンスだからです。

◆ すると、メッセージ value: [3 factorial] value: [3 negated] を受け取ったときに、単に、2番目のブロック式を評価するだけでよくなります。

◆ ブロック ifTrueifFalse は、false のために用意したものです。メッセージが正しく伝達されることを保証するのが、オブジェクト false 自身の存在なのです。

------------ Epilogue ------------

       
    初めての人のためのLISP    
    Book                                                                                                                 
        初めての人のためのLISP        
        著者        
竹内 郁雄
販売元
サイエンス社
定価(税込)
¥ 2,520

◆ なぜ Lisp の本が、それには深い訳が…。Lisp を知ると、Smalltalk が見えてきます。Lisp を知るには、5つのブリミティヴについて理解することが肝要です。すると、Lisp の世界を理解するときの思考フレームが、そのまま Smalltalk の世界を理解するための強力な武器(道具立て)となります。

◆ 連載開始時の予定(全20回)では、コレクションフレームワークまでを紹介するつもりでした。しかし、予定した以上に記事が膨らんでしまい、あと5回でそこまで紹介できなくなってしまいました。そこで、残したテーマは、続編(シーズン2)で紹介することにします。それまで待てない…というみなさんは、参考文献をご覧になってください。

◆ ひとまず連載を終えるにあたって、次の言葉を紹介しておきます。

Messages are the heartbeat of a Smalltalk program.

Kent Beck

ひよ子「あとって言い訳でしょ」 育未「ご、よ…」

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年6月11日 (日)

【予告編】連載: Smalltalk use: better《Season II》

------------ 序 ------------

だれかを槍玉にして、
あいつが悪人だから、
あいつをやっつければ世界が平和になる
っていう映画はね、それだけは創りたくない

宮崎 駿

◆ a<b と b>a とは違う。a-b > 0 は成立しても、a>b は成立しない。3+4 == 7 は成立しても、3*4 == 12 は成立しない。そんな、Java/C# の常識が通用しない、オブジェクト指向(思考)の世界へと誘います。

◆ 天動説(地球中心説)は間違いで、地動説(太陽中心説)は正しいのか。Java/C# を中心に据えたオブジェクト指向の世界観を見直すとともに、オブジェクト指向のルーツを辿って、十七世紀へとタイムスリップします。

◆ 今秋、公開予定。Smalltalk use: better《Season II》に、乞うご期待。

キーワード ◆ Squeak・Smalltalk

------------ 本文 ------------

育未「ねえ、これ書いたの誰 (<.<(..)>.>)」
ひよ子「私…よろしくネ (^_^)/~」

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

 

| | コメント (0) | トラックバック (0)

2006年8月 7日 (月)

連載: Smalltalk use: better《16》大きいことはいいことかな★

キーワード ◆ <・ASCII・asciiValue・Character・self・関数 __lt__・大小比較・文字

60800 ※ PDF でご覧になるなら ⇒ 公開日まで、お待ちください。

------------ 序 ------------

この連載は、1988〜1990年に開催した Smalltalk のセミナー用テキスト(原稿)および講義ノート(ネタ帳)をもとに、再構成したものです。当時と、基本的な枠組みは変りません。その中から、C++ と比較した記述などを、Java に変更しています。翌1991年には、James Gosling さんが(Java に改称する前の)オブジェクト指向言語 Oak の開発に着手したとされています。つまり、その時点では、Java はまだ存在すらしていませんでした。新しくて旧い Java とは異なる、旧くて新しい Smalltalk が提供する、究極のオブジェクト指向の世界へ、さあご一緒にどうぞ。

◆ 三角形の内角の和は、180 度である。二点を通る直線は、ただ1つだけ存在する。これらの常識は、非ユークリッド空間では通用しません。試しに、三角形を紙の上に描いた後で、その紙の縁をほんの少し持ち上げてみてください。すると、内角の和が 180 度より大きくなったり小さくなったりする空間が存在することに気付きます。さらに、二点を通る直線が、無数に存在する空間が存在することを、容易に想像できるようになります。同様に、Java/C# などの世界で培われた常識が通用しない、オブジェクト指向の世界が存在することを、理解できるようになるでしょう。小学校に…(続く)

◆ Java/C# などの世界では、a < b と b > a とは同じ結果が得られるというが常識です。しかし、純粋なオブジェクト指向プログラミングの世界では、この常識が通用しない場面に遭遇します。なぜなら…

------------ 本文 ------------

◆ クラス Character を使って、文字の大小比較について考察します。メッセージセレクター < を使って、2つの文字を大小比較できます。

$a < $b    "true"
$a < $a    "false"
$b < $a    "false"
$A < $a    "true"
$A < $A    "false"
$a < $A    "false"

◆ 2つの文字が同じなら false が得られます。2つの文字が違うなら、その ASCII コードの値に基づいて、大小比較を行った結果が得られます。

60807a

.

.

.

$A asciiValue    "65"
$a asciiValue    "97"
$b asciiValue    "98"

60807basciiValue を使うと、ASCII コードの値が得られます。そこで、この値によって、文字の大小比較を行います。すると、大文字の後に、小文字が続くことが分かります。よって、$A < $a となります。つまり、< を使うと、2つの文字が ASCII コード順に並んでいるかを判定できます。

lt := [:c1 :c2 |
    c1 < c2].
lt value: $a value: $b        "true"

< に相当する、ブロック lt について考えます。lt を < と見なすと、
 lt value: $a value: $b
は、
 $a < $b
に相当します。つまり、文字 $a に対して、メッセージ < $b を送るのと、同等の機能を実現できます。

def __lt__(c1, c2):
    return c1 < c2
print __lt__('a', 'b')
print 'a' < 'b'
# -------------------------------- Output --
True
True

【注意】Python では、特殊な関数 __lt__ によって、演算子 < の機能を規定します。メソッド呼び出しと同等の、演算子による表記が可能になります。

lt := [:Self :aCharacter |
    Self < aCharacter].
lt value: $a value: $b        "true"

◆ ブロック lt において、その役割を明確にするために、引数の名前を変更します。引数 Self が束縛するオブジェクトが、メッセージの受け手となります。どのメソッドを適用するかは、Self が決定します。

【注意】Self という名前の引数は、メソッド本体を記述するときに、レシーバー(メッセージの受け手)を表す疑似変数 self を意識したものです。

lt := [:Self :aCharacter |
    Self asciiValue < aCharacter asciiValue].
lt value: $a value: $b.    "true"
lt value: $a value: $a.    "false"
lt value: $b value: $a.    "false"
lt value: $A value: $a.    "true"
lt value: $A value: $A.    "false"
lt value: $a value: $A.    "false"

< に相当する、ブロック lt について再考します。lt を < と見なすと、
 lt value: $a value: $b
は、
 $a < $b
に相当します。つまり、文字 $a に対して、メッセージ < $b を送るのと、同等の機能を実現できます。

◆ $a < $b を評価すると true が得られることから、2つの小文字が ASCII コード順に並んでいるのが分かります。$a < $a を評価すると false が得られることから、同じ文字を比較すると、つねに false となるのが分かります。$A < $A についても同様です。$b < $a を評価すると false が得られることから、2つの小文字が ASCII コード順に並んでいないのが分かります。$A < $a を評価すると true が得られることから、ASCII コードでは、大文字の後に小文字が並んでいるのが分かります。$a < $A を評価すると false が得られるのも、同様に説明できます。

60807c ◆ ブロック lt を実現するときに、オブジェクト間で、どのようにメッセージがやり取りされているかを観察します。

〔1,2〕ブロック引数 Self および aCharacter が束縛するオブジェクトに対して、メッセージ asciiValue を送ると、その ASCII コードを表す整数値が得られます。

〔3〕2つの文字の大小比較は、これらの値の大小比較によって行われます。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年8月 8日 (火)

連載: Smalltalk use: better《17》私より大きいなら私より小さいかな★★

キーワード ◆ <=・>・>=・ダブルディスパッチ・大小比較・文字

※ PDF でご覧になるなら ⇒ 公開日まで、お待ちください。

------------ 序 ------------

◆ 小学校に入学した頃のことを思い出してください。「いちたすいちは、にぃ〜」から始まって、足し算を覚え、やがて引き算を習います。まだ小さな子供たちに「5−3 は?」と尋ねたら「にぃ〜」と笑顔で答えることでしょう。次に「3−5 は?」と尋ねたら「ひけないよ」と真顔で答える子供も中にはいます。その子に「それができるのよ」と教えようとすると「ちいさいのからおおきいのはひけないもん」と怪訝そうな顔をされるかもしれません。そこで「小さな数から大きな数を引けるのよ」と無理強いをすると「オトナってバカじゃない」と相手にされなくなるかもしれません。やがて…(続く)

◆ 負数の概念を導入すると、それまで無意味とされた「小さな数から大きな数を引くこと」にも意義が生まれます。+ や < などの演算は、数だけを対象とするものでした。しかし、その対象を文字列にまで拡張しようとすると、新たな問題に直面することになります。たとえば…

------------ 本文 ------------

◆ 同様に、メッセージセレクター > を使って、2つの文字を大小比較できます。

$a > $b    "false"
$a > $a    "false"
$b > $a    "true"
$A > $a    "false"
$A > $A    "false"
$a > $A    "true"

◆ 2つの文字が同じなら false が得られます。2つの文字が違うなら、< とは、逆の結果が得られます。

◆ 次のような状況で、2つの文字がお互いに大小比較をしているものとします。

60808a ◆ 誰かに「私より大きいか」と問われたら、その相手に「私より小さいか」と問い返すことで、巧みな問題解決(ダブルディスパッチ)を図ります。これは、メソッド > を記述するときに、メソッド < の記述を再利用できることを意味します。

.

.

lt := [:Self :aCharacter |
    Self asciiValue < aCharacter asciiValue].
gt := [:Self :aCharacter |
    lt value: aCharacter value: Self].
gt value: $a value: $b.    "false"
gt value: $a value: $a.    "false"
gt value: $b value: $a.    "true"
gt value: $A value: $a.    "false"
gt value: $A value: $A.    "false"
gt value: $a value: $A.    "true"

> に相当する、ブロック gt について考えます。lt を < と見なすと、
 lt value: aCharacter value: Self
は、
 aCharacter < Self
に相当します。つまり、引数 aCharacter に対して、自分 Self を引数とするメッセージ < Self を送るのと、同等の機能を実現できます。

◆ 同様に、メッセージセレクター >= および <= を使って、2つの文字を大小比較できます。

【注意】何が起こっているのか
次の実行結果を見て、

Transcript show: 3 + 4; space.
Transcript show: 3 + '4'; space.
Transcript show: '3' + 4; space.
Transcript show: '3' + '4'; cr.
Transcript show: 3 < 4; space.
Transcript show: 3 < '4'; space.
Transcript show: '3' < 4; space.
Transcript show: '3' < '4'
# -------------------------------- Transcript --
7 7 7 7
true true false true

'3' < 4 を評価したときだけ、error: 'Instances of SmallInteger are not indexable' となる理由を考えてください。他は何故エラーにならないのでしょうか。

lt := [:Self :aCharacter |
    Self asciiValue < aCharacter asciiValue].
ge := [:Self :aCharacter |
    (lt value: Self value: aCharacter) not].
ge value: $a value: $b.    "false"
ge value: $a value: $a.    "true"
ge value: $b value: $a.    "true"
ge value: $A value: $a.    "false"
ge value: $A value: $A.    "true"
ge value: $a value: $A.    "true"

>= に相当する、ブロック ge について考えます。lt を < と見なすと、
 (lt value: Self value: aCharacter) not
は、
 (Self < aCharacter) not
に相当します。つまり、自分 Self に対して、メッセージ < aCharacter を送った結果を利用して、同等の機能を実現できます。

gt := [:Self :aCharacter |
    lt value: aCharacter value: Self].
le := [:Self :aCharacter |
    (gt value: Self value: aCharacter) not].
le value: $a value: $b.    "true"
le value: $a value: $a.    "true"
le value: $b value: $a.    "false"
le value: $A value: $a.    "true"
le value: $A value: $A.    "true"
le value: $a value: $A.    "false"

<= に相当する、ブロック le について考えます。gt を > と見なすと、
 (gt value: Self value: aCharacter) not
は、
 (Self > aCharacter) not
に相当します。つまり、自分 Self に対して、メッセージ > aCharacter を送った結果を利用して、同等の機能を実現できます。

60808b .

.

.

$a >= $b    "false"
$a >= $a    "true"
$b >= $a    "true"
$A >= $a    "false"
$A >= $A    "true"
$a >= $A    "true"

◆ < とは、逆の結果が得られます。

$a <= $b    "true"
$a <= $a    "true"
$b <= $a    "false"
$A <= $a    "true"
$A <= $A    "true"
$a <= $A    "false"

◆ > とは、逆の結果が得られます。

◆ ここで注目したいのは、メソッド < を除く、他の3つの大小比較に関する記述が、特定の種類のオブジェクトに依存しないことです。これは、任意の種類のオブジェクトに対しても、これらの記述を再利用できることを意味します。すると、任意の種類に対して < を規定するだけで、他の大小比較を再定義する必要がなくなります。つまり、メソッドを記述する手間を、1/4 に軽減できる可能性を秘めています。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年8月 9日 (水)

連載: Smalltalk use: better《18》あなたの大きいは私のとは違うかな★

キーワード ◆ +・<・>・メソッド・メッセージ・実数・整数・大小比較

※ PDF でご覧になるなら ⇒ 公開日まで、お待ちください。

------------ 序 ------------

◆ やがて、学年が進むと、掛け算を覚え、割り算を教わります。「5÷3 は?」と尋ねたら「割れきれないから、余りがにぃ〜」と得意顔で答える子供も中にはいます。その子に「それができるのよ」と教えようとすると「だめだよ、余りがでるもん」と怪訝そうな顔をされるかもしれません。そこで「÷ を / に変えてみるのよ」と無理強いをすると「大人って馬鹿じゃない」と相手にされなくなるかもしれません。さらに…(続く)

◆ ファイルシステムによっては、大文字小文字を区別しないものが存在します。その場合、同じ綴りでありながら、大文字と小文字との違いだけがある名前を持つファイルを、同じフォルダー内に作成できません。たとえば、'File' と 'file' とは、これらをファイル名と見なすと、その見掛けと違って、同じ名前として認識されます。なぜこのような事態になるかというと…

------------ 本文 ------------

◆ 2つの文字の大小比較を再定義します。

lT := [:Self :aCharacter |
    Self asUppercase asciiValue
    < aCharacter asUppercase asciiValue].
lT value: $A value: $a.    "false"

< に相当する、ブロック lt について考えます。lT を < と見なすと、
 lT value: $A value: $a
は、
 $A < $a
に相当します。つまり、文字 $A に対して、メッセージ < $a を送ることで、2つの文字を「大文字と小文字とを区別せずに」大小比較した結果が得られます。

lt := [:Self :aCharacter |
    Self asciiValue < aCharacter asciiValue].
gt := [:Self :aCharacter |
    lt value: aCharacter value: Self].
lt value: $A value: $a.    "true"
gt value: $a value: $A.    "true"

60809a

< に相当する、ブロック lt について考えます。lt を < と見なすと、
 lt value: $A value: $a
は、
 $A < $a
に相当します。つまり、文字 $A に対して、メッセージ < $a を送ることで、2つの文字を「ASCII コードの値に基づいて」大小比較した結果が得られます。

> に相当する、ブロック gt について考えます。gt を > と見なすと、
 gt value: $a value: $A
は、
 $a > $A
に相当します。つまり、文字 $a に対して、メッセージ > $A を送ることで、2つの文字を「ASCII コードの値に基づいて」大小比較した結果が得られます。

◆ 一般に、a < b と b > a とは、同じ結果が得られるものと期待されます。しかし、a と b とが違う種類のオブジェクトであると、その思惑が外れることがあります。その理由を説明する前に、大小比較ではなく、加算を表す演算 + について考察します。

3 + 4        "7"
3 + 4.0    "7.0"
3.0 + 4    "7.0"
3.0 + 4.0    "7.0"

60809b ◆ 数学の世界では、同じ + に対して、整数も実数も同じ演算がなされるものと期待されます。しかし、計算機の世界では、同じ + に対して、整数と実数とでは違う演算がなされることが期待されます。たとえば、実数を表すビットパターンに対して、整数を対象とする演算 + を適用しても無意味です。なぜなら、整数と実数とでは、その内部表現が異なるからです。再び、大小比較を表す演算について考察します。

【課題】何が問題となっているのか
3+4.0 を評価すると、7.0 となるのは何故でしょう。

60809c ◆ $A と $a とが、違う種類のオブジェクトと仮定します。すると、a < b と b > a とは、必ずしも同じ結果にならない可能性があることに気付きます。ここで、$A は「大文字と小文字とを区別せずに」大小比較する種類の文字とします。$a は「ASCII コードの値に基づいて」大小比較する種類の文字とします。すると、次のように`奇妙な`現象が起こり得ます。

$A < $a    "false"
$a > $A    "true"

◆ < および > によって、どのメソッドが有効かを決定するのは、メッセージの受信者であるオブジェクト自身です。メッセージそのものに決定権はありません。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年8月10日 (木)

連載: Smalltalk use: better《19》文字列と数列は何が違うの(1)★

キーワード ◆ ;・at:・Character・class・clear・cr・Interval・show:・size・SmallInteger・space・String・subscript is out of bounds・to:・Transcript・メソッド・メッセージ・数列・文字列

※ PDF でご覧になるなら ⇒ 公開日まで、お待ちください。

------------ 序 ------------

◆ さらに、学年が進むと、小数を覚え、分数を教わります。分数(有理数)を導入すると、それまで無意味とされた「どんな数でも割れる(ただし0を除く)」ことに新たな意義が生まれます。「正方形の対角線の長さは?」と尋ねると「1.41421356...」とか、「円周率は?」と尋ねると「3.1415926535897931...」とストップを掛けるまで、得意そうに語る生徒も中にはいます。しかし、小数点以下にどれだけ多くの数字を並べても、正確に表現するのは「無理」ということに気付きます。ちなみに、0.9≠1.0 ですが、これを無限に続けると 0.99999...=1.0と等号が成立します。そんな馬鹿なという人は、数学の教科書などで、理解を深めてください。ところで…(続く)

◆ 文字列と数列との間には、興味深い特徴があります。そこで、これらの共通点と相違点とに着目しながら、さらに学習を進めます。

------------ 本文 ------------

Transcript を使うと、式を評価した結果を文字列で確認できるので便利です。実行時のトレース情報を確認したいときなど、簡易ツールとして有用です。

Transcript show: 'hello'
------------------------------ Transcript --
hello

show: を使うと、引数に指定したオブジェクトに関する情報が表示されます。出力結果を見ると、hello を表示するのが分かります。

Transcript clear.
Transcript show: 'hello'; cr.
Transcript show: 'happy'; space.
Transcript show: 'birthday'
  # -------------------------------- Transcript --
hello
happy birthday

clear を使うと、Transcript に表示された情報がすべて消去されます。cr を使うと、そこで改行されます。space を使うと、そこに空白が挿入されます。出力結果を見ると、hello を表示した後で改行して、happy birthday を表示したのが分かります。

【Note】; を使うと、同じオブジェクトにメッセージを送り続けたいときに、簡略して表記できます。

文字列 ◆ 他のプログラミング言語と同様に、文字列は基本的な要素のひとつです。

s := 'ABCDE'.
Transcript show: s; cr.
Transcript show: s class; cr.
Transcript show: s size
-------------------------------- Transcript --
ABCDE
String
5

変数 s は、文字列を束縛します。class を使うと、そのオブジェクトが属するクラスが得られます。出力結果を見ると、文字列のクラスは String となるのが分かります。size を使うと、文字列の長さ(要素数)が得られます。出力結果を見ると、その長さは 5 となるのが分かります。

s := 'ABCDE'.
Transcript show: (s at: 1); space.
Transcript show: (s at: 5); cr.
Transcript show: (s at: 1) class
# -------------------------------- Transcript --
A E
Character

添字を使うと、文字列の各要素を参照できます。at: を使うと、引数に指定した位置にある要素が得られます。先頭の要素を参照するには、添字 1 を使います。末尾の要素を参照するには、その要素数に等しい、添字 5 を使います。出力結果を見ると、先頭の要素が $A で、末尾の要素が $E となるのが分かります。さらに、文字列を構成する各要素のクラスは Character となるのが分かります。

s := 'ABCDE'.
s at: 6    "subscript is out of bounds: 6"

◆ 文字列の範囲を越えて参照しようとすると、error: 'subscript is out of bounds' を生じます。

数列数列も基本的な要素のひとつです。これを文字列と比較しながら、解説します。

s := 1 to: 5.
Transcript show: s; cr.
Transcript show: s class; cr.
Transcript show: s size
  # -------------------------------- Transcript --
(1 to: 5)
Interval
5

変数 s は、数列を束縛します。class を使うと、そのオブジェクトが属するクラスが得られます。出力結果を見ると、数列のクラスは Interval となるのが分かります。size を使うと、数列の長さ(要素数)が得られます。出力結果を見ると、その長さは 5 となるのが分かります。

s := 1 to: 5.
Transcript show: (s at: 1); space.
Transcript show: (s at: 5); cr.
Transcript show: (s at: 1) class
-------------------------------- Transcript --
1 5
SmallInteger

添字を使うと、数列の各要素を参照できます。at: を使うと、引数に指定した位置にある要素が得られます。先頭の要素を参照するには、添字 1 を使います。末尾の要素を参照するには、その要素数に等しい、添字 5 を使います。出力結果を見ると、先頭の要素が 1 で、末尾の要素が 5 となるのが分かります。さらに、数列を構成する各要素のクラスは SmallInteger となるのが分かります。

s := 1 to: 5.
s at: 6    "subscript is out of bounds: 6"

◆ 数列の範囲を越えて参照しようとすると、エラー subscript is out of bounds を生じます。

60810ato: を使うと、指定した範囲内の数を要素とする等差数列が得られます。

.

60810b ◆ このとき、at: を伴うメッセージを解釈するのは、その受信者である文字列および数列です。同じメッセージに対して、文字列および数列は、それぞれ違う解釈が可能です。

.

,

,

60810c ◆ 一般に、ひとつのメッセージに対して、複数のメソッドが対応します。どのメソッドが有効かを決定するのは、メッセージの受信者であるオブジェクト自身です。メッセージそのものに決定権はありません。

.

.

.

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年8月11日 (金)

連載: Smalltalk use: better《20》文字列と数列は何が違うの(2)★

キーワード ◆ class・do:・from:to:do:・Interval・size・timesRepeat:・to:by:・to:by:do:・to:do:・コンパイラー・プログラマー・制御構造・反復・分岐

※ PDF でご覧になるなら ⇒ 公開日まで、お待ちください。

------------ 序 ------------

◆ 平方根や円周率のような無理数を導入すると、それまで無意味とされた「永遠に続く不規則な数」にも新たな意義が生まれます。√ で表現される数は安定することなく無限に続きますが、それを自乗すると安定した数になるという性質を持ちます。中学、高校へと進学する頃には、有理数と無理数との違いを知りますが、まだ実数の概念は登場しません。そして、自乗すると負になるという、それまでの常識が通用しない数の存在を認めざるを得ない状況に追い込まれます。このようにして、虚数の存在を認めることで、有理数と無理数とを統合する実数の概念や、その虚数までも統合する複素数の概念を生み出し、より広範な概念モデルへと発展してきました。(終)

◆ 過去の常識が通用しない新たな概念を突きつけられたときに、それをすぐに受け入れられるかは、個人差によるところが大きいのも事実です。これらのメタファーから、みなさんのオブジェクト指向の概念モデルが、どの段階で停滞しているかを自己確認する一助となれば幸いです。

------------ 本文 ------------

◆ Java/C# などの世界では、制御構造は、コンパイラーに組み込みの機能で、これを理解することが必須とされてきました。純粋なオブジェクト指向プログラミングの世界では、制御構造は、オブジェクトの種類ごとに、プログラマーが自分で規定できます。

◆ 条件分岐を表す、if などに相当する制御構造は、クラス Boolean に固有のメソッドとして記述できることを、すでに紹介しました。条件反復を表す、for などに相当する制御構造については、どのように記述すればいいのでしょうか。

5 timesRepeat: [
    Transcript show: $A]
-------------------------------- Transcript --
AAAAA

timesRepeat: を使うと、指定した回数だけ、ブロック式を評価します。出力結果を見ると、文字 $A を5回続けて表示するのが分かります。

s := 'ABC'.
s do: [:e |
    Transcript show: e; space]
-------------------------------- Transcript --
A B C

do: を使うと、各要素に対して、ブロック式を評価します。 ブロック引数 e は、文字列を構成する各文字を束縛します。出力結果を見ると、各文字を空白で区切りながら、順に表示するのが分かります。

s := 1 to: 3.
s do: [:e |
    Transcript show: e; space]
-------------------------------- Transcript --
1 2 3

do: を使うと、各要素に対して、ブロック式を評価します。 ブロック引数 e は、数列を構成する各整数を束縛します。出力結果を見ると、各整数を空白で区切りながら、順に表示するのが分かります。

s := 1 to: 5 by: 2.
Transcript show: s; cr.
Transcript show: s class; cr.
Transcript show: s size
-------------------------------- Transcript --
(1 to: 5 by: 2)
Interval
3

60811ato:by: を使うと、指定した範囲内の数を要素とする等差数列が得られます。

変数 s は、数列を束縛します。class を使うと、そのオブジェクトが属するクラスが得られます。出力結果を見ると、数列のクラスは Interval となるのが分かります。size を使うと、数列の長さ(要素数)が得られます。出力結果を見ると、その長さは 3 となるのが分かります。

s := 1 to: 5 by: 2.
s do: [:e |
    Transcript show: e; space]
-------------------------------- Transcript --
1 3 5

do: を使うと、各要素に対して、ブロック式を評価します。 ブロック引数 e は、数列を構成する各整数を束縛します。出力結果を見ると、各整数を空白で区切りながら、順に表示するのが分かります。

1 to: 3 do: [:e |
    Transcript show: e; space]
-------------------------------- Transcript --
1 2 3

60811bto:do: を使うと、指定した範囲の数に対して、ブロック式を評価します。ブロック引数 e は、数列を構成する各整数を束縛します。出力結果を見ると、各整数を空白で区切りながら、順に表示するのが分かります。

1 to: 5 by: 2 do: [:e |
    Transcript show: e; space]
-------------------------------- Transcript --
1 3 5

60811cto:by:do: を使うと、指定した範囲の数に対して、ブロック式を評価します。 ブロック引数 e は、数列を構成する各整数を束縛します。出力結果を見ると、各整数を空白で区切りながら、順に表示するのが分かります。

s := 'ABCDE'.
s from: 2 to: 4 do: [:e |
    Transcript show: e; space]
-------------------------------- Transcript --
B C D

60811dfrom:to:do: を使うと、指定した範囲内の各要素に対して、ブロック式を評価します。ブロック引数 e は、2 番目から 5 番目までの各文字を束縛します。出力結果を見ると、B から D までの文字を空白で区切りながら、順に表示するのが分かります。

【課題】何が起こっているのか
次の2つの式を評価すると、

1 to: 3 do: [:e |
    Transcript show: e; space]
(1 to: 3) do: [:e |
    Transcript show: e; space]
-------------------------------- Transcript --
1 2 3
1 2 3

どちらも同じ結果となるのが分かります。これらの本質的な違いは何ですか。また、これらの違いが問題となるのは、どのような場合でしょうか。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (1)

2006年8月14日 (月)

連載: Smalltalk use: better《21》文字列と数列は何が違うの(3)★★

キーワード ◆ asArray・collect:・inject:into:・size・subStrings:・数列・文字列

※ PDF でご覧になるなら ⇒ 公開日まで、お待ちください。

------------ 序 ------------

◆ 余談ですが《19》の枕を補足しておきます。
◆ 0.9≠1.0 というのは明らかです。次のように、
0.9999999999999999999999999999999≠1.0
小数点以下に 9 をいくつ並べても、等号は成立しません。しかし、これが有限ではなく、無限に 9 を続けると、等号が成立するという性質があります。これには、いくつかの証明方法があります。たとえば、
0.999999999... = 1.0 … (1)
の両辺を十倍すると、
9.999999999... = 10.0 … (2)
となります。ここで、(2)-(1) を求めると、
9.000000000... = 9.0
両辺が等しくなることで、証明できます。

◆ それでも、騙されたような気がする人は、(1) の両辺を 3 で割ると、
0.333333333... = 1.0/3
となることで、納得できるでしょうか。

◆ 何か新しいことを学ぼうとするときに、思い込みや、すでに確立された常識が、その理解を妨げるという事例には、枚挙に暇がありません。みなさんの場合は、いかがですか。

------------ 本文 ------------

s := '12345' asArray.
Transcript show: s
-------------------------------- Transcript --
#($1 $2 $3 $4 $5)

asArray を使うと、同じ構成要素を持つ配列が得られます。出力結果を見ると、文字列を構成する各文字を要素とする配列が得られるのが分かります。

s := (1 to: 5) asArray.
Transcript show: s
-------------------------------- Transcript --
#(1 2 3 4 5)

asArray を使うと、同じ構成要素を持つ配列が得られます。出力結果を見ると、数列を構成する各整数を要素とする配列が得られるのが分かります。

Transcript show: 'e: acc'; cr.
Transcript show: '-----------'; cr.
s := 1 to: 5.
r := s inject: '' into: [:acc :e |
    Transcript show: e asString, ': '.
    Transcript show: acc; cr.
    acc, e asString, ','].
Transcript show: '-----------'; cr.
Transcript show: r
-------------------------------- Transcript --
e: acc
-----------
1:
2: 1,
3: 1,2,
4: 1,2,3,
5: 1,2,3,4,
-----------
1,2,3,4,5,

inject:into: を使うと、各要素でブロック式を評価した結果を累積したものが得られます。ブロック引数 acc には、初期値として空文字列 '' を設定します。ブロック引数 e には、数列の各要素が順に割り当てられます。出力結果を見ると、acc の変化から、数列の各要素を ',' で接合した文字列が形成される様子が分かります。

s := '12345' asArray.
sum := s inject: 0 into: [:acc :e |
    acc + e asString].
Transcript show: sum
-------------------------------- Transcript --
15

◆ inject:into: を使って、数の総和を求めます。ブロック引数 acc には、初期値 0 を設定します。出力結果を見ると、1 から 5 までの総和が 15 となるのが分かります。+ を使うと、一方の文字列を数値と見なして、それを加算します。

s := 1 to: 5.
s := s collect: [:e | e asString].
Transcript show: s
-------------------------------- Transcript --
#('1' '2' '3' '4' '5')

collect: を使うと、各要素でブロック式を評価した結果を要素とする、新たなコレクションが得られます。出力結果を見ると、数列の各要素に相当する文字列を要素とする配列が得られます。asString を使うと、任意のオブジェクトを文字列に変換します。

s := 'AB,C,DEF' subStrings: ','.
Transcript show: s; cr.
s do: [:e |
    Transcript show: e; space]
-------------------------------- Transcript --
#('AB' 'C' 'DEF')
AB C DEF

subStrings: を使うと、引数に指定した文字列で分割した、部分文字列を要素とする配列が得られます。出力結果を見ると、',' の位置で分割した部分文字列が、配列の各要素となるのが分かります。そして、各要素を空白で区切りながら、順に表示するのが分かります。

size := [:Self |
    | tally |
    tally := 0.
    Self do: [:each | tally := tally + 1].
    tally].
s := 'ABC'.
r := size value: s.
Transcript show: r
-------------------------------- Transcript --
3

◆ 文字列に対して規定されたメソッド size に相当する、ブロック size について考えます。すると、
 size value: s
は、
 s size
に相当します。つまり、文字列 s にメッセージ size を送ると、文字列の長さ(要素数)が得られます。

60814a ◆ ブロック引数 Self は、実引数に指定された文字列を束縛します。ブロック変数 tally は、数え上げた要素数を保持します。これに、初期値 0 を設定します。ブロック引数 each は、文字列 Self を構成する各文字を束縛します。要素をたどるごとに、tally の値が1つずつ増加します。すると、tally が要素数と等しくなるので、これをリターンオブジェクトとします。出力結果を見ると、文字列 'ABC' の長さが 3 となるのが分かります。

size := [:Self |
    | start stop |
    start := Self first.
    stop := Self last.
    start < stop
        ifTrue: [stop - start + 1]
        ifFalse: [0]].
s := 1 to: 3.
r := size value: s.
Transcript show: r
-------------------------------- Transcript --
3

◆ 数列に対して規定されたメソッド size に相当する、ブロック size について考えます。すると、
 size value: s
は、
 s size
に相当します。つまり、数列 s にメッセージ size を送ると、数列の長さ(要素数)が得られます。

60814b ◆ ブロック引数 Self は、実引数に指定された数列を束縛します。ブロック変数 start に、先頭の値 Self first を設定します。ブロック変数 stop に、末尾の値 Self last を設定します。start < stop を満たすなら、要素数を計算して、これをリターンオブジェクトとします。start < stop を満たさないなら、0 をリターンオブジェクトとします。出力結果を見ると、数列 1 to: 3 の長さが 3 となるのが分かります。

◆ ここで注目したいのは、初期値と終了値を使って、要素を計算で求めていることです。つまり、実際には、size と同数の要素を保持してはいないのです。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年8月15日 (火)

連載: Smalltalk use: better《22》誰が制御するのかな★★

キーワード ◆ timesRepeat:・to:do:・ブロック式・カウンター・隠蔽・受信者・総和・送信者

※ PDF でご覧になるなら ⇒ 公開日まで、お待ちください。

------------ 序 ------------

◆ クリーンエネルギーとして着目されるもののひとつに、燃料電池があります。水の電気分解と対極にある(1)2H2 + 02 → 2H20 は、水素と酸素とが結合して水ができるという「酸化還元反応」と見なせます。(2)HCl + NaOH → NaCl + H20 は、酸化還元反応でしょうか。(3)H2 + Cl2 → 2HCl は、どうでしょう。まだ(2)などは、酸素原子が現れるので、腑に落ちない思いを残しつつも、これが(3)になると、酸素原子が現れないのに「酸化というのは納得がいかない」という人がいるかもしれません。狭義の「酸化」の定義では、酸素と化合(化学結合)するからこそ「酸化」なのですが、広義の「酸化」の定義ではその限りではありません。つまり、より広範な概念モデルへと拡張されたのです。

◆ Java/C# などで、条件分岐による制御構造を表す if 文さえも、純粋なオブジェクト指向の世界では`メッセージ`として表現できることを、すでに学びました。今回は、for 文に象徴されるような、反復を表す制御構造さえも`メッセージ`として表現できることを学びます。つまり、制御構造について、より広範な概念モデルへと拡張します。

------------ 本文 ------------

sum := 0.
e := 1.
5 timesRepeat: [
    sum := sum + e.
    e := e + 1].
Transcript show: sum
-------------------------------- Transcript --
15

60815atimesRepeat: を使って、総和を求めます。変数 sum は、総和を保持します。変数 e に、初期値 1 を与えます。指定された 5 回だけ、処理を繰り返します。5 に対してメッセージを送ると、ブロック式を`特定の`回数だけ評価します。処理を繰り返すたびに、変数 e の値が1つずつ増加します。

60815c ◆ timesRepeat: は、指定した回数だけ、ブロック式を評価します。このとき、処理を何回繰り返すかは、メッセージの受信者が決定します。一方、具体的な処理は、メッセージの送信者が提供します。受信者は、どのような処理が必要かは知りませんが、それを何回繰り返せばいいかを知っています。送信者は、どのような処理が必要かを知っていますが、それを何回繰り返せばいいかは知りません。これは、繰り返し処理をしたい内容と、何回繰り返すかという情報を、それぞれが役割分担をして管理することを意味します。

◆ 1 から 5 までの総和を求めるという処理を実現するには、総和を保持する変数 sum と、カウンターを管理する変数 e とが必要になります。

◆ 変数 sum に、初期値 0 を与え、これに変数 e の値を加えていきます。変数 e に、初期値 1 を与え、処理を繰り返すたびに、値が1つずつ増加します。これらの処理を何回繰り返すかは、受信者である 5 が決定します。すると、sum の値は (1,3,6,10,15) と変化して、e の値は (1,2,3,4,5) と変化します。そして、1 から 5 までの総和として、15 が求まります。

◆ ここで問題となるのは、2つの変数 sum と e とを用意して、これらを管理するという作業が必要になることです。何かうまい方法はないものでしょうか。◆

sum := 0.
1 to: 5 do: [:e |
    sum := sum + e].
Transcript show: sum
-------------------------------- Transcript --
15

60815bto:do: を使って、総和を求めます。変数 sum は、総和を保持します。ブロック引数 e に、1 から 5 までの整数を順に与え、処理を繰り返します。1 に対してメッセージを送ると、ブロック式を`特定の`回数だけ評価します。

60815d ◆ to:do: は、指定した範囲の数に対して、ブロック式を評価します。このとき、処理を何回繰り返すかは、メッセージの受信者と送信者とが協議して決定します。受信者は開始時の条件を、送信者は終了時の条件を提供します。送信者は、どのような処理が必要かを知っていますが、それを何回繰り返せばいいかは知りません。これは、繰り返し処理をしたい内容と、何回繰り返すかという情報を、それぞれが役割分担をして管理することを意味します。

◆ 1 から 5 までの総和を求めるという処理を実現するには、総和を保持する変数 sum だけが必要になります。カウンターを管理する変数は必要ありません。

◆ 変数 sum に、初期値 0 を与え、これにブロック引数 e の値を加えていきます。処理を繰り返すたびに、e には、1 から 5 までの値が順に与えられます。すると、sum の値は (1,3,6,10,15) と変化して、e の値は (1,2,3,4,5) と変化します。そして、1 から 5 までの総和として、15 が求まります。

◆ こうして、問題解決に不要な変数 e を排除することに成功しました。Smap を見ると、外部の変数 e が、内部のブロック引数 e となり、不必要な情報が内部に隠蔽されたのが分かります。

◆ まだ問題となるのは、変数 sum を用意して、これを管理するという作業が必要になることです。何かうまい方法はないものでしょうか。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年8月16日 (水)

連載: Smalltalk use: better《23》何を制御するのかな★

キーワード ◆ do:・inject:into:・カプセル化・隠蔽・属性値

※ PDF でご覧になるなら ⇒ 公開日まで、お待ちください。

------------ 序 ------------

◆ 以前に紹介した、因数分解のメタファーを使って、新たな展開を示します。たとえば、次の有理式を因数分解してください。
 a2+b2
この問題を実数の範囲で解決しようとすると、これ以上の因数分解はできないという結論になります。
 a2+b2 = (a+bi)(a-bi)
しかし、これを虚数の範囲までモデルの適用範囲を拡げると、その問題解決の可能性が広がります。◆

------------ 本文 ------------

s := 1 to: 5.
sum := 0.
s do: [:e |
    sum := sum + e].
Transcript show: sum
------------------------------ Transcript --
15

60816a ◆ do: を使って、総和を求めます。変数 s には、総和を求めたい数列を与えます。変数 sum は、総和を保持します。ブロック引数 e に、数列の各要素(1 から 5 までの整数)を順に与えます。数列に対してメッセージを送ると、ブロック式を`必要な`回数だけ評価します。

60816cdo: は、各要素に対して、ブロック式を評価します。メッセージの受信者は処理すべき対象を提供します。メッセージの送信者は、どのような処理が必要かを知っていますが、何を処理すればいいのかを知りません。これは、何を処理したいか(what)と、どのように処理したいか(how)という情報を、それぞれが役割分担をして管理することを意味します。

◆ 1 から 5 までの総和を求めるという処理を実現するには、総和を保持する変数 sum だけが必要になります。変数 s は、処理の対象を束縛しますが、変数そのものは必須ではありません。この変数は`便宜的に`導入したもので、それがなくても支障はありません。

◆ 変数 sum に、初期値 0 を与え、これにブロック引数 e の値を加えていきます。処理を繰り返すたびに、e には、1 から 5 までの値が順に与えられます。すると、sum の値は (1,3,6,10,15) と変化して、e の値は (1,2,3,4,5) と変化します。そして、1 から 5 までの総和として、15 が求まります。

◆ こうして、問題解決に必要な実引数 5 を統合することに成功しました。Smap を見ると、外部の実引数 5 が、内部の属性値 5 となり、必要な情報がオブジェクト内部にカプセル化されたのが分かります。

◆ ここで問題となるのは、変数 sum を用意して、これを管理するという作業が必要になることです。何かうまい方法はないものでしょうか。

s := 1 to: 5.
sum := s inject: 0 into: [:acc :e |
    acc + e].
Transcript show: sum
------------------------------ Transcript --
15

60816b ◆ inject:into: を使って、総和を求めます。変数 s には、総和を求めたい数列を与えます。変数 sum は、総和を保持します。ブロック引数 acc は、ブロック式を評価した結果を保持します。ブロック引数 e に、数列の各要素(1 から 5 までの整数)を順に与えます。数列に対してメッセージを送ると、ブロック式を`必要な`回数だけ評価します。

60816dinject:into: は、各要素に対して、ブロック式を評価します。メッセージの受信者は処理すべき対象と初期値を提供します。メッセージの送信者は、どのような処理が必要かを知っていますが、何を処理すればいいのかを知りません。これは、何を処理したいか(what)と、どのように処理したいか(how)という情報を、それぞれが役割分担をして管理することを意味します。

◆ 1 から 5 までの総和を求めるという処理を実現するのに、変数は必要ありません。変数 s は、処理の対象を束縛しますが、変数そのものは必須ではありません。同様に、変数 sum は、総和を保持しますが、これも必須ではありません。これらの変数は`便宜的に`導入したもので、それがなくても支障はありません。

◆ ブロック引数 acc に、初期値 0 を与え、これにブロック引数 e の値を加えていきます。処理を繰り返すたびに、e には、1 から 5 までの値が順に与えられます。すると、sum の値は (1,3,6,10,15) と変化して、e の値は (1,2,3,4,5) と変化します。そして、1 から 5 までの総和として、15 が求まります。最後に、変数 sum は、この総和を束縛します。

◆ こうして、問題解決に不要な変数を排除することに成功しました。Smap を見ると、外部の変数 sum および e が、内部のブロック引数 acc および e となり、不必要な情報が内部に隠蔽されたのが分かります。総和を求めるには、acc + e という本質的な処理だけを記述すればいいことになります。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年8月17日 (木)

連載: Smalltalk use: better《24》何処までが同じで何処からが違うの★★

キーワード ◆ do:・inject:into:・カプセル化・隠蔽・属性値

※ PDF でご覧になるなら ⇒ 公開日まで、お待ちください。

------------ 序 ------------

------------ 本文 ------------

timesRepeat := [:Self :aBlock |
    | count |
    count := 1.
    [count <= Self]
        whileTrue:
            [aBlock value.
            count := count + 1]].
timesRepeat value: 3 value: [
    Transcript show: $A]
------------------------------ Transcript --
AAA

◆ クラス Integer で規定されたメソッド timesRepeat: に相当する、ブロック timesRepeat について考えます。すると、
 timesRepeat value: 3 value: [...]
は、
 3 timesRepeat: [...]
に相当します。つまり、指定した回数だけ、ブロック式を評価します。出力結果を見ると、文字 $A を3回続けて表示するのが分かります。

60817a ◆ ブロック変数 count は、ブロック式 aBlock を評価した回数を管理するもので、初期値 1 を設定します。count の値が、ブロック引数 Self の値以下なら、aBlock を評価 value するとともに、count の値を1つ増加させます。すると、指定した Self の回数だけ、aBlock を評価します。

todo := [:Self :stop :aBlock |
    | aValue |
    aValue := Self.
    [aValue <= stop]
        whileTrue:
            [aBlock value: aValue.
            aValue := aValue + 1]].
todo value: 1 value: 3 value: [:e |
    Transcript show: e; space]
------------------------------ Transcript --
1 2 3

◆ クラス Number で規定されたメソッド to:do: に相当する、ブロック todo について考えます。すると、
 todo value: 1 value: 3 value: [:e | ...]
は、
 1 to: 3 do: [:e | ...]
に相当します。つまり、指定した範囲の数に対して、ブロック式を評価します。出力結果を見ると、各整数を空白で区切りながら、順に表示するのが分かります。

60817b ◆ ブロック変数 aValue は、ブロック式 aBlock を評価するときの値を管理するもので、初期値にブロック引数 Self を設定します。aValue の値が、ブロック引数 stop の値以下なら、aBlock を評価 value: aValue するとともに、aValue の値を1つ増加させます。すると、Self から stop までの各値に対して、aBlock を評価します。

do := [:Self :aBlock |
    | start stop aValue |
    start := Self first.
    stop := Self last.
    aValue := start.
    [aValue <= stop]
        whileTrue:
            [aBlock value: aValue.
            aValue := aValue + 1]].
s := 1 to: 3.
do value: s value: [:e |
    Transcript show: e; space]
------------------------------ Transcript --
1 2 3

◆ クラス Interval で規定されたメソッド do: に相当する、ブロック do について考えます。すると、
 do value: s value: [:e | ...]
は、
 s do: [:e | ...]
に相当します。つまり、各要素に対して、ブロック式を評価します。出力結果を見ると、各整数を空白で区切りながら、順に表示するのが分かります。

60817c ◆ ブロック引数 Self は、対象となる数列を束縛します。ブロック変数 start に、数列の初期値を設定します。ブロック変数 stop に、数列の終了値を設定します。ブロック変数 aValue は、ブロック式 aBlock を評価するときの値を管理するもので、初期値 start を設定します。aValue の値が、stop の値以下なら、aBlock を評価 value: aValue するとともに、aValue の値を1つ増加させます。すると、start から stop までの各値に対して、aBlock を評価します。

◆ これらに共通するのは、timesRepeat: におけるブロック変数 count、to:do: および do: におけるブロック変数 aValue など、カウンター変数を、メソッドの利用者が用意する必要がないことです。すると、カプセル化によって情報隠蔽を実現できます。利用者は、些末なカウンターの処理から解放され、本質的な処理だけをブロック内に記述して、後はメソッドに委ねればいいのです。

◆ timesRepeat: に伴うブロック式では不要ですが、to:do: および do: に伴うブロック式では、ブロック引数が必要になります。この引数は、ブロック変数 aValue によって、メソッド内で管理されます。

60817d ◆ これらのメソッドは、変数などの違いを除くと、本質的には同じです。そのため、もっとも汎用性のある do: から、他のメソッドを導出できます。そこには、初期値および終了値を決定するのが、メッセージの受信者か、送信者かの違いがあるだけです。

=================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年8月18日 (金)

連載: Smalltalk use: better《25》これは要るけどこのほうがいいかな★★

キーワード ◆ collect:・do:・select:

※ PDF でご覧になるなら ⇒ 公開日まで、お待ちください。

------------ 序 ------------

------------ 本文 ------------

s := 'ABCDE' asOrderedCollection.
Transcript show: s; cr.
s := s collect: [:e | e asciiValue].
Transcript show: s
------------------------------ Transcript --
an OrderedCollection($A $B $C $D $E)
an OrderedCollection(65 66 67 68 69)

60818acollect: を使うと、各要素でブロック式を評価した結果を要素とする、新たなコレクションが得られます。出力結果を見ると、文字列を構成する各文字の ASCII コードの値を要素とする、新たなコレクションが得られるのが分かります。

collect := [:Self :aBlock |
    | newCollection |
    newCollection := Self species new.
    Self do: [:each | newCollection
        add: (aBlock value: each)].
    newCollection].
s := 'ABCDE' asOrderedCollection.
s := collect value: s value: [:e | e asciiValue].
Transcript show: s
------------------------------ Transcript --
an OrderedCollection(65 66 67 68 69)

60818c ◆ クラス Collection で規定されたメソッド collect: に相当する、ブロック collect について考えます。すると、
 collect value: s value: [:e | ...]
は、
 s collect: [:e | ...]
に相当して、出力結果も同じになるのが分かります。

◆ ブロック変数 newCollection には、得られた結果を保持するコレクションを設定します。species を使って、生成するコレクションの種類を決定します。ブロック引数 Self が保持する各要素 each で、ブロック式 aBlock を評価します。そこで得られた要素を、newCollection に追加します。すべての要素を処理すると、最後に newCollection をリターンオブジェクトとします。

◆ ここで注目したいのは、実引数 Self が保持する各要素を参照する方法が、do: によって決定されることです。これは、collect: を実現する方法が、do: に依存するものの、特定の種類のオブジェクトには依存しないことを意味します。

s := 'ABCDE' asOrderedCollection.
Transcript show: s; cr.
s := s select: [:e | e isVowel].
Transcript show: s
------------------------------ Transcript --
an OrderedCollection($A $B $C $D $E)
an OrderedCollection($A $E)

60818bselect: を使うと、各要素でブロック式を評価して true となるものだけを要素とする、新たなコレクションが得られます。出力結果を見ると、文字列を構成する各文字が母音であるものだけを要素とする、新たなコレクションが得られるのが分かります。◆

select := [:Self :aBlock |
    | newCollection |
    newCollection := Self species new.
    Self do: [:each | (aBlock value: each)
        ifTrue: [newCollection add: each]].
    newCollection].
s := 'ABCDE' asOrderedCollection.
s := select value: s value: [:e | e isVowel].
Transcript show: s
------------------------------ Transcript --
an OrderedCollection($A $E)

60818d ◆ クラス Collection で規定されたメソッド select: に相当する、ブロック select について考えます。すると、
 select value: s value: [:e | ...]
は、
 s select: [:e | ...]
に相当して、出力結果も同じになるのが分かります。

◆ ブロック変数 newCollection には、得られた結果を保持するコレクションを設定します。species を使って、生成するコレクションの種類を決定します。ブロック引数 Self が保持する各要素 each で、ブロック式 aBlock を評価します。そこで true と評価された要素だけを、newCollection に追加します。すべての要素を処理すると、最後に newCollection をリターンオブジェクトとします。

◆ ここで注目したいのは、実引数 Self が保持する各要素を参照する方法が、do: によって決定されることです。これは、select: を実現する方法が、do: に依存するものの、特定の種類のオブジェクトには依存しないことを意味します。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年8月21日 (月)

連載: Smalltalk use: better《26》これは要るけどこれは要らないかな★★

キーワード ◆ do:・inject:into:・reject:・select:

※ PDF でご覧になるなら ⇒ 公開日まで、お待ちください。

------------ 序 ------------

------------ 本文 ------------

s := 'ABCDE' asOrderedCollection.
Transcript show: s; cr.
s := s reject: [:e | e isVowel].
Transcript show: s
------------------------------ Transcript --
an OrderedCollection($A $B $C $D $E)
an OrderedCollection($B $C $D)

60821areject: を使うと、各要素でブロック式を評価して false となるものだけを要素とする、新たなコレクションが得られます。出力結果を見ると、文字列を構成する各文字が母音でないものだけを要素とする、新たなコレクションが得られるのが分かります。

reject := [:Self :aBlock |
    Self select: [:each |
        (aBlock value: each) == false]].
s := 'ABCDE' asOrderedCollection.
s := reject value: s value: [:e | e isVowel].
Transcript show: s
------------------------------ Transcript --
an OrderedCollection($B $C $D)

60821c ◆ クラス Collection で規定されたメソッド reject: に相当する、ブロック reject について考えます。すると、
 reject value: s value: [:e | ...]
は、
 s reject: [:e | ...]
に相当して、出力結果も同じになるのが分かります。◆

◆ ブロック引数 Self が保持する各要素 each で、ブロック式 aBlock を評価します。false と評価された要素だけを選択します。すべての要素について、メソッド select: に続くブロック式を評価した結果を、リターンオブジェクトとします。

◆ ここで注目したいのは、メソッド select: を再利用していることです。これは、reject: を実現する方法が、select: を介して、do: に依存するものの、特定の種類のオブジェクトには依存しないことを意味します。◆

s := 'ABCDE'.
Transcript show: s; cr.
s := s
    inject: ''
    into: [:acc :e | e asString , acc].
Transcript show: s
------------------------------ Transcript --
ABCDE
EDCBA

60821binject:into: を使うと、各要素でブロック式を評価した結果を累積したものが得られます。出力結果を見ると、文字列を構成する各文字を逆順に並べた、新たな文字列が得られたのが分かります。

inject := [:Self :this :aBlock |
    | next |
    next := this.
    Self do: [:each |
        next := aBlock value: next value: each].
    next].
s := 'ABCDE'.
s := inject value: s value: ''
    value: [:acc :e | e asString , acc].
Transcript show: s
------------------------------ Transcript --
EDCBA

60821d ◆ クラス Collection で規定されたメソッド inject:into: に相当する、ブロック inject について考えます。すると、
 inject value: s value: '' value: [:acc :e | ...]
は、
 s inject: '' into: [:acc :e | ...]
に相当して、出力結果も同じになるのが分かります。

◆ ブロック変数 next は、ブロック式を評価した結果を累積したものを保持します。next に、ブロック引数 this が束縛するオブジェクトを初期設定します。next とともに、ブロック引数 Self が保持する各要素 each で、ブロック式 aBlock を評価します。各要素をたどるごとに、next は、そこで得られたオブジェクトを束縛します。すべての要素について、メソッド do: に続くブロック式を評価した後で、next をリターンオブジェクトとします。

◆ ここで注目したいのは、実引数 Self が保持する各要素を参照する方法が、do: によって決定されることです。これは、inject:into: を実現する方法が、do: に依存するものの、特定の種類のオブジェクトには依存しないことを意味します。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年8月22日 (火)

連載: Smalltalk use: better《27》ここだけの話どこにでもある話★★

キーワード ◆ Array・at:・collect:・do:・inject:into:・Interval・OrderedCollection・reject:・select:・String・インスタンス変数・順序列・数列・配列・文字列

※ PDF でご覧になるなら ⇒ 公開日まで、お待ちください。

------------ 序 ------------

------------ 本文 ------------

60822b.

.

.

.

.

 

60822a ◆ ここで注目したいのは、メソッド do: を除く、他の4つの処理に関する記述が、特定の種類のコレクションに依存しないことです。これは、任意の種類のコレクションに対しても、これらの記述を再利用できることを意味します。すると、任意の種類に対して do: を規定するだけで、他の処理を再定義する必要がなくなります。つまり、メソッドを記述する手間を、1/5 に軽減できる可能性を秘めています。

◆ メソッド do: の記述から、同種のオブジェクト群に共通する構造が見えてきます。つまり、特定の種類のコレクションを構成する各要素を処理するときの、典型的な事例を学べます。◆

"String"
do := [:Self :aBlock |
    1 to: Self size do:
        [:index |
        aBlock value: (Self at: index)]].
s := 'ABC'.
Transcript show: s; cr.
do value: s value: [:e |
    Transcript show: e; space]
------------------------------ Transcript --
ABC
A B C

◆ クラス String で規定されたメソッド do: に相当する、ブロック do について考えます。すると、
 do value: s value: [:e | ...]
は、
 s do: [:e | ...]
に相当します。出力結果を見ると、各文字を空白で区切りながら、順に表示するのが分かります。

文字列を構成する各要素(文字)について、ブロック式を評価します。各要素を得るには、at: を使います。index の値は、1 から文字列の長さ(要素数)まで変化します。こうして、各文字について、ブロック式を評価します。

"Interval"
do := [:Self :aBlock |
    | start stop aValue |
    start := Self first.
    stop := Self last.
    aValue := start.
    [aValue <= stop]
        whileTrue:
            [aBlock value: aValue.
            aValue := aValue + 1]].
s := 1 to: 3.
Transcript show: s; cr.
do value: s value: [:e |
    Transcript show: e; space]
------------------------------ Transcript --
(1 to: 3)
1 2 3

◆ クラス Interval で規定されたメソッド do: に相当する、ブロック do について考えます。すると、
 do value: s value: [:e | ...]
は、
 s do: [:e | ...]
に相当します。各整数を空白で区切りながら、順に表示するのが分かります。

数列を構成する各要素(整数)について、ブロック式を評価します。各要素を得るには、aValue を使います。start は先頭の要素を、stop は末尾の要素を、それぞれ保持します。aValue に、start の値を初期設定します。aValue の値が stop の値以下なら、要素をたどるごとに、aValue の値が1つずつ増加します。すると、aValue の値は、start から stop まで変化します。こうして、各整数について、ブロック式を評価します。各要素を保持するのではなく、計算によって得ているのが分かります。

start および stop は、インスタンス変数を意識したものです。この他に、差分を表す step が存在します。

"OrderedCollection"
do := [:Self :aBlock |
    | array firstIndex lastIndex index |
    array := Self collector.
    firstIndex := 1.
    lastIndex := array size.
    index := firstIndex.
    [index <= lastIndex]
        whileTrue:
            [aBlock value: (array at: index).
            index := index + 1]].
s := 'ABC' asOrderedCollection.
Transcript show: s; cr.
do value: s value: [:e |
    Transcript show: e; space]
------------------------------ Transcript --
an OrderedCollection($A $B $C)
A B C

◆ クラス OrderedCollection で規定されたメソッド do: に相当する、ブロック do について考えます。すると、
 do value: s value: [:e | ...]
は、
 s do: [:e | ...]
に相当します。各文字を空白で区切りながら、順に表示するのが分かります。

順序列を構成する各要素(任意)について、ブロック式を評価します。各要素を得るには、at: を使います。array は、各要素を保持する配列を束縛します。firstIndex は先頭の位置を、lastIndex は末尾の位置を、それぞれ保持します。index に、firstIndex の値を初期設定します。index の値が lastIndex の値以下なら、要素をたどるごとに、index の値が1つずつ増加します。すると、index の値は、firstIndex から lastIndex まで変化します。こうして、各要素について、ブロック式を評価します。

array、firstIndex、および lastIndex は、インスタンス変数を意識したものです。

60822c .

.

.

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年8月23日 (水)

連載: Smalltalk use: better《28》世界にひとつだけのはてな★★

キーワード ◆ add:・addAll:・do:・Set・union:・yourself・リターンオブジェクト・集合

※ PDF でご覧になるなら ⇒ 公開日まで、お待ちください。

------------ 序 ------------

------------ 本文 ------------

60823a ◆ クラス Set は、要素が重複しないコレクションを管理します。これは、集合の概念を連想させます。

.

s := Set new.
Transcript show: s; cr.
s add: $A.
Transcript show: s; cr.
s add: $A.
Transcript show: s; cr.
s add: $B.
Transcript show: s; cr
------------------------------ Transcript --
a Set()
a Set($A)
a Set($A)
a Set($B $A)

◆ 変数 s は、生成した Set のインスタンスを束縛します。出力結果を見ると、要素を持たない空集合を生成するのが分かります。add: を使うと、任意の要素を追加できます。出力結果を見ると、1つの文字 $A を要素に持つのが分かります。続けて、同じ文字 $A を追加しようとします。しかし、要素の重複は認められないので、文字 $A を追加できません。続けて、違う文字 $B を追加しようとします。すると、要素は重複しないので、文字 $B を追加します。出力結果を見ると、2つの文字を要素に持つのが分かります。

◆ ここで注目したいのは、要素を追加した順序が保持されないことです。出力結果を見ると、各要素が、追加した順序と関係なく並ぶのが分かります。これは、添字を使って要素を参照できないことを意味します。

s := Set new.
s addAll: 'ABBCCC'.
Transcript show: s; cr
------------------------------ Transcript --
a Set($B $C $A)

addAll: を使うと、複数の要素を一度に追加できます。出力結果を見ると、3つの文字を要素に持つのが分かります。このとき、要素は重複することなく、構成する文字の順序と関係なく並ぶのが分かります。

addAll := [:Self :aCollection |
    aCollection do: [:each |
        Self add: each].
    aCollection].
s := Set new.
Transcript show: s; cr.
addAll value: s value: 'ABC'.
Transcript show: s; cr
------------------------------ Transcript --
a Set()
a Set($B $C $A)

◆ クラス Collection で規定されたメソッド addAll: に相当する、ブロック addAll について考えます。すると、
 addAll value: s value: 'ABC'.
は、
 s addAll: 'ABC'.
に相当して、出力結果も同じになるのが分かります。

◆ ブロック引数 aCollection は、追加したい要素群を束縛します。aCollection が保持する各要素 each を、ブロック引数 Self が束縛する対象に追加します。すべての要素を処理すると、最後に aCollection をリターンオブジェクトとします。

60823b ◆ ここで注目したいのは、各要素を追加するときに、add: を利用していることです。これは、addAll: によって得られる結果が、add: に依存することを意味します。

tally および array は、インスタンス変数を意識したものです。

s := Set new.
s addAll: 'ABC'.
Transcript show: s; cr.
s do: [:e |
    Transcript show: e; space]
------------------------------ Transcript --
a Set($B $C $A)
B C A

do := [:Self :aBlock |
    | tally array |
    tally := Self size.
    array := Self array.
    1 to: array size do:
        [:index |
        | each |
        (each := array at: index)
            ifNotNil: [aBlock value: each]]].
s := 'ABC' asSet.
Transcript show: s; cr.
do value: s value: [:e |
    Transcript show: e; space]
------------------------------ Transcript --
a Set($A $B $C)
A B C

◆ クラス Set で規定されたメソッド do: に相当する、ブロック do について考えます。すると、
 do value: s value: [:e | ...]
は、
 s do: [:e | ...]
に相当して、出力結果も同じになるのが分かります。

集合を構成する各要素(任意)について、ブロック式を評価します。各要素 each を得るには、at: を使います。tally は、要素数を保持します。array は、各要素を保持する配列を束縛します。index の値は、1 から集合の要素数まで変化します。各要素 each が nil でないなら、それでブロック式を評価します。

【課題】何をリターンするのか
do: のリターンオブジェクトは、何でしょう。

s1 := 'AB' asSet.
s2 := 'BC' asSet.
s := s1 union: s2.
Transcript show: s1; cr.
Transcript show: s2; cr.
Transcript show: s
------------------------------ Transcript --
a Set($A $B)
a Set($B $C)
a Set($A $B $C)

union: を使うと、2つの集合の積集合(共通集合)が得られます。出力結果を見ると、2つの集合 s1 および s2 に共通する要素 $B を、1つだけ含むのが分かります。

union := [:Self :aCollection |
    Self copy addAll: aCollection; yourself].
s1 := 'AB' asSet.
s2 := 'BC' asSet.
s := union value: s1 value: s2.
Transcript show: s
------------------------------ Transcript --
a Set($A $B $C)

◆ クラス Set で規定されたメソッド union: に相当する、ブロック union について考えます。すると、
 union value: s1 value: s2
は、
 s1 union: s2
に相当して、出力結果も同じになるのが分かります。

◆ Self および aCollection は、積集合の対象となる各集合を束縛します。一方の集合 Self の複製を生成した後で、addAll: を使って、これに他方の集合 aCollection の各要素を追加します。yourself を記述しないと、リターンオブジェクトは、求める積集合ではなく、aCollection となるので、注意が必要です。

【課題】何が受け取るのか
メッセージ yourself の受け手は、何でしょう。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年8月24日 (木)

連載: Smalltalk use: better《29》並んで並んで赤白黄色きれいでしょ★★

キーワード ◆ add:・addAll:・addAllLast:・addFirst:・addLast:・OrderedCollection・順序列・両頭待ち行列

※ PDF でご覧になるなら ⇒ 公開日まで、お待ちください。

------------ 序 ------------

------------ 本文 ------------

60824a ◆ クラス OrderedCollection は、要素の順序に意味のあるコレクションを管理します。これは、両頭待ち行列の概念を連想させます。
.

s := OrderedCollection new.
Transcript show: s; cr.
s addAll: 'ABC'.
Transcript show: s; cr.
s add: $D.
Transcript show: s; cr.
s addLast: $E.
Transcript show: s; cr.
s addFirst: $F.
Transcript show: s
------------------------------ Transcript --
an OrderedCollection()
an OrderedCollection($A $B $C)
an OrderedCollection($A $B $C $D)
an OrderedCollection($A $B $C $D $E)
an OrderedCollection($F $A $B $C $D $E)

◆ 変数 s は、生成した OrderedCollection のインスタンスを束縛します。出力結果を見ると、要素を持たない順序列を生成するのが分かります。addAll: を使うと、複数の要素を一度に追加できます。出力結果を見ると、3つの文字を要素に持つのが分かります。このとき、要素は、追加した順序と同じに並ぶのが分かります。add: を使うと、任意の要素を追加できます。出力結果を見ると、文字 $D を順序列の末尾に追加するのが分かります。addLast: を使うと、任意の要素を末尾に追加できます。出力結果を見ると、文字 $E を順序列の末尾に追加するのが分かります。addFirst: を使うと、任意の要素を先頭に追加できます。出力結果を見ると、文字 $F を順序列の先頭に追加するのが分かります。

add := [:Self :newObject |
    Self addLast: newObject].
addAllLast := [:Self :anOrderedCollection |
    anOrderedCollection do: [:each |
        Self addLast: each].
    anOrderedCollection].
addAll := [:Self :aCollection |
    addAllLast value: Self value: aCollection].
s := OrderedCollection new.
Transcript show: s; cr.
addAll value: s value: 'ABC'.
Transcript show: s; cr.
add value: s value: $D.
Transcript show: s
------------------------------ Transcript --
an OrderedCollection()
an OrderedCollection($A $B $C)
an OrderedCollection($A $B $C $D)

◆ クラス Collection で規定されたメソッド addAll: および add: にそれぞれ相当する、ブロック addAll および add について考えます。すると、
 addAll value: s value: 'ABC'
 add value: s value: $D
は、それぞれ
 s addAll: 'ABC'
 s add: $D
に相当して、出力結果も同じになるのが分かります。

60824b ◆ ここで注目したいのは、addAll: を実現するときに addAllLast: を、addAllLast: を実現するときに addLast: を利用していることです。また、add: を実現するときに、addLast: を利用しています。これは、これらのメソッドによって得られる結果がすべて、addLast: に依存することを意味します。

makeRoomAtLast := [:array |
    | newArray |
    newArray := array species
        new: array size + 1.
    newArray
        replaceFrom: 1
        to: array size
        with: array
        startingAt: 1.
    array := newArray].
addLast := [:Self :newObject |
    | array lastIndex |
    array := Self collector.
    lastIndex := Self size.
    makeRoomAtLast value: array.
    array at: lastIndex + 1 put: newObject.
    Self setContents: array.
    newObject].
s := 'ABC' asOrderedCollection.
Transcript show: s; cr.
r := addLast value: s value: $E.
Transcript show: s; cr.
Transcript show: r
------------------------------ Transcript --
an OrderedCollection($A $B $C)
an OrderedCollection($A $B $C $E)
E

◆ クラス Set で規定されたメソッド addLast: に相当する、ブロック addLast について考えます。すると、
 addLast value: s value: $E
は、
 s addLast: $E
に相当します。出力結果を見ると、要素 $E を末尾に追加するのが分かります。

makeRoomAtFirst := [:array |
    | newArray |
    newArray := array species
        new: array size + 1.
    newArray
        replaceFrom: 2
        to: array size + 1
        with: array
        startingAt: 1.
    array := newArray].
addFirst := [:Self :newObject |
    | array firstIndex |
    array := Self collector.
    firstIndex := 1.
    makeRoomAtFirst value: array.
    array at: firstIndex put: newObject.
    Self setContents: array.
    newObject].
s := 'ABC' asOrderedCollection.
Transcript show: s; cr.
r := addFirst value: s value: $F.
Transcript show: s; cr.
Transcript show: r
------------------------------ Transcript --
an OrderedCollection($A $B $C)
an OrderedCollection($F $A $B $C)
F

◆ クラス Set で規定されたメソッド addFirst: に相当する、ブロック addFirst について考えます。すると、
 addFirst value: s value: $F
は、
 s addFirst: $F
に相当します。出力結果を見ると、要素 $F を先頭に追加するのが分かります。

◆ ブロック addLast および addFirst に共通する、array は、各要素を保持する配列を束縛します。lastIndex は、末尾の要素の位置を保持します。firstIndex は、先頭の要素の位置を保持します。

array、firstIndex、および lastIndex は、インスタンス変数を意識したものです。

◆ ブロック makeRoomAtLast では、array が束縛する配列の末尾に、要素を追加する場所を確保します。ブロック makeRoomAtFirst では、array が束縛する配列の先頭に、要素を追加する場所を確保します。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年8月25日 (金)

連載: Smalltalk use: better《30》私の辞書には不可能の文字もあるの★★

キーワード ◆ Association・associationsDo:・at:・at:ifAbsent:・at:put:・collect:・Dictionary・do:・keysAndValuesDo:・keysDo:・select:・キー・辞書・写像・値

※ PDF でご覧になるなら ⇒ 公開日まで、お待ちください。

------------ 序 ------------

------------ 本文 ------------

60825a ◆ クラス Dictionary は、任意のキーと値との対からなるコレクションを管理します。これは、写像の概念を連想させます。

s := Dictionary new.
Transcript show: s; cr.
s at: #B put: 2.
Transcript show: s; cr.
s at: #A put: 1.
Transcript show: s; cr.
s at: #C put: 3.
Transcript show: s
------------------------------ Transcript --
a Dictionary()
a Dictionary(#B->2 )
a Dictionary(#A->1 #B->2 )
a Dictionary(#A->1 #B->2 #C->3 )

◆ 変数 s は、生成した Dictionary のインスタンスを束縛します。出力結果を見ると、要素を持たない辞書を生成するのが分かります。at:put: を使うと、キーと値との写像対を要素として追加できます。出力結果を見ると、3つの写像対を要素に持つのが分かります。このとき、各要素が、追加した順序と関係なく並ぶのが分かります。

...
r := s at: #A.
Transcript show: r; cr.
r := s at: #X.
Transcript show: r; cr.
r := s at: #X ifAbsent: [0].
Transcript show: r
------------------------------ Transcript --
1
error: 'key not found'
0

at: を使うと、キーに対応する値が得られます。出力結果を見ると、シンボル #A をキーとする値が 1 となるのが分かります。at:ifAbsent: を使うと、キーが見つからないときに得られる値を指定できます。出力結果を見ると、シンボル #X をキーとする値が見つからないので、0 が得られるのが分かります。

...
s do: [:e | Transcript show: e; space].
Transcript cr.
s keysDo: [:e | Transcript show: e; space].
Transcript cr.
s keysAndValuesDo: [:key :value |
    Transcript show: key,': ',value asString; cr].
------------------------------ Transcript --
3 2 1
C B A
C: 3
B: 2
A: 1

do: を使うと、辞書に登録された値で、ブロック式を評価します。keysDo: を使うと、辞書に登録されたキーで、ブロック式を評価します。keysAndValuesDo: を使うと、辞書に登録されたキーと値で、ブロック式を評価します。

...
r := s collect: [:e | e * 10].
Transcript show: r; cr.
r := s select: [:e | e odd].
Transcript show: r
------------------------------ Transcript --
an OrderedCollection(30 20 10)
a Dictionary(#A->1 #C->3 )

collect: を使うと、辞書に登録された値で、ブロック式を評価した結果を要素とする、新たなコレクションが得られます。select: を使うと、辞書に登録された値で、ブロック式を評価して true となるものだけを要素とする、新たなコレクションが得られます。

collect := [:Self :aBlock |
    | newCollection |
    newCollection := OrderedCollection
        new: Self size.
    Self do: [:each | newCollection
        add: (aBlock value: each)].
    newCollection].
s := Dictionary new.
s at: #A put: 1.
s at: #B put: 2.
s at: #C put: 3.
r := collect value: s value: [:e | e * 10].
Transcript show: r
------------------------------ Transcript --
an OrderedCollection(30 20 10)

◆ クラス Dictionary で規定されたメソッド collect: に相当する、ブロック collect について考えます。すると、
 collect value: s value: [:e | ...]
は、
 s collect: [:e | ...]
に相当して、出力結果も同じになるのが分かります。

select := [:Self :aBlock |
    | newCollection |
    newCollection := Self species new.
    Self associationsDo: [:each |
        (aBlock value: each value)
        ifTrue: [newCollection add: each]].
    newCollection].
s := Dictionary new.
s at: #A put: 1.
s at: #B put: 2.
s at: #C put: 3.
r := select value: s value: [:e | e odd].
Transcript show: r
------------------------------ Transcript --
a Dictionary(#A->1 #C->3 )

◆ クラス Dictionary で規定されたメソッド select: に相当する、ブロック select について考えます。すると、
 select value: s value: [:e | ...]
は、
 s select: [:e | ...]
に相当して、出力結果も同じになるのが分かります。

60825b ◆ ここで注目したいのは、collect: を実現するときに do: を、select: を実現するときに associationsDo: を利用していることです。また、do: および associationsDo: を実現するときに、親クラスで規定された do: を利用しています。これは、これらのメソッドによって得られる結果がすべて、親クラスで規定された do: に依存することを意味します。

【課題】何をリターンするのか
Dictionary のキーには、任意のオブジェクトを利用できますが、例外があります。それは、何でしょう。

60825c ◆ このことから、Dictionary は、特殊な Set であることが想像できます。実際に、辞書 Dictionary は、写像対 Association を要素とする集合 Set と見なせます。

==================================
真樹育未 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)

2006年10月28日 (土)

本文をご覧になるときに(テストを兼ねています)

0・・・・+・・・・1・・・・+・・・・2・・・・+・・・・3・・・・+・
この行が1行に収まるように文字の大きさを設定すると本文が見やすくなります。

ブログで公開している内容は、オリジナルを閲覧するための便宜的なものです。オリジナル版でご覧になるには、以下の中から適切なものを選んでご覧ください。

Macintosh ユーザーのみなさんは

・OmniOutliner 3《oop》オリジナル版

その他のユーザーのみなさんは

・Web アーカイブ《webarchive》

・グラフィック付きリッチテキストフォーマット《rtfd》

・Outline Processor Markup Language《opml》

------------ 序 ------------

みなさんからのコメントは「非公開」ですので、お気にご意見をお寄せください(ただし、ご質問に関しては、必ずしも執筆担当者が対応するとはかぎりません)。

あるいは、大きな声では言えない不のはけ口としてもご利用ください(もしかすると、何か回答が寄せられるかもしれませんが、そこは当てになさらず)。

公開日(リリース予定日)に至るまでの中経過も公開していますので、記事が完成するまでの過程をつぶさに観察してみるのも一興かもしれません。

【注意】正式なリリース版(PDF)とブログの記事との整合性には、の注意を払っているつもりですがでない可能性を秘めています。なにか不整合が見つかったらお知らせください。すぐにでも正式版に反映させて、再リリース致します。

※ PDF で配布された正式版は、OmniGraffle Pro 3.1.2 で作成してあります。そのため、Macintosh の`プレビュー`を使って、最も美しくご覧になれるように最適化されています。もし、Windows の環境下 Acrobat などでご覧になると、少し見づらくなる場合がありますので、あらかじめご了承ください。

◆ タイトルの末尾にある★印は、次のように設定しています。記事の内容を知る目安として、ご参考になさってください。

入門編 ★
基礎編 ★★
応用編 ★★★
中級編 ★★★★
上級編 ★★★★★

------------ 本文 ------------

 

Software Omni Graffle 4 Professional 特別優待版

販売元:アクト・ツー
発売日:2005/10/14
Amazon.co.jpで詳細を確認する


 

Book OMNI OUTLINER&GRAFFLE活用ガイド―Macでアイデアを形にする

著者:折中 良樹
販売元:カットシステム
Amazon.co.jpで詳細を確認する

Code

キーワード
サンプルプログラム
※ PDF でご覧になるなら ⇒ 公開日まで、お待ちください。
【課題】【参考文献】 ◆ □❖
==================================
担当者 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

| | コメント (0) | トラックバック (0)