Re: How not to use "our"?
by JavaFan (Canon) on Nov 29, 2010 at 12:57 UTC
|
How can I improve my code to achieve a similar behaviour i.e. to be able access a common variable but without resorting to globals?
You don't. A variable either is lexical, or it can be accessed from elsewhere, and hence it's a global.
I've read in a number of places that we rarely have to declare variables with "our" and it's usually a bad idea.
If you read statements like that without context, discard them. "A little knowledge is worse than no knowledge". If it did come with context, then read and remember the context as well.
Your example is an excellent case for 'our'.
What is, IMO, bad is your use of string literals. I would write it as:
use strict;
use Exporter qw(import);
our @EXPORT = qw($tinytext $text $mediumtext $longtext);
our $tinytext = 100;
our $text = 200;
our $mediumtext = 500;
our $longtext = 2000;
Then, if you mistype 'tinytext' in your main code, you get a compile time error, instead of a run time uninitialized error. Using string literals as hash keys in the way you're doing is like coding without lexical variables, and warnings turned off. | [reply] [Watch: Dir/Any] [d/l] |
|
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
my $chapters = {
one => 'Chapter 1: AAA',
two => 'Chapter 2: BBB',
three => 'Chapter 3: CCC',
};
The above is more organised than having 3 separate variables. Any thoughts from the monks? | [reply] [Watch: Dir/Any] [d/l] |
|
If you think about it, a package symbol table (stash) *is* a hash, so the individual package variables within a package who's only purpose is to hold constants or configuration parameters is already organised as you would like it.
If you then avoid exporting the individual variables and use them as $config::one, $config::two etc. then you've got the best of both worlds.
The variables are nicely organised, and you also get typo checking at compile time:
>perl -c -wE"package x;our $fred=50;package main; print $x::fred,$x::d
+erf"
Name "x::derf" used only once: possible typo at -e line 1.
-e syntax OK
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".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
|
|
use strict;
use warnings;
my $chapters = {
one => 'Chapter 1: AAA',
two => 'Chapter 2: BBB',
three => 'Chapter 3: CCC',
};
say "We start with $chapters->{noe}"; # Compiler neither gives an er
+ror, nor a warning.
vs
package chapters;
our $one = 'Chapter 1: AAA';
our $two = 'Chapter 2: BBB';
our $three = 'Chapter 3: CCC';
package main;
use strict;
use warnings;
say "We start with $chapters::noe"; # Compile time error.
You're free to not use strict or warnings, but I think they are sane things to use. And it doesn't make sense to put a "use strict;" in your code, and then use code that won't be checked by strict. | [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
Re: How not to use "our"?
by Khen1950fx (Canon) on Nov 29, 2010 at 12:36 UTC
|
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
#!/usr/local/bin/perl
use strict;
use warnings;
package MyData;
sub getData {
my $data = {
'test' => 'yes',
'key' => 'value',
'some' => 'thing',
'array' => [ 1, 2, 3 ],
};
my $key = shift;
defined $data->{$key}
? return $data->{$key}
: return;
}
package main;
foreach my $testcase (qw(test key some bork)) {
my $value = MyData::getData($testcase);
if ($value) {
print "Data for $testcase : $value \n";
} else {
print "No such data : $testcase .\n";
}
}
| [reply] [Watch: Dir/Any] [d/l] |
|
Re: How not to use "our"?
by kcott (Archbishop) on Nov 29, 2010 at 15:21 UTC
|
use strict;
use warnings;
package A;
{
my $maxlengths = {
tinytext => 100,
longtext => 2000,
};
sub max_tiny_text { return $maxlengths->{tinytext}; }
sub max_long_text { return $maxlengths->{longtext}; }
}
package B;
use base 'A';
print 'From B: ', A->max_tiny_text(), "\n";
print 'From B: ', A->max_long_text(), "\n";
package main;
print 'From main: ', B->max_tiny_text(), "\n";
print 'From main: ', B->max_long_text(), "\n";
The output from this is:
From B: 100
From B: 2000
From main: 100
From main: 2000
Here's a quick rundown of what I've done here and why.
-
I've removed Exporter. Take a look at the Selecting What To Export section in that documentation.
-
I've set up class methods (max_tiny_text() and max_long_text()) to return the data.
-
The class data ($maxlengths) is lexically scoped with my inside a block such that it is only visible to the class methods. If you attempt to access $maxlengths within package A but outside that block, you'll get a compilation error.
I've aimed to keep the same general framework you presented. There are (as usual) more ways to do it. :-)
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Just because the names max_tiny_text and max_long_text take the CODE slot of the typeglob instead of the SCALAR slot doesn't make them any less global.
I've removed Exporter. Take a look at the Selecting What To Export section in that documentation.
And instead you write package name, and sub name to get a value. If you're willing to do that, you can do that with scalars as well, and not need Exporter:
package Max;
our $tiny_text = 200;
our $long_text = 1000;
package main;
print "From main: $Max::tiny_text\n";
print "From main: $Max::long_text\n";
You can even interpolate that way. | [reply] [Watch: Dir/Any] [d/l] [select] |
|
Thanks, kcott!
Wished I had read it in greater detail each time I went to that page, because I missed out that part entirely.
But I'm a little puzzled.
Under "Selecting What To Export", the first rule is "Do not export method names!" Why is that so? I thought one of the niceties about modules is that you can put functions in them so that they (the functions) can be reused? And how does one reuse the functions if they aren't exported. Hm...scratches head.
Thanks to all who have commented, particularly wazoox with the working code!
| [reply] [Watch: Dir/Any] |
|
Very briefly, methods are functions used in object oriented code (there's OO tutorials in perldoc is you're not familiar with this). Access to methods should be through inheritance - exporting method names will likely break inheritance.
If you read a bit further down that section you'll see it makes a distinction between modules that are object oriented and those that are just a collection of functions. As an example of the latter type, Scalar::Util is a collection of functions which you can selectively choose to export.
| [reply] [Watch: Dir/Any] |