Let's first define "constant", as Perl doesn't natively have a constant data type.
A constant in Perl is a subroutine that always returns the same value, often a single, very simple statement. Because of its simplicity, the return keyword is not used in most cases.
But subroutines are slower than variables, so why use constant CONSTANT (which, in a way, equals sub CONSTANT { ... }) when $CONSTANT would be faster? It's not only because of the read-only nature of constants, because *CONSTANT = \"read only string"; would take care of that. Using constants is mostly because it's generally considered a Good Thing™ to indicate clearly that something has a constant value, and should not be messed with.
To overcome the speed problem, Perl can inline subroutines. When an inlined subroutine is used, that will be as if it's return value were used as a literal constant, and we can all guess that 2 is faster than calling a subroutine that returns it, or having a variable that has 2 as its value.
Perl can inline subs, when they have an empty prototypes and have a constant return value (I'm probably a bit wrong here - if you're a more experienced monk reading this, please do correct me). So when you have sub FOO { 1 } and sub () BAR { 1 }, BAR() will be a LOT faster.
This all seems to have nothing to do with objects and method calls. But it does have. Because objects don't exist at compile time, method calls are done at runtime, which implies that prototypes are not used. That's why you can use constants as method calls in the first place, because normally the () prototype would avoid parameters to be passed, but methods get their object (or class) as their first argument. So that's the first speed loss, because the constant sub can no longer be inlined.
The second reason why method calls are slow is that Perl has to find out into which package the object is blessed before it can call the appropriate sub.
#!/usr/bin/perl -w
package Foo;
use constant CONSTANT => 2;
package main;
use Benchmark qw(cmpthese);
use strict;
my $object = bless \(my $dummy), 'Foo';
# Note: I use assignments to avoid the constant in void context
# to be optimised away (that would be too fast for Benchmark
# to handle (try removing "my $foo =" for fun ;)).
cmpthese(-1, {
object_method => sub { my $foo = $object->CONSTANT },
class_method => sub { my $foo = Foo->CONSTANT },
direct_sub => sub { my $foo = Foo::CONSTANT }
});
__END__
Benchmark: running class_method, direct_sub, object_method, each for a
+t least 1 CPU seconds...
class_method: 2 wallclock secs ( 1.07 usr + 0.00 sys = 1.07 CPU) @
+401942.99/s (n=430079)
direct_sub: 2 wallclock secs ( 1.16 usr + 0.00 sys = 1.16 CPU) @ 33
+89792.24/s (n=3932159)
object_method: 1 wallclock secs ( 1.14 usr + 0.00 sys = 1.14 CPU) @
+ 548745.61/s (n=625570)
Rate class_method object_method direct_sub
class_method 401943/s -- -27% -88%
object_method 548746/s 37% -- -84%
direct_sub 3389792/s 743% 518% --
And most constants that are to be used in the other package are exported (that's why most constants have some kind of prefix) anyway.
So in general, I think it's not a very good idea to use constants as methods. But the idea is nice :)
U28geW91IGNhbiBhbGwgcm90MTMgY
W5kIHBhY2soKS4gQnV0IGRvIHlvdS
ByZWNvZ25pc2UgQmFzZTY0IHdoZW4
geW91IHNlZSBpdD8gIC0tIEp1ZXJk
| [reply] [d/l] |
The current implementation of constants pretty much sucks anyway, since it fails in so many places (HERE docs, hash keys, and anywhere else that barewords are stringified). The way you're talking about using it is basically to treat it as an obfuscated method generator. Why not just code the methods explicitly, so that people don't have to know about the implementation of the constant pragma to understand your code? | [reply] |
I agree that Perl's idea of constants sucks. It is probably because there ain't no such thing as a constant in perl that the whole inlined subroutine thing emerged; it was probably stumbled upon by some hapless developer, and grew into common usage from there.
The short answer to the original question, which I thought I saw you alluding to the first time I read your response, is that using constants as methods pretty much does away with the compiler's inlining optimization (since a method lookup must now be done at runtime), which is most of why to do it in the first place.
The whole namespace argument doesn't hold up since it is far clearer to say, Module::CONST_VALUE (and get the benefit of inlining, as well) than $objOfSomeHardToDetermineType->CONST_VALUE.
dmm
If you GIVE a man a fish you feed him for a day
But, TEACH him to fish and you feed him for a lifetime
| [reply] [d/l] [select] |
Morally wrong? No. Common practice? Nope. Why? Who knows. Probably because a method isn't seen to be constant. Values are constant.
This trick only works because of the way constants are implemented (functions in the current namespace). If they were implemented differently, this wouldn't work.
------ We are the carpenters and bricklayers of the Information Age. Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement. | [reply] |