捕获每一个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:
以这种方式行事有什么好处?答案 0 :(得分:12)
我已经考虑过这个了。我从来没有听说过Smalltalk的任何原始设计师为这个决定辩护,所以我们不确定他们为什么这么做。我之所以认为原因是因为级联。如果添加:返回接收器,那么(东西添加:thing1)add:thing2将与添加的东西相同:thing1;添加:thing2。通过添加:返回参数,这两个表达式是不同的,程序员可以在适当的时候使用它们。
但是,我认为这是一个错误。我一直在教Smalltalk超过25年,每次教我都会遇到麻烦。我总是警告他们,但他们仍然会犯错误:所以,我认为这是一个糟糕的设计决定。
这个设计决定是关于库,而不是编译器。您可以通过进入集合类并更改它们来更改它。当然,无法预测有多少Smalltalk程序会破坏。收藏是如此根本,以至于这种改变很难成为对语言的真正改变。
答案 1 :(得分: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).
答案 2 :(得分:3)
最好级联这样的方法发送,永远不要依赖它们的返回值。它与setter方法相同,有时它们可能会返回self,有时它们会返回参数。最安全的做法是假设这些方法的返回值接近随机,永远不会使用它。
答案 3 :(得分:2)
我无法辩护,也无法反驳拉尔夫的经历。
对对称的渴望可能是一个促成因素。鉴于#remove:返回被删除的对象,让#add:返回添加的对象是有道理的。
我认为,简单的例子也会让我们产生偏见。当我们已经将对象添加到变量中,或者它是一个简单的文字时,返回的值似乎毫无意义。但是如果我们有(可疑的)代码看起来像这样:
someProfile add: VirtualMachine youngSpaceEnd - VirtualMachine oldSpaceEnd
如果someProfile是一个线性列表,我想你可以获取你刚添加的值:'ed via last。但它可能只是一个包或一套。在这种情况下,它可以很方便:
currentSize := someProfile add: VirtualMachine youngSpaceEnd - VirtualMachine oldSpaceEnd
有些人会认为这比:
更好someProfile add: (currentSize := VirtualMachine youngSpaceEnd - VirtualMachine oldSpaceEnd)
虽然最好的是:
currentSize := VirtualMachine youngSpaceEnd - VirtualMachine oldSpaceEnd.
someProfile add: currentSize
答案 4 :(得分:0)
我提出的最佳解释是使其等同于作业。假设你有这样的代码:
(stream := WriteStream on: String new) nextPutAll: 'hello'.
stream nextPut: $!
分配给变量会计算分配的对象。我应该能够用集合替换变量并获得相同的行为:
(array at: 1 put: (WriteStream on: String new)) nextPutAll: 'hello'.
(array at: 1) nextPut: $!
现在,说了这句话,我会惩罚任何编写此代码的开发人员,因为它不可读。我宁愿把它分成两行:
array at: 1 put: (WriteStream on: String new).
array first
nextPutAll: 'hello';
nextPut: $!
这是我能给出的最好的理由。这样做是为了将赋值转换为与变量赋值一致的集合,但是如果你利用了这个特性,你就会有难以阅读的代码。