Am 04.10.2011 um 13:33 schrieb Mariano Martinez Peck:



On Tue, Oct 4, 2011 at 1:08 PM, Sven Van Caekenberghe <sven@beta9.be> wrote:

On 04 Oct 2011, at 12:52, Mariano Martinez Peck wrote:

> Hi guys. If I tell you the selector is Dictionary >> #at:ifAbsentPut:  what would you expect the second parameter to be?  the value.
> So, one would do:
> Dictionary new at: #foo ifAbsentPut: 4
>
> But if you see Dictionary >>
>
> at: key ifAbsentPut: aBlock
>     "Return the value at the given key.
>     If key is not included in the receiver store the result
>     of evaluating aBlock as new value."
>
>     ^ self at: key ifAbsent: [self at: key put: aBlock value]
>
> so it expects a Block. Ok, we are in Smalltalk, so implementing #value is enough.
>
> Well..the previous example works, but only because we have an ugly Object >> value  that returns self.
> If I put instances of subclasses from ProtoObjects (proxies), that do not work anymore.
>
> So...my question is we do Dictionary at: #foo put: 4, why #at:ifAbsentPut:  expects a block and not directly the value?
> in which case I need a block instead of the value object directly ?

You are right, it feels a bit silly.
However, have a look at the senders (there are many).
Often the block holds an expensive operation when using the dictionary as a cache:

       cache at: key ifAbsent: [ backEnd get: key ]


and what is the difference to do:

cache at: key ifAbsent: ( backEnd get: key )    (notice the parenthesis instead of [])

[500 timesRepeat:[
Dictionary new at: #foo ifAbsentPut: [ CompiledMethod instanceCount ] ]] timeToRun 7254

[500 timesRepeat:[
Dictionary new at: #foo ifAbsentPut:  (CompiledMethod instanceCount)  ]] timeToRun 7294 

gives me more or less the same...

try

| dict |
dict := Dictionary new.
[500 timesRepeat:[ 
dict at: #foo ifAbsentPut: [ CompiledMethod instanceCount ] ]] timeToRun.  21

| dict |
dict := Dictionary new.
[500 timesRepeat:[ 
dict at: #foo ifAbsentPut:  (CompiledMethod instanceCount)  ]] timeToRun  10501

Norbert