Squeak教室 上級編その2
「入出力からクラスの定義まで」
■繰り返し計算する
さて、前回、簡単な式と条件分岐っぽいメッセージを覚えたので、次は繰り返し(っぽいメッセージ)を使ってみようと思います。が、その前に、いつまでもボタンのスクリプトパネル使うわけにもいかないので、もうちょっとちゃんとしたエディタの呼び出し方を覚えておきましょう。
Smalltalkには非常にたくさんのブラウザやエディタがあります。それらは、無数にあるクラスから必要なものを的確に探し出すためにあるわけです。で、「とりあえず、簡単なプログラムをその場で動かせればいいや」っていう場合には、「ワークスペース」というものが便利です。
これを呼び出すには、まずescキーを押して(第2の)ワールドメニューを呼び出して下さい。そこから「開く」を選ぶと、更にメニューが現れます。ここから「workspace」を選ぶと、画面に簡単なテキストエディタのようなウィンドウが現れます。
この「開く」メニューでは、他にクラスのブラウザやメソッドを調べるツールなどいろいろ用意されているので、暇をみてどんなものがあるか調べてみると面白いでしょう。特に「browser」や「package
browser」では、Smalltalk内の全クラスが調べられて、「ほうほう、何がなんだかわけがわからんけどこうなってるのか」ということが見えて楽しいです。
さて、それではいよいよ繰り返しをやってみましょう。ワークスペースに、以下のようにソースコードを記述して下さい。そして、例によって書いたテキストを選択し、ウィンドウ内をescキーを押して現れるメニューから「評価して表示」を選ぶと、実行結果が表示されます。
|total n| total _ 0. n _ 100. 1 to: n do: [:i| total _ total + i]. ^ total
|
例によって、「_」記号=「←」記号、「^」記号=「↑」記号となります。で、実行すると、「5050」という計算結果が表示されます。・・これ、よく見れば、Squeak編の5でやった合計計算の丸写しなんですが(笑)、ま、こういうのはどうやっても他に書きようがないからねぇ・・。
さて、ここで登場しているのは、こんな形のメッセージです。ちょっとややこしいのでよくみて下さい。
数字1 to: 数字2 do: [: 変数 | 実行する文 ]
なんかややこしそうですが、これは、数字1から数字2まで順番にdo:以降のブロック文を実行していくメッセージです。例えば「1to: 10」とあれば、1〜10までの整数ごとに順番にdo:
[]部分を実行していきます。この際、その値はブロックの最初に用意されている変数で得られるようになっています。——例えば、今回の例で見れば、1〜変数nの値まで、ブロック文を実行していくわけです。ここで、totalに変数iの値(つまり1〜nの値)を加算していくことで合計が計算されるわけですね。
それから、これは「数字1のオブジェクトに、to:数字2のメッセージを送り、更にそれにdo:[]のメッセージを送ってる」ということ、ではないです。これは「to:○○
do:[××]」というので1つのメッセージになってます。つまり、to:とdo:の2つの要素からなるわけですね。Smalltalkには、こういう複数の要素から1つのメッセージができあがっているものもあります。こういうのは、to:だけとかdo:だけでは使えないので注意しましょう。
■テキストの入力と表示
しかし、こういうプログラムは、やっぱりユーザーに入力してもらって動くようにならないと、あんまり実用的じゃありません。そこで、その辺りをもう少し補強した形にプログラムを修正しましょう。
| total n str1 | str1 _ FillInTheBlank request: '数字を入力' initialAnswer: '100'. str1 = '' ifTrue:[^nil]. n _ str1 asInteger. total _ 0. 1 to: n do: [:i| total _ total + i]. str1 _ total asString. PopUpMenu notify:'答え:' , str1.
|
これを選択して実行すると、まず画面に「数字を入力」って入力ダイアログが現れます。ここで整数を入力して「了解」ボタンを押すと、1からその数字までの合計を計算して画面に表示します。だいぶ、プログラムっぽくなってきましたね?
ここでは、入力と出力(画面表示)のためのメッセージを使っています。まず入力ですが、これは以下のようなものになります。
FillInTheBlank request: 表示テキスト
initialAnswer: 初期値
この表示テキストと初期値は、いずれもテキストで指定します。これを実行すると、画面に先ほどの入力ダイアログが出てくるわけです。そしてその入力結果が返されます。なおキャンセルした場合には、空のテキストが返されます。
次に画面へのテキストの表示ですが、これは以下のようになります。
PopUpMenu notify: テキスト
今回の例では、テキストをカンマで区切って続け書きしてますね? 複数のテキストをひとまとめに表示したいときは、こんなふうにカンマでつなげて書けます。
また、PopUpMenuという名前からもわかるように、これは本来、メニューを表示するためのものなのです。つまり、ここでは「了解」という項目1つだけのメニューを表示していたわけです。notify:というセレクタを使うと、このように「了解」項目を持ったメッセージ表示用のGUIとして利用できます。
メニューとして利用したければ、「labels:」というセレクタを使い、表示するメニュー項目を指定すれば、普通のメニューを表示させることもできます。例えば、こんな具合です。
(PopUpMenu labels:'AAA\BBB' withCRs) startUp
|
これを評価して表示させると、画面に「AAA」「BBB」という2つの項目を持ったメニューが現れます。そしてメニューを選ぶと、選んだ項目の番号が結果として出力されます。なお、前にもいいましたが「¥」記号は「\」に変わります。
今回は、「withCRs」という変なものが使われてますね。これはテキストのオブジェクトに対し、¥をすべて改行文字として扱うようにするものです。それから「startUp」は、PopUpMenuオブジェクトを画面に表示させるものです。これがないと、実際に表示されないので忘れないように。
今回は、この他にもポイントがあります。それは、「n _ str1 asInteger.」「str1 _ total asString.」という部分です。ここで整数の値をテキストの引数に指定したりするとエラーになります。オブジェクトの種類によって受け付けるメッセージは違うので、「Stringオブジェクトのままの'100'」と「Integerオブジェクトの100」では扱えるメッセージなども違ってきてしまうわけです。なので、ちゃんと必要な種類のオブジェクトを取り出す必要があります。
このような場合、その値のオブジェクトにある「asInteger」「asString」といったものを呼び出すことで、別の種類の値として取り出すことができます。変数自身に型がないので、「どーせ型ないんだからそのまま使っちゃって大丈夫だろ」と思いがちですが、そうすると「そんな種類のオブジェクトじゃメッセージ受けられないよん」といわれちゃったりするのです。
■クラスを作ろう!
しかし、毎回その場でソースコードを打ち込んで実行するというのもけっこう面倒なものです。そろそろ、ちゃんとしたプログラムとして作成しておく方法を覚えておくべきでしょう。
最初に触れましたが、Smalltalkではプログラムは「クラス」と呼ばれるものとして用意されています。プログラムの設計図に相当するものですね。そしてこの中に、必要に応じてさまざまな機能を「メソッド」として組み込みます。ですから、自分でプログラムを作ろうと思ったら、「クラス」というものを作らないといけません。
では、実際に作ってみましょう。ワークスペースから、以下のように入力して実行してみて下さい。見た目は何も変化ありませんが、これで「MyTestClass」というクラスが作成できます。
Object subclass: #MyTestClass instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Tuyano-TestClasses'
|
実際に、ちゃんとクラスができているのか確かめてみましょう。デスクトップでescキーを押してワールドメニューを呼び出し、「開く」メニューのサブメニューから「package
browser」を選んで下さい。画面に、パッケージごとにクラスを閲覧するブラウザ・ウィンドウが現れます。
これは、クラスをパッケージごとに分類して表示するものです。左上の一覧から「Tuyano」を選ぶと、隣の列に「TestClasses」という項目が現れます。これを選ぶとその右の列に「MyTestClass」が。これが、作成したクラスです。選択すると、下の欄に先ほどのクラス定義の文が表示されますね。
さて、先ほどの「クラスの作成」で実行した文は、こんな形をしたものです。ちょっとややこしそうですが、ほとんどの部分は無視してかまわないので、それほど難しくはありません。
継承クラス subclass: #作るクラス
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: カテゴリのテキスト
クラスというのは、「あるクラスを元にして新たなクラスを作る」のが基本です。これは「継承」といって、クラスをらくちんに作るための仕組みなのです。
例えば、「ウィンドウのクラスを作りたい」と思ったとしましょう。すると、ウィンドウに関する全ての機能を実装しないといけません。これは、猛烈に大変です。そこで、あらかじめSmalltalkに用意されている「ウィンドウを表示するクラス」を探し、これを継承して新たなクラスを作ります。するとあら不思議! 継承したクラスの全ての機能をそのまま受け継いで、新しいクラスが作られます。何もしなくても、継承したクラスの全機能が自動的に使えるようになるのです。これが「継承」です。
今回は、別に「このクラスを利用したい」ということはありません。そういう場合は「Object」という一番基本になるクラスを継承します。「Object
subclass: #クラス名」という形で書けば、Objectクラスを継承した新しいクラスができるわけですね。
その後にあるのは、インスタンス変数・クラス変数・プール辞書・カテゴリといったものを指定するためのものです。が、これらはよくわからなければ、空のテキストを指定してかまいません。ただし、最後のカテゴリについては、きちんと指定しておきましょう。今回は「Tuyano-TestClasses」としてありますね。こうすると「Tuyano」内に「TestClasses」というカテゴリが作成され、そこにクラスが置かれるようになるわけです。このようにカテゴリのテキストは「○○-××」といった形で指定します。
■メソッドを追加する
では、先ほどのソースコードをメソッドとしてMyTestClassに追加してみましょう。せっかく先ほどパッケージブラウザを開いたので、これを使って作業をしていくことにします。
まず、作成した「MyTestClass」を選択し、その下にある「Class」というのをクリックして選びます。これは、インスタンスメソッドとクラスメソッドの切り替えボタンです。「インスタンスメソッド」というのは、インスタンス(クラスを元にして作ったオブジェクトです)で使うためのもので、「クラスメソッド」はクラスで使うものになります。これははっきりわかれていて、例えば「インスタンスを作って使うんだけど、ここからクラスメソッドも呼び出しちゃえ」なんてことはできません。クラスメソッドはあくまでクラスに向けてメッセージを送り呼び出すものです。
例えば、今回は「計算をする」メソッドです。これ、いちいちオブジェクト(インスタンスね)を作ってその中のメソッドを実行して・・なんてやるの、面倒くさくないですか? クラスから直接「これやって」と呼び出せた方が便利ですよね? それで、今回はクラスメソッドにしたわけです。まぁ、こういうのは実際に何度も作ってみれば、自然と「どっちにするか」が見えてくると思いますよ。
では、「Class」を選択して現れる右の列(--all--とno messagesって項目がある)の上にマウスポインタを移動し、escキーを押して下さい。そして現れたメニューから「new
category」を選びます。すると、ずらっとカテゴリ名が出てくるので、今回は「new」というのを選び、新しいカテゴリ名として「calc messages」と入力して下さい。これで、クラスメソッドに「calc
messages」というカテゴリが追加されます。
では、作成した「calc messages」カテゴリを選択し、下にある欄に、以下のようにメソッドを記述しましょう。そして、すべてを選択してから、escキーを押して現れたメニューで「了解」を選びます。これでメソッドが作成されますよ。
totalCalc | total n str1 | str1 _ FillInTheBlank request: '数字を入力' initialAnswer: '100'. str1 = '' ifTrue: [^ nil]. n _ str1 asInteger. total _ 0. 1 to: n do: [:i | total _ total + i]. str1 _ total asString. PopUpMenu notify: '答え:' , str1. ^ str1
|
メソッドとしてソースコードを定義する場合、普通にワークスペースで書くのと少しだけ違いがあります。一番最初に、メソッド名を記述する、ということです。
できあがったら、ワークスペースから「MyTestClass totalCalc」と書いて評価実行してみましょう。ちゃんと、メソッドが呼び出されるでしょう? こんな具合に、クラスメソッドは「クラス
セレクタ」という形でいつでも利用できるようになります。なんか、「Smalltalkを使ってる」って感じになってきましたねぇ?
というわけで、ざっとクラス定義からメソッド定義までやってみました。まだ、これだけ眺めても「インスタンスメソッドの場合はどうするんだ?」「引数を持ったときはどうやるんだ?」「クラス変数やインスタンス変数はどうやって作るんだ?」などなど、疑問点が山盛りで出てきそうです。とりあえず「クラスの作り方」「メソッドの作り方」の一番基礎的な部分だけですが、「こんなもんだ」ということを覚えておいて下さい。残りは、慌てず騒がす少しずつ・・。
GO NEXT