Stevie-O has asked for the wisdom of the Perl Monks concerning the following question:

In a perl script, you can do this;
use strict; # hacksym('name', ref) # e.g. hacksym('foo', \@bar) makes @foo an alias for @bar sub hacksym { my $name = shift; my $ref = shift || die "need a reference!"; no warnings 'uninitialized'; no strict 'refs'; *{$name} = $ref; }
The 'no warnings' and 'no strict' have lexical scope; they are in effect only until the enclosing block ends. However, when I tried this:
(beware, this contains syntax that may frighten small children)
package Bling; use strict qw(vars subs); use warnings; # simply put: use Bling; then, whenever your script accesses $$, # it prints 'Bling Bling!!'. my $ref; sub import { unless (defined $ref) { $ref = \${'main::$'}; undef *{'main::$'}; # tramples @$ and %$. I really don't ca +re. tie ${'main::$'}, 'Bling::Bling'; } } sub unimport { if (defined $ref) { untie ${'main::$'}; *{'main::$'} = $ref; undef $ref; } } package Bling::Bling; sub TIESCALAR { bless [], shift; } sub FETCH { local $\; print "Bling Bling!!\n"; $$ref; } 1;
#!/usr/bin/perl -l # blingtest.pl use Bling; $x=$$; print '$x is ', $x; { no Bling; $y=$$; print '$y is ', $y; } print '$$ is ', $$;
The result is that no 'Bling Bling!!'s are printed, because the 'no Bling' is not lexically scoped. My question is this: Is it possible to achieve 'lexicality' of use/no in my own modules, just like strict.pm and warnings.pm do?
--Stevie-O
$"=$,,$_=q>|\p4<6 8p<M/_|<('=> .q>.<4-KI<l|2$<6%s!<qn#F<>;$, .=pack'N*',"@{[unpack'C*',$_] }"for split/</;$_=$,,y[A-Z a-z] {}cd;print lc

Replies are listed 'Best First'.
Re: Lexical use/no Module?
by Abigail-II (Bishop) on Jan 29, 2004 at 01:57 UTC
    The answer is no. Pragma's like strict and warnings set special bits in $^H, which will cause the lexical scopiness.

    Note also that strict and warnings don't mess with the symbol table, nor do they mess with global variables (except those dedicated to them, like $^H).

    Abigail

Re: Lexical use/no Module?
by stvn (Monsignor) on Jan 29, 2004 at 02:48 UTC

    Of course there is nothing to stop you from just mangling the symbol table at runtime. It is not a specifically compile time practice. (Come on try it,.. all the cooool kids are doing it) And with a little creativity and just the right amount of insanity you could make this work.

    I saw this trick in Hook::LexWrap, by TheDamian, its quite simple really and very elegant. The code would look something like this:

    use Bling; $x = $$; ## Bling Bling as before { my $no_bling = Bling->off(); $y = $$; ## no Bling Bling } $z = $$; ## Bling Bling as before
    The magic (oooohhhh spooky) is that the variable $no_bling is lexically scoped. It is also an object instance. When the object is created in Bling->off() it unties $$. The DESTORY method of the object instance then re-tie's $$. Since DESTROY will get called at the close of the block,... whalla,.. you get lexically scoped insanity.

    If you dont like the Bling->off() syntax, then you could try something witty with the indirect object syntax. buh_bye Bling or something like that. (although you can't use "no" cause perl will confuse it with the real "no")

    Of course, no one in their right mind would do such a thing. No no,.. never,... never ever,.. no ,.. stop,.. dont make me,.. nooooooooooo......

    -stvn

    Disclaimer: In no way does this post consitute an endorsement of the practice of mangling perl's global variables. Bad,.. very very Bad.

      Ahh, a most interesting idea.

      And as for your disclaimer, I'd be surprised to find someone who *would* promote hacking the symbol table. But I like to boldly go where no man has gone before (or do I rush in where angels fear to tread?). I even once replaced UNIVERSAL::can ;) Stevie-O's scratchpad

      --Stevie-O
      $"=$,,$_=q>|\p4<6 8p<M/_|<('=> .q>.<4-KI<l|2$<6%s!<qn#F<>;$, .=pack'N*',"@{[unpack'C*',$_] }"for split/</;$_=$,,y[A-Z a-z] {}cd;print lc
        Stevie-O

        Don't get me wrong, I love hacking the symbol table. Personally, I tend to do it more often than I should as well. What I do not advocate however, is messing around with Perl's global variables ($$ in your example). I assume you used it as an example only, since it's doubtful that having your program print "Bling Bling" everytime you try to find out the process id is really what you are going for.

        Personally I never thought symbol tables were all that complex or magical. Its just a bunch of hashes which represents a heirarchy of namespaces. Different paradigm than "normal" maybe but magical, ... nah not so much :)

        -stvn

      The problem is, Hook::LexWrap isn't actually lexically scoped. As Dominus says in his proposal, Hook::LexWrap is lying (which isn't to say it's a bad module at all, it's just not *quite* lexically scoped).

      For example,

      { my $lexical = wrap 'some_sub', pre => \&wrapper; some_sub();#wrapper is called before some_sub other_sub();#other_sub's call to some_sub is *still* #wrapped with &wrapper, even though other_sub is #outside of this lexical scope! } sub other_sub { some_sub();#call made outside of lexical scope in which some_sub is +wrapped. }
      Basically, theres' no good way to implement truly lexically-scoped modules right now.

      However:

      Dominus is working to change this. Here's the HTMLified POD from his proposal patch for Proper Lexical Pragma Modules.:



      Once it's Turing complete, everything else is just syntactic sugar.

        Quite true. But then again, one would need to be insane to actually do something like this and expect it to behave nicely. And short of kidnapping Dominus and forcing him to patch and recompile your version of perl, its the next best thing. And I quote myself:

        Of course, no one in their right mind would do such a thing. No no,.. never,... never ever,.. no ,.. stop,.. dont make me,.. nooooooooooo......

        -stvn
Re: Lexical use/no Module?
by ysth (Canon) on Jan 29, 2004 at 18:48 UTC
    You can get lexical scoping of pragmas by using %^H and $^H (which see), but there are some problems with doing that currently; the most significant is that you only have access to the correct scoped setting at compile-time (e.g. within the scope of a use foo or no foo code run at compile time will be able to tell which of use or no was in effect, but not at run-time.

    This has been pretty high on the list of things it would be nice to clean up in perl5. Dominus has done some work toward cleaning this up. See his grant proposal for more information (though the 5.8.2 obviously doesn't apply, and I'm not sure this would belong in a maintenance release, anyway). Last I heard, he was hoping to work on this more by April '04.

    Yes, I know I've complained at others using %^H, but that was for a specific case for which there is a documented stable interface; there isn't a general interface yet to %^H because (IMO) the existing support for user pragmas isn't good enough to justify one. Still, one needs to be aware that %^H may vanish from future releases.