Re: Why UNIVERSAL::(can|isa) Warn (was Re: using $SIG{__DIE__} correctly (if you must))
Michael G Schwern wrote: I realize this might be because rt.cpan.org does not appear to have been sending out ticket emails. The RSS feeds work though. Shame there's no obvious way to sign up to one feed for all my modules, but I have a little shell script which periodically makes sure I'm signed up for all my individual feeds. Anyone who wants it, prod me off-list. It assumes you use rss2email, but should be adaptable for all other sensible RSS tools. -- David Cantrell
Re: using $SIG{__DIE__} correctly (if you must)
* Joshua ben Jore [EMAIL PROTECTED] [2007-02-28 06:20]: On 2/27/07, A. Pagaltzis [EMAIL PROTECTED] wrote: Together with the contortions required to safely examine $@ after an eval I'm getting tempted to put Unbreak::Eval on the CPAN. Please do. I was joking, mostly; I have several other modules that I’m already neglecting; it wouldn’t do anyone much good if I were to add another neglected module to my directory. :-/ Did David Golden ever send his $@ examining snippet to you? It did about the same thing so the multiple possible errors all got captured. Nope. I think it would already be a good idea if someone just collected all the related issues and solutions in one prose document (maybe as a meditation on PerlMonks) so whoever does have the time and energy to tackle this can simply sit down and play from the sheet. Regards, -- Aristotle Pagaltzis // http://plasmasturm.org/
Re: using $SIG{__DIE__} correctly (if you must)
On Wednesday 28 February 2007 12:53, A. Pagaltzis wrote: I think it would already be a good idea if someone just collected all the related issues and solutions in one prose document (maybe as a meditation on PerlMonks) so whoever does have the time and energy to tackle this can simply sit down and play from the sheet. For what it's worth, I'm working on one for type checking in Perl (that is, Things you'd use ref() for if it actually worked). -- c
Re: Why UNIVERSAL::(can|isa) Warn (was Re: using $SIG{__DIE__} correctly (if you must))
chromatic wrote: On Monday 26 February 2007 21:20, Michael G Schwern wrote: Case in point... my tests started suddenly warning about UNIVERSAL::isa called as a function in Class::DBI. After spending a bunch of time trying to figure out what the hell was going on and if Redhat introduced some new warning or something I finally discover that Test::MockObject uses UNIVERSAL::isa() which warns if *anyone* calls UNIVERSAL::isa() as a function. Its nagging *me*, the unrelated 3rd party, about problems in someone else's code that I don't have control over! No, it's warning you that if Test::MockObject doesn't work, that it's not *my* problem. It's also telling you exactly *where* that problem is. If that were so it would only warn when a MockObject is looked at using UNIVERSAL::isa/can() as a function. That would cover the utility of warning a user about a possible problem using mocked objects without launching a UNIVERSAL::isa crusade. As it is it warns on *any* use of UNIVERSAL::isa() as a function, mocked object or no (although right now UNIVERSAL::isa appears to not warn at all). As much as I'd like to fix the real problem (the belief that enforcing structural subtyping makes any sense), the best I can do is try to work around the damage while not sweeping it under the rug. I can't see how ignoring the problem gets it fixed. While I understand the desire to want to fix other people's code and educate users, there are many problems with this appraoch. I've outlined them in detail below but what it boils down to is this... When I'm programming on a project I want to work on that project. What I do *not* want to do is have something totally unrelated nagging me to fix potential bugs in someone else's code. This would be like if you hired some painters to paint your house and they keep bugging you every five minutes that the potholes in the street need to be patched up, that my neighbor really ought to sort his recycling better and my landlord really should have the water heater inspected. Its distracting and it does nothing to get my actual work done. Instead, a course of eduction and contacting the actual authors of the naughty code is in order. You've certainly started in on the former. As for the latter, I suggest doing a Google Perl code search for UNIVERSAL:: and contacting each of the authors. Now for the analysis why putting crusader code into otherwise functional modules is a bad idea: _Modules are supposed to be modular_ They should avoid universal effects or poking around in other namespaces without a damned good reason. If I download a module which does X I do not want it to also launch a Crusade against other installed code. Stay in your box. _You're alerting the wrong person_ If there's a problem with a CPAN module the author of that module should be told, not the users. The users can't do much but report the problem, which in the case of MockObject vs Class::DBI I did. And now I twiddle my thumbs waiting for a patch to be applied. Meanwhile, my tests spew all sorts of warnings that don't indicate any actual problem and I can't do anything more about. _You're annoying the user_ By adding on Crusader Code to a module you're causing annoyance to the users of your module who, as mentioned above, often can't do much about it. _You're annoying LOTS of users_ The solution to any particular mistaken use of UNIVERSAL::isa in a CPAN module is for the author to patch it. Maybe one user reports the bug and provides a patch. One user, one bug report, one patch, one author. In order to effect this change you are spewing warnings at lots and lots of people, many of which can do nothing but report the bug. _You're conflating two behaviors into one module_ I want to use Test::MockObject to mock objects. Scanning my code for mistaken uses of UNIVERSAL::isa is another thing entirely that I may or may not want to do. By bolting the two together it becomes impossible to do one without the other. This lowers the utility of MockObject. _You can break other people's code_ By mucking with other people's code you potentially *break* that code. By *silently* changing the way isa() works, or in Eric's case deleting a $SIG{__DIE__} handler, any mistake you make can now break lots of other totally unrelated code. Silently, unexpectedly and very difficult to debug because nobody would think that loading MockObject would have anything to do with Class::DBI (I didn't). As UNIVERSAL::isa and can have had and currently do have bugs (I can't even get UNIVERSAL::isa to warn) you take what should be the safe action of loading a module and turn it into a potential bomb for the whole system.
Re: Why UNIVERSAL::(can|isa) Warn (was Re: using $SIG{__DIE__} correctly (if you must))
On Tuesday 27 February 2007 00:13, Michael G Schwern wrote: If that were so it would only warn when a MockObject is looked at using UNIVERSAL::isa/can() as a function. You really ought to read the code, especially the part where Test::MockObject and UNIVERSAL::isa and UNIVERSAL::can are separate modules. The previous paragraph is brought to you by the word decoupled and the letters Q and A. That would cover the utility of warning a user about a possible problem using mocked objects without launching a UNIVERSAL::isa crusade. As it is it warns on *any* use of UNIVERSAL::isa() as a function, mocked object or no (although right now UNIVERSAL::isa appears to not warn at all). Yes, that's what UNIVERSAL::isa and UNIVERSAL::can do. They attempt to work around the damage of using base methods as functions and warn about them. Test::MockObject and Test::MockObject::Extends use both other modules because that anti-pattern tends to break mock objects. It tends to break other types of code too, which is why they are separate modules. The previous three paragraphs are brought to you by the words modularity and generalization and the letters O, O, and P. When I'm programming on a project I want to work on that project. What I do *not* want to do is have something totally unrelated nagging me to fix potential bugs in someone else's code. When I'm programming on a project, I want the rest of the code to work and not generate strange failures. Instead, a course of eduction and contacting the actual authors of the naughty code is in order. You've certainly started in on the former. As for the latter, I suggest doing a Google Perl code search for UNIVERSAL:: and contacting each of the authors. That didn't work. Chris Dolan, I believe, had an interesting conversation with Andy Wardley over strange Template Toolkit failures with Test::MockObject. I believe this was also pre-UNIVERSAL::isa. Even Ben Tilly, dispenser of voluminous wisdom on Perl Monks, still seems to believe that can() is a method not worth supporting because some people might not use it correctly. Now for the analysis why putting crusader code into otherwise functional modules is a bad idea: _Modules are supposed to be modular_ They should avoid universal effects or poking around in other namespaces without a damned good reason. If I download a module which does X I do not want it to also launch a Crusade against other installed code. Stay in your box. UNIVERSAL::isa and UNIVERSAL::can are separate modules. They don't know the internals of Test::MockObject nor any other code that might want to use them. This is on purpose. _You're alerting the wrong person_ If there's a problem with a CPAN module the author of that module should be told, not the users. The users are the ones who will encounter the bugs when, as just one example, Test::MockObject falls prey to someone else's buggy code. _You're annoying the user_ By adding on Crusader Code to a module you're causing annoyance to the users of your module who, as mentioned above, often can't do much about it. They can report the bug, much as they would have to do if they encountered it in practice. However: 1) UNIVERSAL::isa and UNIVERSAL::can work around the bug 2) The warnings are merely warnings, not crashings and errors, as the bug would be 3) The warnings do their best to identify exactly *where* the bug is, which beats trying to figure out weird crashes all to pieces _You're annoying LOTS of users_ The solution to any particular mistaken use of UNIVERSAL::isa in a CPAN module is for the author to patch it. Maybe one user reports the bug and provides a patch. One user, one bug report, one patch, one author. In order to effect this change you are spewing warnings at lots and lots of people, many of which can do nothing but report the bug. Yet these bugs aren't getting fixed. It seems to me that there's a different problem somewhere else. Exactly how long have we been talking about UNIVERSAL::isa and UNIVERSAL::can *not* being functions? Years! Years!! If I thought evangelism alone would work, I'd stick to that. If I thought piling workaround upon workaround would work, I'd do that too, but I'm not a PHP programmer with a security hole. _You're conflating two behaviors into one module_ Again, you really ought to read the code. I want to use Test::MockObject to mock objects. Scanning my code for mistaken uses of UNIVERSAL::isa is another thing entirely that I may or may not want to do. By bolting the two together it becomes impossible to do one without the other. This lowers the utility of MockObject. Yeah, it really SUCKS that Test::MockObject has a chance of working despite bugs in other people's software. The refund line is --- over there, right under the You're WELCOME! sign. _You can break other people's code_ By mucking with other people's code you potentially *break* that code. By
Re: using $SIG{__DIE__} correctly (if you must)
# from Michael G Schwern # on Monday 26 February 2007 09:20 pm: breaking broken code is easier than accounting for ignorance with the unfortunate side-effect that the user learns something. The ignorance goes away and balance is restored. Again, you're assuming the user here to be the author of the naughty code in question. Or that you can write code which knows what's naughty and what's intended. I say that most of the time such vigilante coding will only bother 3rd parties who use your vigilante module in conjunction with someone else's code. There's nothing vigilante about writing code that assumes other code will behave properly. If I were going to put something on CPAN that messed with __DIE__ hooks, it would only be an audit module. I'm certainly not going to put delete($SIG{__DIE__}) at the beginning of every module either (take a joke -- it saves typing.) I will, however, refuse to say local $SIG{__DIE__} inside of every eval just because *maybe* *somebody* did *something* wrong *somewhere*. The user has every right to shoot themselves in the foot however they see fit. Your CPAN module is going to break other CPAN modules and the poor sap using them who didn't write any of it is going to have no idea why. You're placing the blame in the wrong place. Modules which rely on a poorly-implemented $SIG{__DIE__} are going to break anyway. I'm just saying we should all leave the slack in the rope and not walk on eggshells. If the poor sap (though I tend to give Perl programmers more credit than that) wants to send me an e-mail questioning why I would be so bold as to use eval, I'll happily diagnose the problem and send them in the right direction. --Eric -- Insert random misquote here --- http://scratchcomputing.com ---
Re: Why UNIVERSAL::(can|isa) Warn (was Re: using $SIG{__DIE__} correctly (if you must))
On Tuesday 27 February 2007 13:42, Michael G Schwern wrote: This handily solves your stated purpose of warning the user about MockObjects not being used because of UNIVERSAL::isa mistakes WITHOUT warning the user about EVERY mistaken use of UNIVERSAL::isa. $ perldoc perllexwarn -- c
Re: using $SIG{__DIE__} correctly (if you must)
Eric Wilhelm wrote: There's nothing vigilante about writing code that assumes other code will behave properly. If I were going to put something on CPAN that messed with __DIE__ hooks, it would only be an audit module. Oh good. I will, however, refuse to say local $SIG{__DIE__} inside of every eval just because *maybe* *somebody* did *something* wrong *somewhere*. The user has every right to shoot themselves in the foot however they see fit. Unfortunately your foot is on top of theirs because its 50/50 as to who the user is going to email with the bug. That said, I only bother with this level of bulletproofing in things like Test::Builder and you're glad I do. Your CPAN module is going to break other CPAN modules and the poor sap using them who didn't write any of it is going to have no idea why. You're placing the blame in the wrong place. Modules which rely on a poorly-implemented $SIG{__DIE__} are going to break anyway. I'm just saying we should all leave the slack in the rope and not walk on eggshells. If the poor sap (though I tend to give Perl programmers more credit than that) wants to send me an e-mail questioning why I would be so bold as to use eval, I'll happily diagnose the problem and send them in the right direction. That's very generous of you.
Re: Why UNIVERSAL::(can|isa) Warn (was Re: using $SIG{__DIE__} correctly (if you must))
chromatic wrote: On Tuesday 27 February 2007 13:42, Michael G Schwern wrote: This handily solves your stated purpose of warning the user about MockObjects not being used because of UNIVERSAL::isa mistakes WITHOUT warning the user about EVERY mistaken use of UNIVERSAL::isa. $ perldoc perllexwarn Yes I'm aware of that. It is lexical thus I cannot say this to switch off the warning for good: no warnings UNIVERSAL::isa; use Test::MockObject; ... I have to patch the code which is calling UNIVERSAL::isa() as a function. Every instance of it in all the code I might use. In the case of a CPAN module it is not my code. I might not even have write access to edit it. Thus it provides no better option for the 3rd party user. It is also the wrong solution when, in most cases, it actually is a mistake to call UNIVERSAL::isa as a function. It would be better to patch the code (if I can and if I have the inclination) then to paper over it. What is wrong with the proof-of-concept I proposed?
Re: Why UNIVERSAL::(can|isa) Warn (was Re: using $SIG{__DIE__} correctly (if you must))
On Tuesday 27 February 2007 13:58, Michael G Schwern wrote: What is wrong with the proof-of-concept I proposed? The lines: my $real_isa = \UNIVERSAL::isa; ... if( ref $obj and eval { $obj-$real_isa(Test::MockObject) } ) { -- c
Re: Why UNIVERSAL::(can|isa) Warn (was Re: using $SIG{__DIE__} correctly (if you must))
On 27/02/07, chromatic [EMAIL PROTECTED] wrote: On Tuesday 27 February 2007 13:58, Michael G Schwern wrote: What is wrong with the proof-of-concept I proposed? The lines: my $real_isa = \UNIVERSAL::isa; ... if( ref $obj and eval { $obj-$real_isa(Test::MockObject) } ) { Why not have something like --- package UNIVERSAL::isa; our %care_about; sub import { my $self = shift; @[EMAIL PROTECTED] = (); } sub isa { my ($obj, $class) = @_; # do correct isa stuff warn my warning if (exists $care_about{$class}) or (exists $care_about{ref $obj}); } *UNIVERSAL::isa = sub \isa; --- then in Test::MockObject; use UNIVERSAL::isa __PACKAGE__; you could even add caller() by default making no different at all. Then you only give a warning when people call UNIVERSAL::isa on your objects, F
Re: Why UNIVERSAL::(can|isa) Warn (was Re: using $SIG{__DIE__} correctly (if you must))
On Tuesday 27 February 2007 14:25, Fergal Daly wrote: Why not have something like --- package UNIVERSAL::isa; our %care_about; sub import { my $self = shift; @[EMAIL PROTECTED] = (); } sub isa { my ($obj, $class) = @_; # do correct isa stuff warn my warning if (exists $care_about{$class}) or (exists $care_about{ref $obj}); } *UNIVERSAL::isa = sub \isa; --- then in Test::MockObject; use UNIVERSAL::isa __PACKAGE__; you could even add caller() by default making no different at all. Then you only give a warning when people call UNIVERSAL::isa on your objects, Yeah, I was thinking about that last night and this morning. It's a little tricky to allow class methods too, but that part works in UNIVERSAL::isa and UNIVERSAL::can right now, so it's doable. -- c
Re: Why UNIVERSAL::(can|isa) Warn (was Re: using $SIG{__DIE__} correctly (if you must))
Fergal Daly wrote: sub isa { my ($obj, $class) = @_; # do correct isa stuff warn my warning if (exists $care_about{$class}) or (exists $care_about{ref $obj}); Consider what if $obj is a subclass of the class you care about? That should probably get checked, too, as it too overrides isa(). I believe its going to have to be... sub _do_i_care { my $obj = shift; for my $class (keys %care_about) { return 1 if $obj-isa($class); } return 0; } I'm hand waving over the part where isa() might go into a deep recursion back into UNIVERSAL::isa(). An alternative is to care about any object or class which overrides isa(). sub _do_i_care { my $thing = shift; my $isa = $thing-can(isa); return 1 if $isa ne \UNIVERSAL::isa; } Again, hand waving over possible deep recursion into UNIVERSAL::can().
Re: using $SIG{__DIE__} correctly (if you must)
* Michael G Schwern [EMAIL PROTECTED] [2007-02-27 06:25]: $SIG{__DIE__} = sub { # We don't want to muck with death in an eval, but $^S isn't # totally reliable. 5.005_03 and 5.6.1 both do the wrong thing # with it. Instead, we use caller. This also means it runs under # 5.004! my $in_eval = 0; for( my $stack = 1; my $sub = (CORE::caller($stack))[3]; $stack++ ) { $in_eval = 1 if $sub =~ /^\(eval\)/; } ... }; That's how you do it right and maintain any sort of backwards compatibility. Owh goodness aragh *twitch* Together with the contortions required to safely examine $@ after an eval I’m getting tempted to put Unbreak::Eval on the CPAN. -- *AUTOLOAD=*_;sub _{s/(.*)::(.*)/print$2,(,$\/, )[defined wantarray]/e;$1} Just-another-Perl-hack; #Aristotle
Re: using $SIG{__DIE__} correctly (if you must)
A. Pagaltzis wrote: * Michael G Schwern [EMAIL PROTECTED] [2007-02-27 06:25]: $SIG{__DIE__} = sub { # We don't want to muck with death in an eval, but $^S isn't # totally reliable. 5.005_03 and 5.6.1 both do the wrong thing # with it. Instead, we use caller. This also means it runs under # 5.004! my $in_eval = 0; for( my $stack = 1; my $sub = (CORE::caller($stack))[3]; $stack++ ) { $in_eval = 1 if $sub =~ /^\(eval\)/; } ... }; That's how you do it right and maintain any sort of backwards compatibility. Owh goodness aragh *twitch* Together with the contortions required to safely examine $@ after an eval I’m getting tempted to put Unbreak::Eval on the CPAN. I was poking around in CGI::Carp and found this: # The mod_perl package Apache::Registry loads CGI programs by calling # eval. These evals don't count when looking at the stack backtrace. sub _longmess { my $message = Carp::longmess(); $message =~ s,eval[^\n]+(ModPerl|Apache)/(?:Registry|Dispatch)\w*\.pm.*,,s if exists $ENV{MOD_PERL}; return $message; } sub ineval { (exists $ENV{MOD_PERL} ? 0 : $^S) || _longmess() =~ /eval [\{\']/m }
Re: using $SIG{__DIE__} correctly (if you must)
On 2/27/07, A. Pagaltzis [EMAIL PROTECTED] wrote: Owh goodness aragh *twitch* Together with the contortions required to safely examine $@ after an eval I'm getting tempted to put Unbreak::Eval on the CPAN. Please do. Did David Golden ever send his $@ examining snippet to you? It did about the same thing so the multiple possible errors all got captured. Josh
Re: using $SIG{__DIE__} correctly (if you must)
On 2/27/07, Joshua ben Jore [EMAIL PROTECTED] wrote: On 2/27/07, A. Pagaltzis [EMAIL PROTECTED] wrote: Owh goodness aragh *twitch* Together with the contortions required to safely examine $@ after an eval I'm getting tempted to put Unbreak::Eval on the CPAN. Please do. Did David Golden ever send his $@ examining snippet to you? It did about the same thing so the multiple possible errors all got captured. Damn. That was intended to be private. Good thing it wasn't anything damning. Josh
Re: using $SIG{__DIE__} correctly (if you must) (was: Object Identification Cold War and the return of autobox.pm)
# from Michael G Schwern # on Monday 26 February 2007 01:50 pm: And then someone defined a $SIG{__DIE__} so now its C{ local $SIG{__DIE__}; eval { $obj-isa($class) } } No. If that $SIG{__DIE__} doesn't check $^S, then it's just delete($SIG{__DIE__}) and you're back to eval {$obj-isa($class)} and balance is restored. --Eric -- So malloc calls a timeout and starts rummaging around the free chain, sorting things out, and merging adjacent small free blocks into larger blocks. This takes 3 1/2 days. --Joel Spolsky --- http://scratchcomputing.com ---
Re: using $SIG{__DIE__} correctly (if you must)
Eric Wilhelm wrote: # from Michael G Schwern # on Monday 26 February 2007 01:50 pm: And then someone defined a $SIG{__DIE__} so now its C{ local $SIG{__DIE__}; eval { $obj-isa($class) } } No. If that $SIG{__DIE__} doesn't check $^S, then it's just delete($SIG{__DIE__}) and you're back to eval {$obj-isa($class)} and balance is restored. You don't want to delete someone else's $SIG{__DIE__}. And how can you know if it checks $^S (most don't)? Or was that a round-about way to say you should always check $^S in your $SIG{__DIE__} which would be great but nobody does which brings me right back to it shouldn't be so hard to do it right!
Re: using $SIG{__DIE__} correctly (if you must)
# from Michael G Schwern # on Monday 26 February 2007 03:29 pm: Eric Wilhelm wrote: # from Michael G Schwern # on Monday 26 February 2007 01:50 pm: And then someone defined a $SIG{__DIE__} so now its C{ local $SIG{__DIE__}; eval { $obj-isa($class) } } No. If that $SIG{__DIE__} doesn't check $^S, then it's just delete($SIG{__DIE__}) and you're back to eval {$obj-isa($class)} and balance is restored. You don't want to delete someone else's $SIG{__DIE__}. No, I do. Why would anyone else's $SIG{__DIE__} be in my code? Now, maybe you're going to say that someone might use my module and be upset because their broken $SIG{__DIE__} is broken. And how can you know if it checks $^S (most don't)? Maybe some juggling of exit and die. Hmm, sounds like a job for chromatic. Acme::OhNoYouDidn::t? Or, you could just curry it into a sub that does check $^S if you wanted to be safe and weren't concerned about the call stack. Or you could always just walk down the hall and tell whoever wrote it to fix it. Or was that a round-about way to say you should always check $^S in your $SIG{__DIE__} Yeah. No, I don't actually delete it. But if you're having problems, delete() may well be the answer. which would be great but nobody does which brings me right back to it shouldn't be so hard to do it right! Why doesn't anybody do it right? Yes, the docs say that it was an accident that $SIG{__DIE__} gets called from within an eval and that may be fixed in the future. But, it's very clear in both perlvar and perlfunc#die, so why bother with the eval {local $SIG{__DIE__}; ...} mess? Just cause broken code to break instead of working around it. --Eric -- Anyone who has the power to make you believe absurdities has the power to make you commit injustices. --Voltaire --- http://scratchcomputing.com ---
Re: using $SIG{__DIE__} correctly (if you must)
# from Michael G Schwern # on Monday 26 February 2007 05:53 pm: Put another way... be lax in what you accept, strict in what you output. That's a different subject having more to do with piped text than code (if anybody in this case is being strict about acceptance here, it's perl) and even if it weren't, that philosophy can only go so far. What we have here is more a case of walking on eggshells, doing various preventative things in case somebody 'd. How many cases can you account for? And, is it worth the loss of an idiom to try to sweep this flaw under the rug? Also this: eval { delete $SIG{__DIE__}; $obj-isa($class) } is no shorter than this: eval { local $SIG{__DIE__}; $obj-isa($class) } To be clear (since I must not be funny enough), the delete() bit was a joke. This is much shorter than both: eval {$obj-isa($class)} Or you could always just walk down the hall and tell whoever wrote it to fix it. That's a long bloody hall you've got there for CPAN code. I would hope to not find many modules on CPAN that install such a thing. It's global, so whoever wrote $0 gets to decide what to do with it. That's a pretty short hall in most sane situations. And how do you know the user didn't intend it to run even if its in an eval? The bit about it might be fixed later implies that this intention would eventually lead to disappointment anyway. But, it's very clear in both perlvar and perlfunc#die, so why bother with the eval {local $SIG{__DIE__}; ...} mess? Just cause broken code to break instead of working around it. BECAUSE WE ALL THROUGHLY STUDY THE DOCUMENTATION, RIGHT?! Yeah. Thoroughly study? It apologizes about the brokenness (in both places) before it even explains how to use it! People do it wrong because its easier to do it that way. And it usually works fine. Most people don't even know about $^S. Hell, even the designers didn't think of it as evidenced by the accidental feature. Doing it slightly wrong but usable is easier than doing it right. That's why nobody does it right. Design failure. Sure it's a design failure. But, breaking broken code is easier than accounting for ignorance with the unfortunate side-effect that the user learns something. The ignorance goes away and balance is restored. To be clear, I totally agree that it is a design failure. To cite a seemingly completely unrelated issue: a buggy reimplementation of require() that is a direct result of not understanding that a bad $SIG{__DIE__} could be fixed to allow eval {require foo} (and possibly not realizing that local $SIG{__DIE__} would be an option.) So, the code in question digs around in @INC to see if it can find a file. Unfortunately, that solution breaks @INC subrefs. So, now we're down an idiom and a feature! If the perpetrator of the die hook in question had just been told too bad, that mess wouldn't have happened. Yeah, it shouldn't suck that much and ruby should be faster and perl 6 should be out by now and python should just exit instead of suggesting that maybe you meant Ctrl-D. --Eric -- The only thing that could save UNIX at this late date would be a new $30 shareware version that runs on an unexpanded Commodore 64. --Don Lancaster (1991) --- http://scratchcomputing.com ---
Re: using $SIG{__DIE__} correctly (if you must)
Eric Wilhelm wrote: Also this: eval { delete $SIG{__DIE__}; $obj-isa($class) } is no shorter than this: eval { local $SIG{__DIE__}; $obj-isa($class) } To be clear (since I must not be funny enough), the delete() bit was a joke. This is much shorter than both: eval {$obj-isa($class)} You seem to be saying everyone should fix their shit which I would love to see happen. Meanwhile, you've got to deal with broken or impolite shit. Fortunately, since most folks localize their __DIE__ handlers, this usually isn't a concern except to authors of really widely used modules. But, it's very clear in both perlvar and perlfunc#die, so why bother with the eval {local $SIG{__DIE__}; ...} mess? Just cause broken code to break instead of working around it. BECAUSE WE ALL THROUGHLY STUDY THE DOCUMENTATION, RIGHT?! Yeah. Thoroughly study? It apologizes about the brokenness (in both places) before it even explains how to use it! I still hold that even if folks have read the docs on this subject, and not everyone learns $SIG{__DIE__} by studying perlvar, they don't remember it. I usually forget about it. Its simply not a day-to-day concern and there's just too many damned exceptions to keep in mind. And then there's still my assertion that until 5.8, $^S is not reliable. So even if you wanted to do it right it doesn't work! $SIG{__DIE__} = sub { # We don't want to muck with death in an eval, but $^S isn't # totally reliable. 5.005_03 and 5.6.1 both do the wrong thing # with it. Instead, we use caller. This also means it runs under # 5.004! my $in_eval = 0; for( my $stack = 1; my $sub = (CORE::caller($stack))[3]; $stack++ ) { $in_eval = 1 if $sub =~ /^\(eval\)/; } ... }; That's how you do it right and maintain any sort of backwards compatibility. People do it wrong because its easier to do it that way. And it usually works fine. Most people don't even know about $^S. Hell, even the designers didn't think of it as evidenced by the accidental feature. Doing it slightly wrong but usable is easier than doing it right. That's why nobody does it right. Design failure. Sure it's a design failure. But, breaking broken code is easier than accounting for ignorance with the unfortunate side-effect that the user learns something. The ignorance goes away and balance is restored. Again, you're assuming the user here to be the author of the naughty code in question. Or that you can write code which knows what's naughty and what's intended. I say that most of the time such vigilante coding will only bother 3rd parties who use your vigilante module in conjunction with someone else's code. Your CPAN module is going to break other CPAN modules and the poor sap using them who didn't write any of it is going to have no idea why. Case in point... my tests started suddenly warning about UNIVERSAL::isa called as a function in Class::DBI. After spending a bunch of time trying to figure out what the hell was going on and if Redhat introduced some new warning or something I finally discover that Test::MockObject uses UNIVERSAL::isa() which warns if *anyone* calls UNIVERSAL::isa() as a function. Its nagging *me*, the unrelated 3rd party, about problems in someone else's code that I don't have control over! Finally, if I download a module to do X I expect it to do X and not try to Cure The Ills of the World. Just as Test::MockObject should be about mock objects and not about Spreading The Word about UNIVERSAL::isa(), your module should not be about smiting others for using $SIG{__DIE__} improperly. If you want to Cure The Ills Of The World contact the authors directly and provide a patch. To be clear, I totally agree that it is a design failure. To cite a seemingly completely unrelated issue: a buggy reimplementation of require() that is a direct result of not understanding that a bad $SIG{__DIE__} could be fixed to allow eval {require foo} (and possibly not realizing that local $SIG{__DIE__} would be an option.) So, the code in question digs around in @INC to see if it can find a file. Unfortunately, that solution breaks @INC subrefs. So, now we're down an idiom and a feature! If the perpetrator of the die hook in question had just been told too bad, that mess wouldn't have happened. Having written such things, yes its very hard to get all the tiny little nuances right. I know I've got stuff that blows up with code refs in @INC. UNIVERSAL::require probably has all sorts of interesting edge cases. Right now I'm teasing apart the code in Test::More to deal with overloaded objects which don't implement stringify. It sucks. Yeah, it shouldn't suck that much and ruby should be faster and perl 6 should be out by now and python should just exit instead of suggesting that maybe you meant Ctrl-D. Whoa there, boy. Ease down.
Why UNIVERSAL::(can|isa) Warn (was Re: using $SIG{__DIE__} correctly (if you must))
On Monday 26 February 2007 21:20, Michael G Schwern wrote: Case in point... my tests started suddenly warning about UNIVERSAL::isa called as a function in Class::DBI. After spending a bunch of time trying to figure out what the hell was going on and if Redhat introduced some new warning or something I finally discover that Test::MockObject uses UNIVERSAL::isa() which warns if *anyone* calls UNIVERSAL::isa() as a function. Its nagging *me*, the unrelated 3rd party, about problems in someone else's code that I don't have control over! No, it's warning you that if Test::MockObject doesn't work, that it's not *my* problem. It's also telling you exactly *where* that problem is. As much as I'd like to fix the real problem (the belief that enforcing structural subtyping makes any sense), the best I can do is try to work around the damage while not sweeping it under the rug. I can't see how ignoring the problem gets it fixed. -- c