#at:ifAbsent... (was: Polymorphism without protocol dilution)

Maurice Rabb m3rabb at stono.com
Wed Sep 2 03:51:22 UTC 1998

At 8:13 PM 9/1/98, Bob Arning wrote:
>I'm not sure I parsed this as you intended:
>On Tue, 1 Sep 1998 16:55:11 -0400 "David N. Smith"
><dnsmith at watson.ibm.com> wrote:
>>I don't think of this as a type issue, but an evaluation issue. When is the
>>parameter evaluated: when first passed, when about to insert it into the
>>collection (lazy evaluation), or never? I claim one needs all three.

Correct me if I am wrong, but I think you misunderstood what Dave is
saying.  If we use the proposed methods:

The parameter is evaluated when it is first passed:

   dict at: '200!' ifAbsentPut: (200 factorial).            "<- puts a value"

The parameter is evaluate when it about to be inserted:

   dict at: '55!' ifAbsentPutValueOf: [55 factorial]        "<- puts a value"

The parameter is never evaluated. (It is just inserted):

   dict at: '10! calculation' ifAbsentPut: [10 factorial].  "<- puts a block"
   dict at: '10!' ifAbsentPut: 3628800                      "<- puts a value"

At no point is he suggesting that the ifAbsent: or ifAbsentValueOf:
parameter be used or evaluated inside the method unless the #at: fails to
find the key.  He is _not_ suggesting that we break from the consistent
behavior of all the other ifXxxx: protocols.

>>#at:ifAbsentPut:, as implemented elsewhere, evaluates the parameter
>>expression before the message is sent. If it is a block then the block is
>>put into the collection.

Again this is what he means:

                  anInteger _ dict at: '22!' ifAbsentPut: (22 factorial)
"evaluates the parameter expression before the message is sent" ---|

   aBlock _ dict at: 'bobs example'
                 ifAbsent: (aBoolean ifTrue: [ [:x | x doSomething] ]
                                     ifFalse: [ [:x | x doSomethingElse] ])
"evaluates the parameter expression before the message is sent" ---|

>Are you referring to actual implementations? I seem to recall from VSE
>work that if the second argument is a block, then it is #value'd if the
>key does not exist and the result is added. Perhaps this was a local
>implementation (I cannot recall at this point) - do different
>implementations exist?

Yes, unfortunately different dialects of Smalltalk implement
#at:ifAbsentPut: with different semantics.  Some insert the second
parameter whether it is a block or a simple object (as we propose).  Others
insert either a simple value, or the value of a block if it is a block.


>>Note that, for consistancy, if the thrid example is considered wrong, one
>>should then make #at:put: have the same properties as #at:ifAbsentPut:. If
>>a block is passed it is evaluated before putting its value into the

To restate the above: If #at:ifAbsentPut: behaves such that it accepts
either a simple value or a block, using the value of the block if it is a
block, then #at:put: should behave the same. Thus:

dict at: 1 put: 10 factorial            "puts a 3628800"
dict at: 2 put: [10 factorial]          "puts a 3628800"
dict at: 3 put: [ [10 factorial] ]      "puts a block"

IMHO, these semantics are not just ugly, but "astonishing"!  I vote for Dave's.

Dave, please correct me if I got this all wrong.


  Maurice Rabb    773.281.6003    Stono Technologies, LLC    Chicago, USA

More information about the Squeak-dev mailing list