Ken Nakagakさん、上手です。
素晴らしい仕上がりですね。
プログラミング言語間の変換というのは、両方の言語の根本的な部分、最もオブ
ジェクト指向の原点に近い部分を知らないとできないわけで、自分で言い出しな
がらちょっと無謀だったかなと思っていました。このような良い変換を出してい
ただいて、提案者としてとてもうれしいです。
例えば、下記の部分などは、直接、引数付きコンストラクタをつくるのかと思っ
ていたので、なるほど、と思いました。
> public Sum(String aString, int aNumber){ setNameAndAmount(aString, aNumber); }
>
> public Sum setNameAndAmount(String aString, int aNumber){
内容は、時間をかけて調べて、コメントさせていただきます。
一点のみ、ブロックの説明を補強した方が良いと思うので、叩き台を載せておき
ます。加筆・訂正をお願いいたします。
On Sat, 10 Jun 2000 22:50:14 +0900
"Ken N." <kenn@....nu> wrote:
> Part1と2についてコードをJavaにしてみました。
> どの程度妥当な訳になっているかあまり自信はありませんが、参考になれば。
>
>
> まずはPart1のほうです。
>
>
> <Smalltalk>
> === Page 190 Code 1
>
> Object subclass:#Sum
> instance variables:'name amount'
> </Smalltalk>
>
> <Java>
> === Page 190 Code 1
>
> /*
> Smalltalkではクラスにメッセージを送ることによってサブクラ
> スを導出します。適当な基底クラスが見付からなければ
> ``Object'' にメッセージを送ることになります。意味としては
> 新規クラスの定義ですので、Javaならば以下のように書けば十分
> でしょう。
> */
> class Sum {
> private String name;
> // 後になって登場するコードを見る限りでは、nameはString
> // で良いと思われます。
> private int amount;
> // amountについては、とりあえずintにしておきました。
>
> // メソッドの定義は後で出て来ます。ここではブランクにして
> // おきます。
> }
> </Java>
>
>
> <Smalltalk>
> === Page 191 Code 1
>
> ^self new
> setName:aString
> amount:aNumber
> </Smalltalk>
>
> <Java>
> === Page 191 Code 1
>
> /*
> 本文の記述をみればわかる通り、上記のSmalltalkコードは、メソッ
> ドの本体部分だけです。しかし、「コンストラクタ」と明記され
> ていますので、以下のように書けます。
> */
> public Sum(String aString, int aNumber){
> setNameAndAmount(aString, aNumber);
> }
> </Java>
>
>
> <Smalltalk>
> === Page 191 Code 2
>
> name:aString amount:aNumber
> ^self new
> setName:aString
> amount:aNumber
> </Smalltalk>
>
> <Java>
> === Page 191 Code 2
>
> /*
> すでに上述のとおりですが、ファクトリメソッドのほうが意味的
> に近いかもしれません。こんなふうに書けると思います。(でも、
> いかにも「直訳」という感じですね)
> */
> private Sum(){}
>
> public static Sum createWithNameAndAmount(String aString, int aNumber){
> Sum aNewSum = new Sum();
> aNewSum.setNameAndAmount(aString, aNumber);
> return aNewSum;
> }
> </Java>
>
>
> <Smalltalk>
> === Page 191 Code 3
>
> setName:aString amount:aNumber
> name:=aString
> amount:=aNumber
> </Smalltalk>
>
> <Java>
> === Page 191 Code 3
>
> /*
> 「新しいインスタンスを作って初期化する」という処理から「イ
> ンスタンスを初期化する」という処理を分離するのが彼らの流儀
> のようです。
>
> 直訳すると以下のようになるでしょう。
> */
> public Sum setNameAndAmount(String aString, int aNumber){
> name = aString;
> amount = aNumber;
> return this;
> }
>
> /*
> しかし、実際にはつぎのようなものでも十分かもしれません。
> */
> private /* or protected */ void setNameAndAmount(String aString, int aNumber){
> name = aString;
> amount = aNumber;
> }
> </Java>
>
>
> <Smalltalk>
> === Page 192 Code 1
>
> name
> ^name
> </Smalltalk>
>
> <Java>
> === Page 192 Code 1
>
> // 特に説明は不要だと思います。
> public String getName(){ return name; }
> </Java>
>
>
> <Smalltalk>
> === Page 192 Code 2
>
> amount
> ^amount
> </Smalltalk>
>
> <Java>
> === Page 192 Code 2
>
> public int getAmount(){ return amount; }
> </Java>
>
>
> <Java>
>
> /*
> 彼らは、ここまでで一旦``Sum''の実装に一区切りつけています
> から、一応まとめておきます。
> */
> class Sum {
> private String name;
> private int amount;
>
> public Sum(String aString, int aNumber){ setNameAndAmount(aString, aNumber); }
>
> public Sum setNameAndAmount(String aString, int aNumber){
> name = aString;
> amount = aNumber;
> return this;
> }
> public String getName(){ return name; }
> public int getAmount(){ return amount; }
> }
> </Java>
>
>
> つづいてPart2のほうです。
>
>
> <Smalltalk>
> === Page 193 Code 1
>
> testEmpty
> |summarizer|
> summarizer:=self emptySummarizer.
> </Smalltalk>
>
> <Java>
> === Page 193 Code 1
>
> /*
> Summarizerクラスの実装に入る前に、そのクラスのテストを先に
> 書くことから始めているわけですね。本章の主題でもあります。
>
> さてと... JUnitを使うことにしましょうか。
>
> class SummarizerTest extends TestCase {
> ...
> }
>
> などとしてあるものとします。
> */
>
> public SummarizerTest testEmpty(){
> Summarizer summarizer = emptySummarizer();
> // 未完です
> return this; // voidでもいいと思います。
> }
> </Java>
>
>
> <Smalltalk>
> === Page 193 Code 2
>
> testEmpty
> |summarizer|
> summarizer:=self emptySummarizer.
> self should:[summarizer summary isEmpty]
> </Smalltalk>
>
> <Java>
> === Page 193 Code 1
>
> /*
> ``should:''キーワードメソッドは、受け取ったブロッククロー
> ジャにvalueメッセージを送り、Trueのインスタンスが返ってこ
> なければエラーとするものだと推測できます。以下のように書け
> ると思います。
> */
> public SummarizerTest testEmpty(){
> Summarizer summarizer = emptySummarizer();
> assert(summarizer.summary().isEmpty());
> return this; // voidでもいいと思います。
> }
> /*
> しかし、両者の違いについては知っておいたほうがいいでしょう。
> 上記Javaコードではassertには評価された後の値、つまり、真ま
> たは偽が渡りますが、前出のSmalltalkコードでは、真偽の獲得は
> should:キーワードメソッドの中で行なわれることになります。
#ここです。ブロックに対して以下のような説明があった方が解り易いと思いま
す。叩き台です。
・[ ]はブロックを意味する。
[:引数 | 記述 ] [:引数 | |一時変数| 記述 ]の形で使われる。
ブロック内のコードは、value ファミリーのメッセージを行うまで実行されない。
(遅延実行)
ブロックの value は、ブロック内で最後に実行された最後の評価ステートメント
の値である。
ループに使われる WhileTrue: IfTrue: そして and: などのメッセージにおいて、
レシーバまたはパラメータとしてブロックが使われる場合は記述ブロックであり、
インラインでコンパイルされるため、ブロックとしては扱われない。
(「さくさくSmalltalk(p39)」 および Smalltalk by Example(p54)より引用)
#value で 評価する場合とそうでない場合をどう判別するか教えて下さい。
ちはみに、「Smalltalkイディオム」(青木淳著)を見たらこんなことが書いてあり
ましたので併せて紹介します。
ブロッククロージャはリテラルであり、・・・Smalltalkでプログラミングすると
いうことは、仮想イメージ(オブジェクトメモリ)の中にブロッククロージャの
ようなリテラルを書き込んでいくことに他なりません。・・
ブロッククロージャは遅延評価が可能なオブジェクトであり、多彩な制御構造を
作り出す鍵になっています。・・ブロッククロージャを縦横無尽に使いこなせる
ようになったならば、Smalltalkプログラミングの免許皆伝になることを記憶して
おいてください。
#以下のソースは省略。
(以上)
> -.- . -. -.
> Ken Nakagaki (kenn@....nu is NOT for private E-Mail)
> 「人は船ではない。人は会社ではない」-- Gerry Spence
>