I’ve been discussing a code style issue with a friend. We have a series of packages that implement an interface by returning a specific type of value via a named subroutine. For example:
package Foo::Type::Bar; sub generate_foo { # about 5-100 lines of code return stuff here; }
So you can go:
my $bar_foo = Foo::Type::Bar->generate_foo; my $baz_foo = Foo::Type::Baz->generate_foo;
We have many of these, all under the same Foo::Type::* hierarchy.
I think the packages should clearly indicate that they implement the foo_generate interface, e.g.:
package Foo::Type::Bar; use base 'Foo::Type'; sub generate_foo { ... return stuff here; }
I think this is good code style, much more clear and clean for other coders exploring the code. It also lets you check Foo::Type::Bar->isa('Foo::Type') to see if it implements the interface (other parts of the subsystem are entirely OO).
My friend disagrees. Some arguments he makes are:
Foo::Type::*packages are clearly named, and used only in an internal project, and therefore there’s no question of wondering whether or not a given package implements an interface- the packages are often small and part of a standalone subsystem, and they feel to him like batch files or conf files, not heavy Perl OO code
- Perl expresses implementation via inheritance, which may be complex or problematic, particularly when one gets to multiple inheritance
- adding a
Foo::Typesuperclass doesn’t add any value, as it would literally be an empty package, used only to enable->isalookups - programmatically indicating interface implementation is a matter of personal code style
Is one or the other of us ‘right’? What would you do?
Edit: in examples, renamed Foo::Generator to Foo::Type
I think you should upgrade to Moose if you are asking these questions. There you’ll be able to define your interface by creating a role or class with appropriate abstract methods.
I agree with you that doing this can add valuable information. In Java there is the concept of a ‘marker interface,’ which is an empty interface which has no methods which exists only to tag a set of classes as being useful for a certain purpose. The most common example of this is the Serializable interface.
Of course, just because it can be useful does not mean it will be in your particular situation. 🙂