Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Re^3: on the fly methods

by Rhandom (Curate)
on Feb 27, 2007 at 21:07 UTC ( [id://602388]=note: print w/replies, xml ) Need Help??


in reply to Re^2: on the fly methods
in thread on the fly methods

Sorry to the original thread as we are now a bit off the beaten topic.

Yes. It is a method. It will skip $code's ->isa. It breaks overloading. It also works in 99% of the use cases (probably more) that the general programming population will use and in those cases where somebody has created an object that pretends to be code they can simply pass sub { &$code } and suddenly it works fine. Changing to $code->isa('CODE') in this case would actually break 99% of use cases because it only allows for objects that are CODE (not bare coderefs). I think it is wonderful that Perl 5 (and other languages) can call methods in a more functional form if the need arises.

Using defined &$code almost works but it breaks if a non-coderef reference is passed in. It also doesn't go the full route of supporting overloaded objects so it isn't any more of a solution.
The only thing that "might" be able to handle 100% of cases is something like
use Scalar::Util qw(blessed); my $is_code = blessed($code) ? $code->can('&{}') : ref($code) eq 'CODE +';

UPDATE: - Yup - I missed blessed coderefs which would have to be checked for with eval { defined &$code }. The corrected code might look like
my $is_code = ! blessed($code) ? ref($code) eq 'CODE' : $code->can('&{}') || $code->isa('CODE') # arguably not a good test (bless +{}, 'CODE') || eval { defined &$code }; # arguably bad because it ge +ts called in some contexts


Arguably that isn't all that bad. I'm sure there is probably still a case I'm missing. I do know of a few companies that are still pre-Perl 5.8 and the Scalar::Util::blessed route isn't even an option for them.

Yes. I agree that things can break. Perl 5 has problems in being able to type data or easily (s/easily/succinctly/) detect the type or capabilities of data. There are many things that can break during argument passing in Perl 5. There are basic things that can be done to check for basic types of data. If advanced users want to pass in advanced types, the basic checks won't prohibit them - they just force them to wrap them in more palatable forms. Although many times the "basic" checks I've seen are indeed poorly done and restrict viable options that would otherwise work just fine.

I've probably already gone too far. There are many who feel very strongly about this issue. But the picture painted is usually more severe that is necessary and when presented as a blanket statement hides useful, working use cases.

Often on Perlmonks there is the assumption that one doesn't know what they are doing when they actually do. And of course there are those that assume they know what they are doing when they actually do not.

my @a=qw(random brilliant braindead); print $a[rand(@a)];

Replies are listed 'Best First'.
Re^4: on the fly methods
by chromatic (Archbishop) on Feb 28, 2007 at 00:43 UTC
    Changing to $code->isa('CODE') in this case would actually break 99% of use cases...

    So would changing to fileno $code, but I didn't suggest that either.

    I don't really care if the naive approach satisfies 99% of the use cases for two reasons. First, I've had well-used code on the CPAN for years that tends to break in messy ways when people use quick hacks instead of well-tested, working code. Second, plenty of people pick up on bad idioms and use them without realizing where they fail and what they break. This leads to even more people breaking my code. and complaining to me and I just can't fix the problems.

    I'd love to see a test case for when eval { defined &$code } fails. I couldn't come up with one. I even tried it with overloaded objects.

      Then write a module that provides routines (not methods) that satisfy your exacting standards or stop whining.

      Most of the time when I come across these cases, I find several choices of what to do and none of them are perfect and it isn't easy to figure out if I'm overlooking some bizarre code (such as chromatic's "well-used code on the CPAN" that breaks in the face of the techniques that most people end up using).

      I often punt and use UNIVERSAL::isa( $var, "TYPE" ) and assume that people who do really strange stuff can always just push @ISA, "TYPE" if they need to.

      I can't afford to spend the amount of effort that you would require to support a slightly old version of Perl just to try (and probably fail) to figure out how to get my code to work with that last 1% of weird cases.

      For years I've felt that Perl needed better ways to determine "is this a hash reference" and what we got was more ways to do it and other changes that made none of the ways perfect still. So now we've got lots of not perfect ways and lots of confusion.

      In one case (Data::Diver), I wanted to be extra precise so I resorted to something like eval { my $x= $ref->[0]; 1 } but that can't be used to test for CODE refs (and one can still write objects that don't tollerate such very well, but I really consider such objects broken at this point).

      So I test for CODE refs by using isa() as a function. And I'm sure I'll do that many more times until someone comes up with the obviously better solution. And the following isn't obviouisly better to me:

      ( eval { $ref->can("isa") } || \&UNIVERSAL::isa )->( $ref, "TYPE" )

      because it is dang ugly and I'm not going to type that over and over (and I'm not sure that it is a 100% solution and it took me several tries to even come up with that).

      I've seen people fighting about "isa" and "UNIVERSAL" and "AUTOLOAD" and I've mostly come away with the impression that AUTOLOAD is broken in design and should have instead been designed to return a code ref and there is no perfect solution to this design oversight and there are several conflicting camps about the "right" way to deal with it and I haven't seen a clear winner so I don't write code that assumes any one of those camps.

      So provide the obviously better solution.

      - tye        

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://602388]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (5)
As of 2024-04-24 18:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found