Iteration and Nested Blocks
I recently ran into an interesting design challenge involving the Resource Acquisition Is Initialization (RAII) idiom and the Composite design pattern.
Consider a simple Switch
class that models an on/off switch:
Let’s say we have some actions that must be performed when the switch is off. We could write the code explicitly every time we perform any of the actions:
This works, but forces the switch off and leaves it that way. That is very likely to mess up other code, so it would be better to make sure we restore the original state of the switch when we’re done with it:
That’s a bit better, but still leaves the switch off if
perform_action
raises an exception, and it doesn’t return the switch
to the off state if something in perform_action
turns it on, so we’d
really want to use an ensure block and yet more code. That’s a lot of
duplication every time we need to temporarily turn off the switch.
Instead, we can use the RAII idiom that
I wrote about earlier
and
spoke about at MWRC 2014
and add a method to Switch
to help us with this:
That’s better.
Now, what if we had a bank of switches, and we needed all of the switches to be off while performing the action?
I guess that works, but it’s pretty fragile if we decide to change how many switches are in the bank. If we’re going to be managing banks of switches a lot, we can turn to the Composite pattern:
Most of SwitchBank
is easy to write; we have to decide whether the
bank is on or off if only a few of the switches are on (I chose “on”
here). But how do we write be_off_while
for this case?
One option is to duplicate the implementation from Switch
:
Duplication is often a code smell, and this case is no different, but
here there’s not much code, so it’s borderline. What if
be_off_while
was a much more complex method? Duplication would be
worse in that case. Is there a way we can implement this by
delegating to Switch
’s be_off_while
method? How can we marry an
iteration of SwitchBank
’s switches with nested block calls?
Here’s a way I found to solve the problem:
Here we’re using a lambda that calls itself recursively. With
recursion, there’s always a danger of running out of stack space. For
this situation we’ll assume that a SwitchBank
won’t have enough
switches to cause a problem, but it is something to be aware of.
The lambda takes a collection of switches starting with a copy of the original array. The lambda destructively modifies the collection, so we need to make sure we’re working on a copy.
If the collection is empty (the base case of the recursion), we simply
yield
to the block, performing the desired action.
Otherwise, we remove the first element from the array and call its
be_off_while
method, nesting a recursive call to the lambda inside.
This recursive call is made on a collection that is now one element
shorter than it was (because we just shift
ed an element out of it).
Because the collection is always one element shorter, we can guarantee
that the recursion will eventually terminate.
The net result is that we nest calls to each element’s be_off_while
method and ultimately perform the desired action at the innermost
level of nesting.
I found this to be an interesting problem to solve. A functional programming expert could probably come up with a better solution than this.
I originally solved this problem in Smalltalk, but translated to Ruby for this post. In both of these languages, I find this solution a little too clever and I probably wouldn’t keep this code around for long.
For my original case, the surrounding context suggested a different way of attacking the problem, so I ended up not keeping this code.