Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

RFC: feature proposal re code in @INC

by blazar (Canon)
on Jan 26, 2006 at 11:47 UTC ( #525698=perlmeditation: print w/ replies, xml ) Need Help??

Premise

One of my favourite 'tricks'1 is the possibility of putting code in @INC, as explained in perldoc -f require. Now, the standard way to use it is to return an open filehandle to the wanted module, e.g.

#!/usr/bin/perl use strict; use warnings; use lib sub { my $wanted=pop; return undef if $wanted ne 'Foo.pm'; open my $fh, '<', \<<'.EOM' or die "D'Oh! $!\n"; # ---- Begin package code. use strict; use warnings; package Foo; use base 'Exporter'; our @EXPORT='bar'; sub bar { print "Hmmm, seems to work!!\n"; } 1; __END__ .EOM # ---- End package code. $fh; }; use Foo; bar; __END__

(Although in this form looks more like obfuscation than a Good Thing™ ;-)

The proposal

Now, it occurred to me that even if, as usual, there are many other ways to do what I'm about to propose, one may want to use this feature to "alias" a package (or better, a set of packages at a time) by modifying $_[1] (in the case of the sub or array form of this 'trick') - and returning undef to let the default mechanism continue the search in the standard locations. But this is not currently possible:

$ perl -le 'use lib sub {$_[1]="Foo.pm"; undef}; use Anything;' Modification of a read-only value attempted at -e line 1. BEGIN failed--compilation aborted at -e line 1.

So I wonder if $_[1] could be made not read-only instead.

I understand that there may be inherent risks in doing so, but

  1. I don't see many options for one to inadvertently modify $_[1];
  2. the rationale should be that this is a somewhat "advanced" anyway so if one is using it, then he's supposed to know what it's doing.

1 See e.g.:

Comment on RFC: feature proposal re code in @INC
Select or Download Code
Re: RFC: feature proposal re code in @INC
by diotalevi (Canon) on Jan 26, 2006 at 14:44 UTC

    Try this. It does something but I'm not sure what.

    @_ = ( $_[0], "Whatever.pm" );

    PS, if you change the value from read-only, you'll probably be modifying the optree. That's usually a bad idea.

    ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

      I'm not sure if I understand your proposal, which is probable, given your hacking skills. However I don't want to force $_[1] to hold "Whatever.pm" for use in the same sub - I want it to be modified as a side-effect of the sub having been called, and I don't want to change the value from read-only either: I "want" it not to be read-only in the first place.

      I was thinking of something along these lines: suppose that one writes some modules in different versions for some different OSen (OK: as I premised since the beginning, I know there are other ways to do this), well if she had this feature available then she may do something like:

      use lib sub { for (qw/Foo.pm Bar.pm Baz.pm/) { if ($_[1] eq $_) { $_[1] =~ s/\./-$^O./; last; } } # let perl go on searching the 'faked' .pm! undef; };

      (There are probably better examples.)

      I admit that this opens an ambiguity as to what should be shown in case the modified module can't be found: is it, say, Foo.pm or Foo-linux.pm that can't be found? Probably, both, I would say: the error message may report both the original name and the "current" (at failure time) one, if they differ.

        Gawds. Use some mundane magic for once. This @INC hackery sucks when used for things like this. Instead of "crecent wrench" you're pulling out the "hyper-spacial quantum vortex thingie with extra nubbly attachment." I loathe your example.

        BEGIN { eval "use Foo-$^O; 1" or die $@; }

        ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

        I can imagine that someone could come up with a good way to use this feature. For example, in chaining with other code refs. I'm not entirely sure how that would work, but someone might be able to get it to work.

        However, I'm pretty sure this particular example would breed nothing but headache and heartache - there is no fallback mechanism here to allow you to say that if Foo-linux.pm doesn't exist, Foo.pm will be fine. Or, if it isn't fine, to print out a usable error message. Because as the user, I'd probably be confused by any error message referencing "Foo-linux.pm" when I had a "use Foo" in my code without some sort of extra information on my screen.

        Instead, I would suggest that code that is intended to stack probably should be made into objects that have an INC method (see require). Someone may write a generic "extract from tarball" INC object. If you want to change the name you get from the tarball, you can write your own INC object that wraps the tarball INC object, and changes the name on the way through.

        (Note that before looking this up during the writing of this node, I wasn't even aware of INC objects...)

Re: RFC: feature proposal re code in @INC
by Anonymous Monk on Jan 26, 2006 at 15:52 UTC
    *sigh* Perl just keeps getting bigger and bigger. Every version of perl is yet another language, isn't it? With yet another way to subtlely make the code look like it's doing one thing, and yet really be doing another, all in the name of job security.

    Now I have to watch out for code cowboys screwing things up with wierd @INC modifiers, on top of all the other dirty tricks they like to pull with ties and closures and evals, hidden like rats in their 1000 line subroutines. :-(

    Life sucks.

    --
    Ytrew

      "watch out for"? What does that mean? The whole coderef-in-@INC thing is a tool fit for a few specific purposes. If you don't need it, just don't use it?

      (ties and closures and evals, oh my!)

        watch out for"? What does that mean? The whole coderef-in-@INC thing is a tool fit for a few specific purposes. If you don't need it, just don't use it?
        (ties and closures and evals, oh my!)

        I don't. I usually try to write code that's clear, simple, obvious, and provably correct.

        I do, however, have to maintain code written by other people. The more wierd corners the language has, the more places for them to hide bugs on me! Sure, you shouldn't hide code in @INC without a good reason, but that's no reason to assume people won't. Remember, many coders adopt worst practices for job security. Unfortunately, the messes they leave behind last years after they're gone.

        The bottom line is, for every new feature you add to the language, that's just one more thing I have to check for when I'm debugging to see why someone else's program just broke. Before, I had to make sure @INC had the right module; now I have to verify that some weasly twit hasn't snuck some code in there for no good reason; and made my bugfix fail because of it!

        I mentioned ties, closures, and evals not because they're bad when used wisely, but because they're miserable to deal with when badly applied. Which they are. Repeatedly and frequently badly applied. :-( --
        Ytrew

      Well, I wouldn't put ties and closures on the same level as evals, especially if you mean string-eval.

      Said this, Perl's nature is intrinsically that of a polymorphic, complex, dynamic language with a rich syntax and semantic. You have to live with that! And generally Perl aficionados do like it too! Or else you may try to choose a simpler alternative. (Pssst! Don't tell anyone, but I think that io is very cool - if only I had some spare time I'd like to learn something more about it1)


      1 Of course the fact that it has a simple, consistent syntax, and that it has no keywords doesn't automatically make you an expert programmer...

        Well, I wouldn't put ties and closures on the same level as evals, especially if you mean string-eval.

        They're all potentially evil. Try working with code like this. What does it do?

        $x = $h { foo($y) }; $z = &$x( $a ); eval $z if ( $b );

        I don't even know; and I invented this example. :-)

        Note that for large hashes and complex, 1000 line functions with obscure return values, you won't really know what that code actually does; it's very hard to figure out what's going on, until runtime (and sometimes not even then -- we've got a special abstraction layer that re-implements a turing machine in software. Don't ask! And the system's too slow! Gof figure!). Welcome to my world. :-(

        Note also that if $h is a tied hash, it can change the values of $a and $b. Heck, it could even change the meaning of the code to be evaluated in $z.

        Perl's nature is intrinsically that of a polymorphic, complex, dynamic language with a rich syntax and semantic.

        It's been growing every more complex every year for the last ten years; and I felt had too much unnecessary complexity back in 1996. Expanding the language rather than cleaning it up and simplifying the messy parts hardly seems a winning propositon to me. It feels like we've been doing a nosedive in wrong direction... and I worried that Perl 6 is mostly cool new features, without concern for how they'll be (mis)used.

        You have to live with that!

        Maybe, but I don't have to like it. :-( And it takes a massive amount of lobbying effort to get management to change languages, so I'm probably stuck with Perl; a fringe language like Io will need greater support (and much better documentation) before I'll be allowed to code in it/learn it.
        --
        Ytrew

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (8)
As of 2014-12-25 17:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (161 votes), past polls