Re: Symbolic reference with strict "refs"
by davido (Cardinal) on Aug 17, 2012 at 16:21 UTC
|
What you're really asking is how to write dodgy code in a way that is obscured from strict's view; a way that either the makers of strict didn't think of, or thought of and figured if you're going to that much trouble you must have your reasons. Still dodgy, and maybe even more-so because it does its little dirty deed so quietly that a future maintainer won't have the benefit of the visual cue that no strict 'refs'; provides.
I would opt for the no strict 'refs'; ## no critic (strict) method in the narrowest possible scope.
By the way, there are plenty people who's opinions I respect who will tell you that the crime isn't in writing code that requires no strict 'refs';, but in writing such code unnecessarily and dangerously. Dodgy is when it's used to solve a problem created by poor design. Genius is when it falls into the category of "Making difficult things possible."
I wanted to mention an article that Mark Jason Dominus wrote. We're all familiar with his article that talks about why it's stupid to use a string as a variable name. But he has another gem that gets a little less attention. Here's the snippet that I find interesting.
A programmer posted to comp.lang.perl.misc with an example that manufactured a function name at run time, and then called the function. Many people jumped in to say this was a mistake, some even saying it was a mistake because it caused a strict 'refs' violation. This is nonsense. Violating strict 'refs' is like setting off the fire alarm. It is a warning that something dangerous may be occurring; it is not a problem in itself. The problem is the fire.
What is the fire, the real problem, in this case? I wrote a series of widely-read and often-cited articles about the problems that arise from using values as the names of variables and functions. Before responding to this thread, I read over the articles, checking each problem I mentioned to see if it could occur in the original programmer's code. None of the real problems could actually arise. I said that I was not able to see what the problem was, and asked people to explain it.
...
| [reply] [d/l] [select] |
|
|
no strict 'refs'; ## no critic (strict)
Wow. I mean... Wow.
Clearly, what we need now is a Perl::Critic rule that warns you when you turn off Perl::Critic checking in a way that isn't wise.</sarcasm>
I'm actually a fan of tools that can point out my mistakes. There is a reason I choose the word "mistakes" there and not "misdeeds".
In programming, I've found that trying to prevent people from doing something "bad" by accident can often be a valuable effort. Trying to prevent people from purposefully doing something "bad" usually ends up being a worse idea than the original "bad" thing (that is trying to be prevented).
I can see the power of Perl::Critic being quite valuable when used to prevent accidental mis-steps. I can even see value in an automated tool telling me that I forgot to include "use strict;" in some file of Perl code. RequireUseStrict sounds like that.
I despair for whoever felt it was a good idea to even create the ProhibitNoStrict rule.
The only sane solution here is to simply turn off that rule in whatever configuration the original poster is using. If that rule is turned on by default in any cluster of configuration settings for Perl::Critic, then that should be changed as well.
If ProhibitNoStrict is even kept as part of Perl::Critic, then turning it on should write "Either you're an idiot or your boss is a maniacal control freak of limited skill; probably both" somewhere.
Whoever wrote ProhibitNoStrict, if you thought you were helping inexperienced coders learn some kind of best practice, then please read the original question. The only result was to plant FUD and to encourage working around a stupid test by doing something even more dodgy than the practice originally declared somehow undesirable.
At least there was more justification for the state of things with "/*LINTED*/". I thought we learned the folly of that route long ago. I guess the people writing and using the new Perl 'lint' are probably too young to know anything about the old C 'lint'.
I consider inclusion of "## no critic" to be completely unacceptable in a code review. Perhaps I should write a Perl::Critic policy module to enforce that automatically. What we really need is a tool that forces us to make our code ugly so we all have to look at that noise every time we edit or read the code so we can avoid seeing any complaints if we run the tool.
| [reply] |
|
|
I skimmed the post once and was ready to disagree with you, but you're completely correct. The intent may have been good ("Hey, you should at least look at code which disables strictures to see if it's sensible!"), but there's no way to implement this in Perl::Critic sensibly. It's not a good rule.
| [reply] |
|
|
| [reply] [d/l] [select] |
Re: Symbolic reference with strict "refs"
by tobyink (Canon) on Aug 17, 2012 at 16:23 UTC
|
My advice is no strict 'refs'; ## no critic. strict and perlcritic are meant to be tools that help you. When they are not helping you, you should disable them (in the smallest scope possible); you shouldn't be forced to jump through hoops.
That said, a bit of stash exploration can get you there...
use 5.010;
use strict;
use warnings;
{
package Foo::Bar;
our @ISA = qw(Quux);
}
sub get_isa
{
my $klass = shift;
my $stash = \%::;
for my $part (split '::', $klass)
{
$stash = \%{ *{ $stash->{$part . '::'} } };
}
$stash->{ISA};
}
my $isa = get_isa('Foo::Bar');
say "Foo::Bar isa $_" for @$isa;
That's actually less grokkable than using symbolic references.
There is a package called Package::Stash (used extensively by Moose) which wraps some of this up in a cleaner API. But my vote is to use symbolic references.
perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
| [reply] [d/l] [select] |
Re: Symbolic reference with strict "refs"
by broquaint (Abbot) on Aug 17, 2012 at 20:05 UTC
|
| [reply] [d/l] [select] |
Re: Symbolic reference with strict "refs"
by BrowserUk (Patriarch) on Aug 17, 2012 at 21:59 UTC
|
#! /your/shebang/
no Perl::Critic;
...
And get on with life.
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
| [reply] [d/l] |
Re: Symbolic reference with strict "refs"
by Athanasius (Archbishop) on Aug 17, 2012 at 17:19 UTC
|
#! perl
use strict;
use warnings;
{
package Aardman;
our @ISA = qw( Wallace Gromit );
}
{
package main;
my $pkg = 'Aardman';
my $var = $pkg . '::ISA';
my $ref = eval "\\\@$var";
print join(', ', @$ref), "\n";
}
Output:
Wallace, Gromit
(But, for the reasons given by davido and tobyink above, you should probably just use no strict 'refs'.)
Athanasius <°(((>< contra mundum
| [reply] [d/l] [select] |
Re: Symbolic reference with strict "refs"
by denishowe (Acolyte) on Aug 28, 2012 at 10:39 UTC
|
Thanks for all the erudite replies. tye and chromatic are right: ProhibitNoStrict is not helping me. I don't want to clutter my code with ## no critic so I'm just going to turn off that rule in a .perlcriticrc in the code directory.
It's not helping me in this case and I'm almost convinced by tye's passion that it is just a bad rule altogether. strict asks me "Are you sure you want a symbolic reference?", my no strict "refs" answers "Yes", then ProhibitNoStrict asks "Are you sure you're sure?" | [reply] [d/l] [select] |