9

バックグラウンド

すべての Smalltalk 初心者は、add:"self" を返すのではなく、追加されたオブジェクトを返すことに注意してください。

たとえば、次のコードを使用します。

myCollection := OrderedCollection new 
  add: 'Peter';
  add: 'John';
  add: 'Paul'.

myCollectionコレクション自体ではなく、文字列「Paul」が含まれます。

これは、add:追加されるオブジェクトが返され、カスケード式全体が最後に送信されたメッセージに評価されるためです。

代わりにyourself、最後に次のように記述する必要があります。

myCollection := OrderedCollection new 
  add: 'Peter';
  add: 'John';
  add: 'Paul';
  yourself.

質問

  • これはなぜですか?
  • これは何を設計したのですか?
  • add:このように振る舞うことの利点は何ですか?
4

5 に答える 5

12

私はこれについてたくさん考えました。Smalltalkの元の設計者がこの決定を擁護しているのを聞いたことがないので、なぜ彼らがそれをしたのかはわかりません。その理由はカスケードによるものだと判断しました。add:がレシーバーを返した場合、(things add:thing1)add:thing2はthings add:thing1と同じになります。追加:thing2。add:return引数を指定することにより、これら2つの式は異なり、プログラマーは適切な場合にそれぞれを使用できます。

しかし、それは間違いだと思います。私は25年以上Smalltalkを教えてきましたが、教えるたびに人々はこれに問題を抱えています。私はいつも彼らに警告しますが、それでも彼らはadd:で間違いを犯します。したがって、これは悪い設計上の決定だと思います。

この設計上の決定は、コンパイラーではなく、ライブラリーに関するものです。コレクションクラスに移動して変更することで、変更できます。もちろん、いくつのSmalltalkプログラムが壊れるかを予測することは不可能です。コレクションは非常に基本的なものであるため、この変更は言語の実際の変更と同じくらい難しいでしょう。

于 2012-12-27T07:52:45.143 に答える
6

他の言語では、次のように記述できます。

b[j] = a[i] = e;

at:put:put オブジェクトを返す場合、これは Smalltalk で何らかの形で保持され ます。

collectionB at: j put: (collectionA at: i put: e).

add:/にも同じ関心がremove:あり、この種の連鎖が可能です。

collectionB add: (collectionA add: anElement).
collectionB add: (collectionA remove: anElement).
于 2012-12-27T01:22:09.063 に答える
3

そのようなメソッド送信をカスケードし、それらの戻り値に決して依存しないことが常に最善です。セッター メソッドでも同じです。自己を返す場合もあれば、パラメーターを返す場合もあります。これらのメソッドの戻り値はランダムに近く、決して使用しないと想定するのが最も安全です。

于 2012-12-27T08:12:31.600 に答える
2

私はそれを擁護することはできませんし、ラルフの経験を反駁することもできません.

対称性への欲求が一因かもしれません。#remove: が削除されたオブジェクトを返すことを考えると、 #add: が追加されたオブジェクトを返すようにすることは理にかなっています。

単純な例も私たちを偏らせていると思います。変数に追加するオブジェクトが既にある場合、またはそれが単純なリテラルである場合、戻り値は無意味に見えます。しかし、次のような (疑わしい) コードがあるとします。

someProfile add: VirtualMachine youngSpaceEnd - VirtualMachine oldSpaceEnd

someProfile が線形リストの場合、最後に追加した値を取得できると思います。しかし、それはただのバッグかセットかもしれません。その場合、次のことを行うと便利です。

currentSize := someProfile add: VirtualMachine youngSpaceEnd - VirtualMachine oldSpaceEnd

以下よりも優れていると考える人もいます。

someProfile add: (currentSize := VirtualMachine youngSpaceEnd - VirtualMachine oldSpaceEnd)

最善の方法は次のとおりです。

currentSize := VirtualMachine youngSpaceEnd - VirtualMachine oldSpaceEnd.
someProfile add: currentSize
于 2012-12-27T20:27:00.637 に答える
0

私が思いついた最良の説明は、それを割り当てと同等にすることです。次のようなコードがあるとします。

(stream := WriteStream on: String new) nextPutAll: 'hello'.
stream nextPut: $!

変数への割り当ては、割り当てられたオブジェクトに評価されます。変数をコレクションに置き換えて、同等の動作を得ることができるはずです。

(array at: 1 put: (WriteStream on: String new)) nextPutAll: 'hello'.
(array at: 1) nextPut: $!

さて、そうは言っても、このコードを書いた開発者は、読めないという理由で非難します。私はそれを2行に分けたいと思います:

array at: 1 put: (WriteStream on: String new).
array first
   nextPutAll: 'hello';
   nextPut: $!

これが私ができる最高の正当化です。コレクションへの割り当てを変数への割り当てと一致させるために行われますが、その機能を利用すると、コードが読みにくくなります。

于 2013-01-05T01:33:50.790 に答える