I have two comments to make. The first addresses the use of labels. The second is on why you you might want an exception rather than a logical test.
Loop Labels
Loop labels and loop control are the one common form of goto
that isn't generally frowned upon. (The other form is the rare use of a particular form in AUTOLOADER to seamlessly transfer control to generated code--unless you start experimenting with deeper magics you will never need it.)
@rassie
's point that your tests should be encapsulated in an is_valid()
method for your objects is excellent, but I want to comment on another important aspect of using labeled loops: naming.
Using OUTER
as a label is like using %hash
as a variable. The name tells a maintenance programmer nothing about what is happening or why.
Perl syntax calls out for a noun-verb naming structure for labels with keywords like next
and last
. Good names for your outer loop could be OBJECT_TEST
, OBJECT_VALIDATION
, or OBJECT_CHECK
.
Exceptions
When I look at your code I see a structure that is focussed on the normal case. This is fine as long as you have a way to ensure that errors are caught.
If your stuff_that_assumes_valid_object()
method checks for validity, then throws an exception (via die
), then your code becomes very simple.
This code is identical to your nested loop:
eval { $_->stuff_that_dies_on_invalid_object() for @objects };
store_objects(@objects);
But if you want the behavior in @rassie
's code of filtering out invalid objects and only storing the valid ones, you can do:
my @to_store = grep {
eval { $_->stuff_that_dies_on_invalid_object; 1 }
} @objects;
store_objects(@to_store);
It's also nice to know that your calls to code that makes assumptions will be safe. Either you expect a failure and catch the exception, or your program terminates on an unexpected, unsafe operation.
P.S. @rassie
is absolutely right about the Law of Demeter. Keep your object internals and knowledge about them as limited as possible. Consider making store_objects()
, assumes_valid_elements()
and assumes_valid_objects()
code into methods.