Exceptions and conditionals
Our convention has been to raise an exception when a method (such as match) fails. This causes a problem with if statements. Often we want to test whether an operation, such as match, succeeded and take an appropriate action. Raising an exception on failure precludes that.
Andy suggested that we could require the use of special method names in conditionals, say ending with ?, and catch the NoMethodError exception to define those methods to return a Boolean value, instead of raising exceptions. So, instead of writing if match, we would write if match?. Unfortunately, that has two problems:
- If NoMethodError is raised then either the rest of the computation within main is lost or the entire computation must be restarted (using retry). The first is unacceptable and the second is highly inefficient at best—in the worst case, it would be incorrect if the computations in main have side-effects.
- If the user class defined its own method name ending with ? then we have no control over its behavior.
The issue here is similar to what comes up in implementing “projection” and “congruence”. Essentially, we want to defer the computation. In this case, we want to defer computing the conditional expression so that it can first be enclosed inside a rescue block to return a Boolean value, instead of raising an exception. The solution is also similar, by introducing appropriate keywords and requiring that the method name be specified symbolically for later evaluation.
if succeeds :match, with_args(:Assign[...]) ... elsif succeeds :myMethod ... else ... end
Of course, with_args is optional, as the elsif clause shows. Finally, fails is a synonym of !succeeds. Once again, my desire to have the most compact syntax trumps other possible solutions that would require enclosing the if-else statement inside a block.
The icing on the cake with this approach is that we can implement environment rollback on failure inside conditionals.
Our convention has been to raise an exception when a method (such as match) fails. This causes a problem with if statements. Often we want to test whether an operation, such as match, succeeded and take an appropriate action. Raising an exception on failure precludes that.
Andy suggested that we could require the use of special method names in conditionals, say ending with ?, and catch the NoMethodError exception to define those methods to return a Boolean value, instead of raising exceptions. So, instead of writing if match, we would write if match?. Unfortunately, that has two problems:
- If NoMethodError is raised then either the rest of the computation within main is lost or the entire computation must be restarted (using retry). The first is unacceptable and the second is highly inefficient at best—in the worst case, it would be incorrect if the computations in main have side-effects.
- If the user class defined its own method name ending with ? then we have no control over its behavior.
The issue here is similar to what comes up in implementing “projection” and “congruence”. Essentially, we want to defer the computation. In this case, we want to defer computing the conditional expression so that it can first be enclosed inside a rescue block to return a Boolean value, instead of raising an exception. The solution is also similar, by introducing appropriate keywords and requiring that the method name be specified symbolically for later evaluation.
if succeeds :match, with_args(:Assign[...]) ... elsif succeeds :myMethod ... else ... end
Of course, with_args is optional, as the elsif clause shows. Finally, fails is a synonym of !succeeds. Once again, my desire to have the most compact syntax trumps other possible solutions that would require enclosing the if-else statement inside a block.
The icing on the cake with this approach is that we can implement environment rollback on failure inside conditionals.
2 comments November 6th, 2008
Show Comments