in reply to importing a function

Personally I don't find:

__PACKAGE__->define_attributes(qw/foo bar/);

ugly - and that's what I would go for since it makes sense and is a familiar construct. Personally I find mixing functional and OO APIs in the same module confusing ;-)

However, if you really don't like it one other solution would be to reverse the process and have each class declare a method that returns the attributes, e.g:

sub define_attributes { qw(foo bar) };

You could then have the super-class scan for its sub-classes via an INIT block, after the sub-classes should have been compiled (obviously won't work if you require classes at run time tho'). You can then find their attributes by calling the appropriate define_attributes method.

Another method would be to use something like Attribute::Handlers so you could do:

sub attrs : Attributes { qw(foo bar) };