Re: OOP - Constant Vs. Subroutine
by merlyn (Sage) on May 11, 2007 at 20:00 UTC
|
When a constant is used in an expression, perl replaces it
with its value at compile time, and may then optimize the
expression further. In particular, any code in an "if
(CONSTANT)" block will be optimized away if the constant
is false.
In other words, it's not a sub call any more.
| [reply] [Watch: Dir/Any] [d/l] |
|
ah, that makes perfect sense.
| [reply] [Watch: Dir/Any] |
Re: OOP - Constant Vs. Subroutine ()
by tye (Sage) on May 12, 2007 at 06:17 UTC
|
Many reading this thread can probably already figure this out, but it hasn't been stated directly so...
Note that you can get your subs to be just as fast1 by adding "()" after each's name. That is, replace something like:
sub DoesNotChange { 5; }
with
sub DoesNotChange() { 5; }
1 But who cares? If you couldn't notice the speed difference w/o resorting to Benchmark...
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
by adding "()" after each's name
...which is exactly the reason why perl can optimize the sub away at compile time and makes them
behave like use constant- note the two invocations
qwurx [shmem] ~ > perl -MO=Concise,-exec -e 'use constant foo=>"5"; $c
+=4+foo;'
1 <0> enter
2 <;> nextstate(main 70 -e:1) v
3 <$> const[IV 9] s
4 <#> gvsv[*c] s
5 <2> sassign vKS/2
6 <@> leave[1 ref] vKP/REFC
-e syntax OK
qwurx [shmem] ~ > perl -MO=Concise,-exec -e 'sub foo(){"5"}; $c=4+foo;
+'
1 <0> enter
2 <;> nextstate(main 2 -e:1) v
3 <$> const[IV 9] s
4 <#> gvsv[*c] s
5 <2> sassign vKS/2
6 <@> leave[1 ref] vKP/REFC
-e syntax OK
are identical (except for the code of constant.pm loaded in the first), while
qwurx [shmem] ~ > perl -MO=Concise,-exec -e 'sub foo{"5"}; $c=4+foo;'
1 <0> enter
2 <;> nextstate(main 2 -e:1) v
3 <$> const[IV 4] s
4 <0> pushmark s
5 <#> gv[*foo] s
6 <1> entersub[t3] sKS/TARG,1
7 <2> add[t4] sK/2
8 <#> gvsv[*c] s
9 <2> sassign vKS/2
a <@> leave[1 ref] vKP/REFC
-e syntax OK
leaves the sub as a sub since it doesn't have a null prototype list.
--shmem
_($_=" "x(1<<5)."?\n".q·/)Oo. G°\ /
/\_¯/(q /
---------------------------- \__(m.====·.(_("always off the crowd"))."·
");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
While I have no idea of Perl's internals, it also seems that it depends what the sub contains. Of course, this is logical, since you can't inline everything. Seems to be that things that can be reduced to constant values will be inlined, which also makes it easier to remember :) So, "4" will be inlined, "4+4" too, since it can also be optimized away. "@INC" won't, for example.
Ordinary morality is for ordinary people. -- Aleister Crowley
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] [d/l] |
|
agreed -- who cares. this in no way, shape, or form will noticably affect any sort of perl code.
I just brought this topic up, because I wanted to understand exactly why the speed difference existed. all i really care for is being able to stash & access class variables. I find using subs/constants is much easier than using 'our' scoped package variables for stashing info -- its just a quick $self->name instead of inspecting the object and moving on from there
In any event, I did the following benchmark below to test the speed difference between the various options in writing & calling these methods
Results vary on each run, but fall into 2 general categories...
faster:
sub get() { 'a'; }
use constant get_constant=> 'a';
slower:
sub get { 'a'; }
sub get { return 'a'; }
sub get() { return 'a'; }
and the code...
package class;
use strict;
sub new {
my ( $proto )= @_;
my $class= ref($proto) || $proto;
my $self= bless ( {} , $class );
return $self;
}
sub get_sub { 'a'; }
sub get_sub_nullproto () { 'a'; }
sub get_sub_return { return 'a'; }
sub get_sub_return_nullproto () { return 'a'; }
use constant get_constant=> 'a';
package main;
use strict;
use Benchmark qw[ cmpthese ];
my $object= class->new();
cmpthese -1, {
get_sub => sub { my $a= $object->get_sub; },
get_sub__paren => sub { my $a= $object->get_sub(); },
get_sub_nullproto => sub { my $a= $object->get_sub_nullproto; },
get_sub_nullproto__paren => sub { my $a= $object->get_sub_nullprot
+o(); },
get_sub_return => sub { my $a= $object->get_sub_return; },
get_sub_return__paren => sub { my $a= $object->get_sub_return(); }
+,
get_sub_return_nullproto => sub { my $a= $object->get_sub_return_n
+ullproto; },
get_sub_return_nullproto__paren => sub { my $a= $object->get_sub_r
+eturn_nullproto(); },
get_constant => sub { my $a= $object->get_constant; },
get_constant__paren => sub { my $a= $object->get_constant(); },
};
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: OOP - Constant Vs. Subroutine
by perrin (Chancellor) on May 11, 2007 at 19:59 UTC
|
The constant pragma creates a sub with a specific prototype, allowing it to be in-lined. For some uses in OO code, you're probably better off using class methods, since subclasses can override them. | [reply] [Watch: Dir/Any] |
|
subclasses can override constants too.
| [reply] [Watch: Dir/Any] |
|
How would you do that? Would you have to call it like a method?
Class->constant;
That would prevent the in-lining behavior, but I guess it's no worse than a normally defined simple method. | [reply] [Watch: Dir/Any] [d/l] |
|
|
|
Re: OOP - Constant Vs. Subroutine
by princepawn (Parson) on May 11, 2007 at 21:01 UTC
|
Isn't Best Practice to use Readonly not constant?
Carter's compass: I know I'm on the right track when by deleting something, I'm adding functionality
| [reply] [Watch: Dir/Any] |
|
#! perl -slw
use strict;
use Benchmark qw[ cmpthese ];
use constant {
X => 0, Y => 1, Z => 2, P => 3, Q => 4,
};
use Readonly;
Readonly::Hash my %Fields => {
X => 0, Y => 1, Z => 2, P => 3, Q => 4,
};
sub prioritisedSort1 {
return $a->[ P ] <=> $b->[ P ]
or $a->[ Z ] <=> $b->[ Z ]
or $a->[ Y ] <=> $b->[ Y ]
or $a->[ X ] <=> $b->[ X ]
or $a->[ Q ] <=> $b->[ Q ];
}
sub prioritisedSort2 {
return $a->[$Fields{P}] <=> $b->[$Fields{P}]
or $a->[$Fields{Z}] <=> $b->[$Fields{Z}]
or $a->[$Fields{Y}] <=> $b->[$Fields{Y}]
or $a->[$Fields{X}] <=> $b->[$Fields{X}]
or $a->[$Fields{Q}] <=> $b->[$Fields{Q}];
}
our $N ||= 1e5;
my @AoA1 = map {
[ map{ int rand $_ } 1000, 100, 10, 500, 50 ]
} 1 .. $N;
my @AoA2 = map{ [ @$_ ] } @AoA1;
my( @sorted1, @sorted2 );
cmpthese -1, {
constant => sub{ @sorted1 = sort prioritisedSort1 @AoA1 },
Readonly => sub{ @sorted2 = sort prioritisedSort2 @AoA2 },
};
print "\nFirst and last 5 for constant";
print "[@$_]"
for @sorted1[ 0 .. 4 ], [ qw[ - - - - - ] ], @sorted1[ -5 .. -1 ];
print "\nFirst and last 5 for Readonly";
print "[@$_]"
for @sorted2[ 0 .. 4 ], [ qw[ - - - - - ] ], @sorted2[ -5 .. -1 ];
__END__
C:\test>junk8 -N=1e2
Rate Readonly constant
Readonly 137/s -- -96%
constant 3459/s 2427% --
First and last 5 for constant
[226 44 0 8 3]
[425 64 7 10 2]
[790 25 8 20 27]
[461 37 0 27 47]
[151 51 3 31 35]
[- - - - -]
[734 15 9 482 6]
[90 40 2 489 5]
[957 21 9 491 45]
[17 99 3 494 44]
[585 50 7 495 22]
First and last 5 for Readonly
[226 44 0 8 3]
[425 64 7 10 2]
[790 25 8 20 27]
[461 37 0 27 47]
[151 51 3 31 35]
[- - - - -]
[734 15 9 482 6]
[90 40 2 489 5]
[957 21 9 491 45]
[17 99 3 494 44]
[585 50 7 495 22]
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] |
|
Yes, per TheDamian advice. And see also merlyn's article. However, for my personal need, I don't see any advantages other than interpolating purpose.
Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!
| [reply] [Watch: Dir/Any] |
|
use constant FOO => { x => 0 };
print FOO->{x}; # 0
++ FOO->{x};
print FOO->{x}; # 1
Readonly also makes sure your entire data structure is readonly. constant only does that to the topmost level.
| [reply] [Watch: Dir/Any] [d/l] |
|
|
|
|
I should have clarified my intent...
If you're looking for 'read only' variables, then yes-- use Readonly , not constant
AFAIK : Readonly creates package variables , while constant creates inheritable subroutines. For my needs, constant was more appropriate -- though a sub with a null prototype seems to be even more appropriate.
| [reply] [Watch: Dir/Any] |