in reply to eval-blocks and Test::Builder

I try to avoid using eval and code that can dies (exceptions being the exception). Why wasn't this written as something like

package DBM::Deep::Array; sub _get_self { ref $_[0] eq ARRAY ? tied( @{$_[0]} ) : $_[0] }
possibly with a Scalar::Util::reftype()?

eval is reasonably expensive as it creates a new lexical scope and dieing and unwinding the stack is also expensive. Is there an advantage to using it rather than the code above? updated:silly benchmark added and removed!

Replies are listed 'Best First'.
Re^2: eval-blocks and Test::Builder
by dragonchild (Archbishop) on Feb 25, 2006 at 00:51 UTC
    Actually, the nearly-equivalent code is:
    sub _get_self { my $reftype = Scalar::Util::reftype( $_[0] ); $reftype = '' unless defined $reftype; if ( $reftype eq 'ARRAY' ) { return tied( @{ $_[0] } || $_[0] } return $_[0]; }
    (Your version misses the fact that 'ARRAY' is a legal classname and that the value returned from tied() is a blessed hashref which makes the _get_self() for DBM::Deep::Hash more complex.)

    (Yes, my code could be shortened if I was able to use // for defined-or. That's a 5.10ism and DBM::Deep runs on practically every Perl version since 5.004, we think.)

    I don't like that code for three reasons:

    1. It's 6 times longer and has at least twice the number of codepoints. This makes it at least 4 times harder to comprehend at a glance.
    2. Writing that code correctly to function in all cases is hard. I had to edit my version twice as I was writing this reply because I found edge cases.
    3. It assumes that $_[0] will never be something that wants to pretend it's an array using overload. For example, using Contextual::Return or some other magic.

    By using an eval-block, you allow the item to behave the way it wants to behave, if it wants to behave that way, plus you let Perl worry about the edgecases. To get truly equivalent code would be about 40 lines and I don't think I could get it all correct. At that point, an eval-block is quicker.


    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?

      I'm not familiar with DBM::Deep but are you really expecting to have a $_[0] that's a Contextual::Return object? If _get_self is a method in the DBM::Deep::Array package then I don't see how any of the edge cases you have catered for could actually happen.

        A couple of the features that we're working towards are subclassibility and multiple engines. Which means DBM::Deep::Array could be subclassed by something that masquerades as an array using Contextual::Return or some other class that overloads @{}. Why should I prevent that when I prefer to use code that ducktypes $_[0] vs. explicit-types it?

        My criteria for good software:
        1. Does it work?
        2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?