in reply to Is it morally wrong to use constants as methods in a package?

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