Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

use strict;,$main::, and AUTOLOAD: Why can't we all get along?

by hsmyers (Canon)
on Jul 17, 2002 at 20:24 UTC ( [id://182572]=perlmeditation: print w/replies, xml ) Need Help??

Recently it was pointed out to me by Aristotle that code references and use strict; were not inherently incompatible. Where I had been using &{$_[0]}($_), I could replace that with $main::{$_[0]}($_)! I thought the idea of strict code references was fairly elegant and adopted the idiom on the spot. Now for what Paul Harvey calls, 'the rest of the story'.

It seems that this technique collides with another idiom I use when developing code-- sub AUTOLOAD. At first I thought that the problem was use strict;, but a little testing showed that AUTOLOAD was working as designed, directly invoking a non-existent functions defaulted as they should, no problem. Just not the hash reference! So it seemed that I could either have $main:: and use strict or AUTOLOAD and &{$_[0]}($_) but that I would have to give up AUTOLOAD if I wanted the former.

That sucks!” was my predictable reaction to that little piece of news. But next I remembered TIMTOWTDI! and set about replacing the functionality of AUTOLOAD or more realistically, the functionality that I needed. The result follows. Given an AUTOLOAD like:

sub AUTOLOAD { my $tree = shift; our $AUTOLOAD; print OUT "@@@ $AUTOLOAD(\$tree) @@@\n"; recurse($tree); }
the fix (with a example call) looks like:
sub coderef { if (exists($main::{$_[0]})) { $main::{$_[0]}($_[1]); } else { print OUT "@@@ main::$_[0](\$tree) @@@\n"; recurse($_[1]); } } sub startrule { my $tree = shift; foreach (@$tree) { if ( ref eq 'ARRAY' ) { if ( ref( @$_[0] ) eq 'ARRAY' ) { startrule($_); } else { coderef(@$_[0],$_); } } } }
Certainly not as magical as the real AUTOLOAD but it gives me back the missing feature without much effort and seems a pretty good exchange.

Note: for those who wonder why I didn't stick with my original no strict "refs";, all I can say is that I'm compulsive! I don't like warning messages after a compile and I don't like doing with out use strict;...

--hsm

"Never try to teach a pig to sing...it wastes your time and it annoys the pig."

Replies are listed 'Best First'.
Re: use strict;,$main::, and AUTOLOAD: Why can't we all get along?
by tadman (Prior) on Jul 17, 2002 at 20:59 UTC
    There's some intrinsic humor in the way you're uneasy about turning off reference checking, and yet you're perfectly willing to use AUTOLOAD.

    Instead of turning off references completely, you can just turn them off locally. Like this:
    sub foo { my ($foo_target) = @_; no strict 'refs'; # Up to no good here ${"${foo_target}::foo"}++; }
    So the disengaged ref checking should be localised to that block.

    No warnings. It's a lot easier than wrapping your calls in a "loader".
      True! If it were not for the fact that the $main:: calls are scattered through out about 1000 lines of code I'd buy into your version. Frankly I haven't made up my mind yet about this being paranoid nonsense on my part or a semi-good idea...

      --hsm

      "Never try to teach a pig to sing...it wastes your time and it annoys the pig."
        I think if you've got calls "scattered through" your code, it's time to think about what you're doing. I like to keep my Black Ops-style programming to very small areas, and wherever possible, use intermediate functions to get the goods. In, done, out, and nobody is the wiser.

        One way to avoid using AUTOLOAD is to auto-generate your functions. I've found this to be far more effective and flexible.

        You can do this like so:
        sub maker { no strict 'refs'; foreach my $func (qw[ foo bar baz ]) { *{"Foo::$func"} = sub { $func }; } } maker(); print join(',', Foo::foo(), Foo::bar(), Foo::baz()),"\n";
        Of course, your code is probably much more complex. Still, no warnings, and you can even use closures.
Re: use strict;,$main::, and AUTOLOAD: Why can't we all get along?
by Aristotle (Chancellor) on Jul 18, 2002 at 07:13 UTC

    Again it depends. AUTOLOAD is more for use with object oriented programming; and indeed again strict will not complain if you call a sub as main->$subname($_). Of course the first parameter passed is now the classname, "main" in this case, and your subs will have to accomodate for that, by shifting it off first thing or however you choose to handle it.

    I am slightly irked by the setup as displayed; coderef() is a rather unhelpful name and the distribution of decision making is a bit clumsy IMHO. I'd do something like this:

    sub default_handler { print OUT "@@@ main::$_[0](\$tree) @@@\n"; recurse($_[1]); } sub dispatch { ref $_[0] eq 'ARRAY' ? \&startrule : $main::{$_[0]} || \&default_handler; } sub startrule { my $tree = shift; ref eq 'ARRAY' and dispatch($_->[0])->($_) foreach @$tree; }

    I'm not happy with that either though.. I think a clean solution would require a dispatch mechanism separate from Perl's that does not rely on sub names. No propositions however as right now my brain won't cooperate.

    Also I'm wondering why there are too many locations for tadman's pragma solution to be feasible? After all, you have to add the coderef() call to the same places that you'd have to add no strict 'refs'; to, unless I'm missing something important.

    Quick note with regard to your snippets: you are aware that @$_[0] is actually a single element array slice? Since you want a scalar, you should write that as $$_[0] or $_->[0].

    Makeshifts last the longest.

      In reverse order, sorry about the typo, typically I'm using $_ as a complex array of arrays and get a little sloppy in my notation (hmmm, note to self-- sloppy in this context usually means 'possibly bug-ridden', needs checking). As far as tadman's approach goes, I've no objection other than the additional typing, which come to think of it might actually be a little clearer in terms of what I'm doing-- i.e. self documenting. Sorry you were irked-- I thought a routine that deals with call refs might as well be called that! I like your economy of style though even if you are not happy with the proposed solution.

      --hsm

      "Never try to teach a pig to sing...it wastes your time and it annoys the pig."

        Oh, the being irked was not personal, nothing to be sorry for. I just thought the code was somewhat unclear and proposed what I think might be more readable.

        As far as subroutine naming goes, I prefer to call subroutines after what they do, rather than what they receive (verb vs subject). But that's a whole different can of worms.. :-)

        Makeshifts last the longest.

Re: use strict;,$main::, and AUTOLOAD: Why can't we all get along?
by Abigail-II (Bishop) on Jul 18, 2002 at 11:14 UTC
    I must say, I fail to see what you are argueing in your post.

    First, you say you can replace &{$_ [0]}($_ [1]) with $main::{$_ [0]} ($_ [1]). That's only partially true, it only works if you are in the main package. You are of course still using a soft reference - and the fact that it's not halting compilation may be a bug that will be fix in a next version.

    But then you start talking about AUTOLOAD, and there's where I lost it. What's the relation between AUTOLOAD and the bug exp^W^Wtechnique described above? Do you want to call the function in $AUTOLOAD after you loaded it with the technique above? Why? Isn't that why we have &goto $AUTOLOAD?

    Abigail

      I use AUTOLOAD as a debugging technique to catch as yet un-written code references. It goes away in the production version. The code references come from a parse tree produced as part of a compiler. So from my point of view, this comes down to things that are admittedly cosmetic, but as I pointed out I am somewhat helplessly compulsive hence the problem. Is the un 'Strict' performance of $main:: going away or were you referring to some thing else?

      --hsm

      "Never try to teach a pig to sing...it wastes your time and it annoys the pig."
      Why should $main::{$softref} become subject to stricture? After all, it is an obviously intentional symbolic lookup. If you forbid it, Object->$methodname() would have logically to be forbidden as well, wouldn't it? In fact, Object->method() is a symbolic lookup on a bareword; now things get tricky..

      Makeshifts last the longest.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (4)
As of 2024-04-25 05:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found