My own Smalltalk has these: Enumerable methods for: 'enumerating' limit: n do: aBlock "Pass elements of the receiver to aBlock one at a time, as for #do:, but stop after n elements. n must be a non-negative SmallInteger. Which elements you get is for the receiver to decide." |count| n < 1 ifTrue: [ n = 0 ifTrue: [^self]ifFalse: [self pvtCountError: n]]. count := 0. self do: [:each | aBlock value: each. (count := count + 1) < n ifFalse: [^self]]. AbstractKeyedCollection methods for: 'enumerating' limit: n keysAndValuesDo: aBlock "Pass keys and corresponding values of the receiver to aBlock one at a time, as for #keysAndValuesDo:, but stop after n elements. See #limit:do:." |count| n < 1 ifTrue: [ n = 0 ifTrue: [^self]ifFalse: [self pvtCountError: n]]. count := 0. self keysAndValuesDo: [:key :value | aBlock value: key value: value. (count := count + 1) < n ifFalse: [^self]].
Enumerable is the superclass of Collection; it doesn't cover streams but does cover 2- and 3-dimensional arrays. AbstractKeyedCollection covers both dictionaries and sequences. Since they only depend on #do: and #keysAndValuesDo: respectively, they should fit nicely into some sort of Trait(s). I gave a great deal of thought to the names, and decided on "limit" since it is already in use in a similar sense in things like LimitedOutputStream or #printStringLimitedTo:. I did consider #do:limitedTo: and #keysAndValuesDo:limitedTo: which would be more consistent with #streamContents:limitedTo:, but "heavy" things like blocks really work better at the end.