tags:

views:

208

answers:

4

I think I read somewhere that some modules only have object oriented interfaces ( though they didn't create objects, they only held utility functions ). Is there a point to that?

+1  A: 

namespacing, mostly. Why not? Everything that improves perl has my full approval.

Stefano Borini
+7  A: 

First, its important to remember that in Perl, classes are implemented in a weird way, via packages. Packages also serve for general namespace pollution prevention.

package Foo;

sub new {
  my ($class) = @_;
  my $self = bless {}, $class;

  return $self;
}

1;

That is how you make a Foo class in Perl (which can have an objected instantiated by calling Foo->new or new Foo). The use of new is just a convention; it can be anything at all. In fact, that new is what C++ would call a static method call.

You can easily create packages that contain only static method calls, and I suspect this is what you're referring to. The advantage here is that you can still use OO features like inheritance:

package Bar;

sub DoSomething {
    my ($class, $arg) = @_;
    $class->Compute($arg);
}

sub Compute {
    my ($class, $arg) = @_;
    $arg * 2;
}

1;

package Baz;
@Baz::ISA = qw(Bar);

sub Compute {
    my ($class, $arg) = @_;
    $arg * 2 - 1
}

1;

Given that, then

say Bar->DoSomething(3) # 6
say Baz->DoSomething(3) # 5

In fact, you can even use variables for the class name, so these can function very much like singletons:

my $obj = "Baz"; # or Baz->new could just return "Baz"
print $obj->DoSomething(3) # 5

[Code is untested; typos may be present]

derobert
+7  A: 

I suspect that this is mostly a philosophical choice on the part of authors who prefer OO to imperative programming. Others have mentioned establishing a namespace, but it's the package that does that, not the interface. OO is not required.

Personally, I see little value in creating classes that are never instantiated (i.e. when there's no object in object-oriented). Perl isn't Java; you don't have to write a class for everything. Some modules acknowledge this. For example: File::Spec has an OO interface but also provides a functional interface via File::Spec::Functions.

File::Spec also provides an example of where OO can be useful for uninstantiated "utility" interfaces. Essentially, File::Spec is an abstract base class -- an interface with no implementation. When you load File::Spec it checks which OS you're using and loads the appropriate implementation. As a programmer, you use the interface (e.g. File::Spec->catfile) without having to worry about which version of catfile (Unix, Windows, VMS, etc.) to actually call.

Michael Carman
And from the module authoring point of view: if you use the arrow interface from the beginning, you can add in inheritance later on. If you use straight sub calls, and you want to introduce inheritance, you either have to change your whole interface, or engage in some black Exporter magic.
hobbs
+2  A: 

As others have said, inheritance is the big gain if an actual object is not needed. The only thing I have to add here is the advice to name your variables well when writing such interfaces, e.g.:

package Foo;

# just a static method call
sub func
{
    my $class = shift;
    my (@args) = @_;
    # stuff...
}

I named the variable that holds the classname "$class", rather than $this, to make it clear to subsequent maintainers that func() will be called as Foo->func() rather than $foo->func() (with an instantiated Foo object). This helps avoid someone adding this line later to the method:

my $value = $this->{key};

...which will fail, as there is no object to deference to get the "key" key.

If a method might be called either statically or against an instantiated object (for example, when writing a custom AUTOLOAD method), you can write this:

my method
{
    my $this = shift;
    my $class = ref($this) || $this;
    my (@args) = @_;
    # stuff...
}
Ether