Just a quick note that Devel::EvalError is up. I got tired of repeatedly running into cases where $@ was empty even though an eval had just failed (in code that throws and catches a lot of exceptions). After hand-rolling the quick fix several times for cases that I ran into, I realized this should just be a module. Enjoy.

- tye        

`

Replies are listed 'Best First'.
Re: Devel::EvalError lives
by Your Mother (Archbishop) on Jul 07, 2008 at 04:45 UTC

    This is wonderful. Your snippets here about the issue a while back opened my eyes to a bunch of things I didn't know/consider. But I have to ask about the module, what's with the camelcase methods? ItIsReallyNotPerlLike and IveGrownIncreasinglyIrritatedByItsUse.

      Underscores suck. They disappear in browser links. They render wider than spaces in propotional fonts conveying the exact opposite meaning of what they should (these_items_are_groups_together even_though_the underscores_have_spread_them_apart). They are relatively hard to type.

      But so much for whining about trivialities.

      Perl uses all-lower-case or all-upper-case for its special names (keywords, reserved words, built-ins, etc). So I don't use either scheme for naming subroutines (since the practice of marking user subroutines with their own sigil fell out of fashion). So I consider it important (not just "style") to use an initial capital on subroutine names.

      I've never seen anybody using underscore_ridden_identifiers with mixed case. And I'm inclined to consider Such_A_Practice a Worst_Of_Both_Worlds situation (for one thing, even harder to type, especially when the 'shift' has to quickly switch sides). And other alternatives seem equally silly (different capitalization for one-word names or Just_initial_cap_with_underscores).

      So I use CamelCase for module names and for subroutine names. Since there was a grand total of two subroutines with TwoWords names (and one more whose use is already discouraged that would have two words, one hyphenated hence three capitals in CamelCase) complaining "IveGrownIncreasinglyIrritatedByItsUse" is over the top, of course.

      I suppose you prefer CGI.pm where one uses td() but Tr()? I don't want to be the first module author who picked 'say', 'our', 'qv', 'when', 'given', 'dor', etc. as a subroutine name.

      I suggest you get over it. Otherwise, wikis are going to be painful for you. :)

      - tye        

Re: Devel::EvalError lives
by Tanktalus (Canon) on Jul 07, 2008 at 16:09 UTC

    I suppose you probably hit this problem more often than many of the rest of us ;-) Then again, you may notice more than the rest of us...

    What surprised me when I looked at the doc was that we actually had to type "eval" ourselves. I kind of expected it to take a coderef or string, and perform the eval itself. (This may have still required "sub" since prototyping wouldn't work for this, and since you're using objects where I don't think prototyping works anyway.)

    A bit more thinking, and I'm wondering why all the overhead in the first place. If you had an exportable SafeEval (maybe two - one taking strings, the other taking a code ref via a prototype to look more like the built-in eval) which automatically created the object and returned that, it would definitely make this much simpler. And simpler means faster adoption. And that means more safe perl code out there. IMO, it may even make it harder to misuse the module (again, producing more safe code).

    use Devel::EvalError; my $ee = EvalExpectOne { ...; 1 }; ... $ee->Reuse(); $ee = EvalExpectOneStr "..."; # EvalExpectOneStr could append the "; 1 +" to the end automatically
    These eval functions would be able to set up all the handlers, do the eval, and take down all the handlers before returning back. That should also get rid of your overlapping issues - there'd be no hanging-on of previous handlers - the only way to overlap really would be having one eval inside another (directly or indirectly).

    Then, for absolute convenience, I'd suggest that EvalExpectOne probably could do everything via Contextual::Return:

    return BOOL { $obj->Succeeded() } STR { $obj->Reason() } LIST { $obj->AllReasons() };
    But that's probably getting too convoluted ;-) ("Too much black magic")

      No, I won't be using Contextual::Return. Anything that feels the need to globally override something as basic as caller isn't something that other modules should depend on (and it appears to have relatively little reason to override it, but I haven't looked at it). Going from my "Chance of success 100%" to a subset of Contextual::Return's "Change of success 63%" is certainly not worth the proposed convenience (not to mention the subtle complexity).

      It might be worth having a function that takes a code ref (and a separate one that takes a string). Given the serious problems with such minor magic that made Error something to avoid (Re: Re2: Learning how to use the Error module by example), I didn't want to repeat that mistake.

      But it may be that EvalBlock { ... } would only change the semantics exactly as much as eval { ... } would anyway. I'll have to contemplate that a bit (I was thinking that there was some trap with regard to making closures, but a memory leak in old Perls is not enough to prevent me from offering such a simpler interface). I had intended to research that issue but failed to, so thanks for reminding me.

      Part of the reason that I didn't go down that road is that I wanted to allow the user to choose how to make their eval "expect one". But I guess I could take a string or block but still leave the appending up to the user (where it will be visible to the next person to read the code). I also didn't want to have to have 4 routines. But I've since decided to pretty much deprecate ExpectNonEmpty(), so just having EvalString and EvalBlock might be the way to go.

      I'll at least leave the current interface available for those who want to avoid memory leaks in certain Perl versions.

      Thanks again.

      - tye