(Ovid constants) Re: my $var; vs. use constant VAR = '';
by Ovid (Cardinal) on Apr 27, 2001 at 01:08 UTC
|
The second method is better defensive programming. However, what it does is pretty much equivalent to the following:
BEGIN {
sub FILENAME() { '/path/to/file/to/munge' }
}
Because FILENAME is actually a subroutine, it cannot be interpolated in quotes. In other words, the following are not synonymous:
my $filename = "/path/to/file/to/munge";
print "$filename";
use constant FILENAME => '/path/to/file/to/munge';
print "FILENAME";
The first example prints the filename, the second just prints "FILENAME".
That's a minor issue, but it does crop up from time to time (particularly when I'm writing an open X, Y or die statement).
Cheers,
Ovid
Join the Perlmonks Setiathome Group or just click on the the link and check out our stats. | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: my $var; vs. use constant VAR = '';
by tadman (Prior) on Apr 27, 2001 at 01:07 UTC
|
'use constant' doesn't appear to be terribly popualar,
as 'my' does effectively the same thing, without the child-proof
safety locks that prevent you from modifying variables
declared that way.
Instead of declaring a whole whack of constants using my(),
such as:
my ($filename) = "/path/to/file";
my ($filemode) = "immolate";
my ($opmode) = "seek";
my ($filetype) = "image/gif";
You could always convert this to a hash-structure, such as:
my (%config) = (
filename => "/path/to/file",
filemode => "immolate",
opmode => "seek",
filetype => "image/gif",
);
This has the advantage of allowing you to declare virtually
unlimited constants, without having to explicitly declare
them on their own my() line. Additionally, you can load
these from a file quickly and easily (i.e. an INI-type file,
an Apache-style file, or something else) such that you can
vary the configuration without modifying the program itself.
Of course, using a hash-lookup is slower than a regular
variable, but the price you pay would depend on frequency
of use, and in practice, should be so slight as to really
be irrelevant. In most cases where a constant is used frequently,
such as inside a loop, you would expect to see something like:
my ($thing) = $config{'thing_to_mash'};
for (my $x = 0; $x < 100_000_000; $x++)
{
DoCrazyStuff($thing, $x, Foo($x));
}
In this admittedly simple example, the hash is only used
once, and the variable itself is repeatedly used.
If you really don't trust yourself to keep your const's
constant, and to not modify them in any way, write a
function to extract parameters from it, such as:
sub Config { return $config{$_[0]}; }
Then you could keep %config in some sort of codeblock or
module which nobody has access too. This is kind of extreme,
though. | [reply] [Watch: Dir/Any] [d/l] [select] |
|
my ($filemode) = ("immolate"); # list context
or
my $filemode = "immolate"; # scalar context
And yes, it really does matter when you get into subroutine arg grabbing, like
my $count = @_; # get the length
or should that have been
my ($count) = @_; # get the first arg
So, make your left side and your right side agree, and I don't have to scratch
my head wondering where you are headed.
-- Randal L. Schwartz, Perl hacker | [reply] [Watch: Dir/Any] [d/l] [select] |
|
Letting go of brackets is hard if you come from the C
school of bondage and discipline programming, where forgetting
something minor, like brackets on a function call, is
punishable by death ("Segmentation fault.").
When declaring arguments, I have found that the code
looks strange, inconsistent, and a little off-kilter when
mixing and matching declaration styles,
where 'off-kilter' is a euphemism for "looks broken":
sub Foo
{
# Arguments: ARRAY <- ARRAY
my ($ich, $bin) = @_;
# Local variables: SCALAR,SCALAR,...
my $x, $y, $z;
# Local constants: ARRAY <- ARRAY
my ($ein, $berliner) = qw [ jelly donut ];
# Single constant: SCALAR <- SCALAR
my $go = 5;
}
Any statement like 'my $count = @_' can make me feel a little
bit dizzy, if only because it seems like anything could
happen there (i.e. concatenation with spaces, concatenation without,
first element assignment, last element assignment, count of items,
index of last item, etc.). Instead, I would rather explicitly
specify what is intended as 'my ($count) = scalar (@_);', though
rumor would have it that 'scalar' is deprecated.
Anyway, maybe I'm just behind the times. I use brackets on
int() and join(). I'll admit it! Maybe it's curable. As long
as I'm careful to make sure that my assignments are array-safe
(as I don't want to go to jail)
then things work okay, in their own wacky way, and everything is
bracketized and compartmentalized neatly.
So, I can only suppose that you would prefer the following
mutant variation, suggested for fun:
my $filename = "/path/to/file",
$filemode = "immolate",
$opmode = "seek",
$filetype = "image/gif";
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
|
Re: my $var; vs. use constant VAR = '';
by satchboost (Scribe) on Apr 27, 2001 at 01:07 UTC
|
Personally, I don't use constants. However, I work on a relatively large project with over 1000 files. That means that hiding my globals in modules that inherit Exporter tends to be more efficient for me. (And, easier to maintain, to boot!)
That said, by using use constant, you are being purer, in a sense. You're giving more information to the reader of your code as to exactly what's going to happen in the rest of the code. This is a good thing.
That said ... unless you are absolutely positive about the lifetime scope of what you're working on, I'd tend to shy away from constants. Let's say you're working on something that takes information from a number of Perl modules (like parent, children, function names, etc) and makes a bunch of HTML pages from it. Initially, you're going to be working with a small set of files, so making a bunch of stuff constant, like the base directory, makes sense. However, your project grows. You start to realize that you want to allow for greater flexibility. Maybe you don't think that you can change the constants, so your development possibilities are restricted. This sounds far-fetched, but it really isn't.
I conceive of constants as things that can never change, no matter how my script/tool/app changes. Things like PI, E, etc. I don't care what happens to what I've written, but PI isn't changing. That's a good choice for a constant. Making a filename a constant means that you have to alter your code significantly if you want to allow users to pass the filename into the script. That's a design that wasn't thinking ahead.
Just my $0.02. | [reply] [Watch: Dir/Any] [d/l] |
Re: my $var; vs. use constant VAR = '';
by Rhandom (Curate) on Apr 27, 2001 at 01:55 UTC
|
Something that will let you use scalars but will prevent them being modified:
my $const = \"Don't touch me!";
my $num = \5.6;
local *const2 = \"Another string";
local *num2 = \3.14159;
print "[$$const][$$num][$const2][$num2]\n";
### try and modify it
eval{ $num2 = 3; };
print $@;
print "$num2\n";
The first ones are not as pretty as dollar variables, and the second have a slight overhead of local, but I think that should give you some nice unmodifiable variables.
UPDATE:
Benchmarks are always good. Read em and weep:
#!/usr/bin/perl -w
use Benchmark qw(timethese cmpthese countit timestr);
use constant CONST_MOD => 3;
sub CONST_SUB () { 3 };
my $const_my = 3;
local $const_local = 3;
my $const_ref = \3;
local *const_alias = \3;
print "mod[".CONST_MOD."]sub[".CONST_SUB."]\n"
."my[$const_my]local[$const_local]\n"
."ref[$$const_ref]alias[$const_alias]\n";
cmpthese (1_000_000,
{
CMod => sub { my $t = CONST_MOD },
CSub => sub { my $t = CONST_SUB },
CMy => sub { my $t = $const_my },
CLocal => sub { my $t = $const_local },
CRef => sub { my $t = $$const_ref },
CAlias => sub { my $t = $const_alias },
});
Produces the following:
mod[3]sub[3]
my[3]local[3]
ref[3]alias[3]
Benchmark: timing 1000000 iterations of CAlias, CLocal, CMod, CMy, CRe
+f, CSub...
CAlias: 0 wallclock secs ( 0.79 usr + 0.00 sys = 0.79 CPU) @ 12
+65822.78/s (n=1000000)
CLocal: 0 wallclock secs ( 0.80 usr + 0.00 sys = 0.80 CPU) @ 12
+50000.00/s (n=1000000)
CMod: 2 wallclock secs ( 0.80 usr + 0.00 sys = 0.80 CPU) @ 12
+50000.00/s (n=1000000)
CMy: 1 wallclock secs ( 0.75 usr + 0.00 sys = 0.75 CPU) @ 13
+33333.33/s (n=1000000)
CRef: 0 wallclock secs ( 1.03 usr + 0.00 sys = 1.03 CPU) @ 97
+0873.79/s (n=1000000)
CSub: 0 wallclock secs ( 0.81 usr + 0.01 sys = 0.82 CPU) @ 12
+19512.20/s (n=1000000)
Rate CRef CSub CLocal CMod CAlias CMy
CRef 970874/s -- -20% -22% -22% -23% -27%
CSub 1219512/s 26% -- -2% -2% -4% -9%
CLocal 1250000/s 29% 3% -- -0% -1% -6%
CMod 1250000/s 29% 3% 0% -- -1% -6%
CAlias 1265823/s 30% 4% 1% 1% -- -5%
CMy 1333333/s 37% 9% 7% 7% 5% --
The only noticable differences are the my and the ref. The reference takes too long, the "my" is a little quicker but it is modifiable. All of the others are neck a neck, so, I'd vote for local *var=\23;
my @a=qw(random brilliant braindead); print $a[rand(@a)]; | [reply] [Watch: Dir/Any] [d/l] [select] |
|
Ah, the perils of benchmarking... my results from v5.6.1 on Linux:
Rate CRef CAlias CMy CLocal CMod CSub
CRef 2702703/s -- -8% -22% -22% -24% -27%
CAlias 2941176/s 9% -- -15% -15% -18% -21%
CMy 3448276/s 28% 17% -- -0% -3% -7%
CLocal 3448276/s 28% 17% 0% -- -3% -7%
CMod 3571429/s 32% 21% 4% 4% -- -4%
CSub 3703704/s 37% 26% 7% 7% 4% --
and then the same program, run just a second later:
CAlias 2857143/s -- -0% -3% -6% -20% -23%
CRef 2857143/s 0% -- -3% -6% -20% -23%
CMod 2941176/s 3% 3% -- -3% -18% -21%
CSub 3030303/s 6% 6% 3% -- -15% -18%
CLocal 3571429/s 25% 25% 21% 18% -- -4%
CMy 3703704/s 30% 30% 26% 22% 4% --
MeowChow
s aamecha.s a..a\u$&owag.print | [reply] [Watch: Dir/Any] [d/l] [select] |
|
Don't worry, I had that happen on mine as well, but in every case, the my was a percentage faster and the ref was a percentage slower and everything else just hummed around in the middle. The point wasn't the benchmark. The point was that declaring aliases or setting up your own constant subs, are not that much slower than my'ing a variable or local'ing a variable.
The point of benchmark is ballpark, and all of the types are in the ball park.
my @a=qw(random brilliant braindead); print $a[rand(@a)];
| [reply] [Watch: Dir/Any] |
|
|
|
Re: my $var; vs. use constant VAR = '';
by arturo (Vicar) on Apr 27, 2001 at 01:06 UTC
|
From perldoc constant
"These constants do not directly interpolate into double-quotish strings, although you may do so
indirectly."
There might be a bit of a performance hit when using the constants approach, but I doubt it's *huge* and you are protected from accidentally altering your constants.
"edited" by (arturo) hisself ... sorry, I thought I'd broken the lines up correctly and it showed up fine in my browser.
| [reply] [Watch: Dir/Any] [d/l] |
|
Actually constants are faster, since use constant simply turns them into constant subs (for versions of Perl that support this):
sub CONST_NAME () { 'value' }
IIRC, this form is optimized by the Perl compiler such that there are no hits to the symbol table in dereferencing the value; it would be as if you typed the constant value in as a literal, much like a preprocessor #DEFINE macro.
update: Looks like I was wrong, my variables are actually a hair faster than both constants and even literal values.
MeowChow
s aamecha.s a..a\u$&owag.print | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: my $var; vs. use constant VAR = '';
by antihero (Novice) on Apr 27, 2001 at 00:59 UTC
|
eeek... I just noticed that I borked the title... it was meant to read
my $var =""; vs. use constant VAR => ''; | [reply] [Watch: Dir/Any] [d/l] |
|
Something that is just as fast (slightly faster) than use constant, that can be localized, and that is neat, is to create a reference or alias to a non modifiable variable.
Try this:
local *CONST = \23.34234334234;
Try to modify it. You can't. Declare it at the top of your program and it is there for life. Put it in a sub and it stays around for the life of the sub.
See 75935 buried way at the bottom of this node.
my @a=qw(random brilliant braindead); print $a[rand(@a)]; | [reply] [Watch: Dir/Any] [d/l] |