tags:

views:

5068

answers:

6

Does Perl have an enumeration type that adheres to best practices, or maybe more importantly, does it need one?

The project I am working one uses strings all over the place to denote things that would typically use an Enum in a language like C#. For example, we have a set of phone numbers in an array of hashes, each associated with a phone type ("Home", "Work", "Mobile", etc.):

$phone_number->{type} = 'Home';

Would it be sufficient to use a read-only set of variables here or should an Enum be used? I've found an enum module on CPAN but it appears to use bare words which violates one of the Perl Best Practices. My thinking on using read-only variables goes something like this:

use Readonly;

Readonly my $HOME   => 'Home';
Readonly my $WORK   => 'Work';
Readonly my $MOBILE => 'Mobile';

$phone_number->{type} = $HOME;

Is this a good approach or is there a better way?

+3  A: 

Perl doesn't support the concept natively but there are modules to add this functionality

http://search.cpan.org/perldoc/enum

Ray Booysen
+3  A: 

Your way is more than adequate.

You can also create enums with Moose::Util::TypeConstraints, if you happen to be using Moose. (Which you should be.)

jrockway
+9  A: 

No, there isn't a built-in enum construct. Perl doesn't do a lot of strict typing, so I think there's actually little need for one.

In my opinion, the Readonly approach you used is solid.

There's also the more traditional constant pragma.

use constant {
    HOME   => 'Home',
    WORK   => 'Work',
    MOBILE => 'Mobile',
};

$phone_number->{type} = HOME;

Behind the scenes, it sets up a function for each constant that returns the value, like so.

sub HOME () { 'Home' }

I'd stick with Readonly unless you want to take advantage of that property, for example:

package Phone::Type;

use constant {
    HOME => 'Home',
    #...
};

package main;

print Phone::Type->HOME, "\n";
Ronald Blaschke
For strictness, there is sub HOME () {'home'} made behind scene.
Hynek -Pichi- Vychodil
You're right, thanks for pointing this out.
Ronald Blaschke
When you have a subroutine which take in Phone::Type enum as argument, how do you perform dynamic checking on the subroutine argument is Phone::Type type enum, not string, not number...
Yan Cheng CHEOK
Just for clarification sub HOME () {'home'} and use constant { HOME => 'Home', WORK => 'Work', MOBILE => 'Mobile',}; are the same? the later generates (Behind the scene) the code?
Phill Pafford
Your examples don't match up ;-), but yes, the current implementation does. See section TECHNICAL NOTES in perldoc constant. constant also does some name checking. For example, starting with double underscores is disallowed, and names like 'BEGIN' cause a warning (with 'use warnings') because they might be confusing. For details have a look at the implementation by calling 'perldoc -m constant'.
Ronald Blaschke
This is actually inaccurate as later version of Perl do. Look here http://stackoverflow.com/questions/473666/does-perl-have-an-enumeration-type/1037736#1037736
Nathan Fellman
+1  A: 

Perl does in fact have an enum type like in C. Try this for details.

perldoc enum

For instance:

use enum qw(HOME WORK MOBILE);

Now we have:

HOME == 0
WORK == 1
MOBILE == 2

You can also set the indeces yourself:

use enum qw(HOME=0 WORK MOBILE=10 FAX);

Now we have:

HOME == 0
WORK == 1
MOBILE == 10
FAX == 11

Look here for more details.

Note that this isn't supported in every version of Perl. I know that v5.8.3 doesn't support it, while v5.8.7 does.

Nathan Fellman
Inasmuch as I can tell, `use enum` is a CPAN module, not part of the core language.
Paul Nathan
+1  A: 

You should always remember that PBP is advisory - the book itself as much. You need to interpret the guidelines rather than slavishly adopting them.

hexten
A: 

You should look at the constant perl module.

use constant WEEKDAYS => qw(
 Sunday Monday Tuesday Wednesday Thursday Friday Saturday
);
Oreolek