Reputation: 13396
Imagine that you have to select some values and for each of them you have to evaluate a block. On the other hand if there is no value that satisfies the condition another block has to be evaluated.
Example: Consider the next method signature:
forPositivesOf: aCollection do: aBlock otherwise: defaultBlock
This method should evaluate a block aBlock
with every positive element of aCollection
, but if there are no elements like that, evaluate defaultBlock
. Please note that in reality the method may calculate something more complex than just positive numbers, and instead of aCollection there can be a much complex object.
Upvotes: 4
Views: 108
Reputation: 3200
Taking Uko's solution a bit further:
forPositivesOf: aCollection do: aBlock otherwise: defaultBlock
^ (aCollection
select: #positive
thenCollect: aBlock
) ifEmpty: defaultBlock
Upvotes: 1
Reputation: 13396
One really nice functional way that works for SequenceableCollections:
forPositivesOf: aCollection do: aBlock otherwise: defaultBlock
(aCollection
select: #positive
thenCollect: [ :el | aBlock cull: el ]) ifEmpty: [ defaultBlock value ]
Upvotes: 0
Reputation: 1218
A more compact version of the first alternative is the following that doesn't instantiate a new closure, and just uses the ones received as arguments.
forPositivesOf: aCollection do: aBlock otherwise: defaultBlock
^(aCollection select: [:each | each positive ])
ifEmpty: defaultBlock
ifNotEmpty: [ :collection | collection do: aBlock ]
Upvotes: 4
Reputation: 13396
At the moment I see two solutions:
1)
forPositivesOf: aCollection do: aBlock otherwise: defaultBlock
(aCollection select: #positive)
ifEmpty: [ defaultBlock value ]
ifNotEmpty: [ :collection |
collection do: [ :el | aBlock cull: el ] ]
but in case calculation of positive
is expensive it would be good to evaluate aBlock
for the first encountered element, as then the one who passed aBlock
will be able to react in any desired way.
2)
forPositivesOf: aCollection do: aBlock otherwise: defaultBlock
| encountered |
encountered := false.
aCollection do: [ :el |
el positive ifTrue: [
encountered := true.
aBlock cull: el ] ].
encountered ifFalse: [
defaultBlock value ]
But I don't like the extra encountered variable, it makes code less functional.
Upvotes: 1