tags:

views:

394

answers:

4

I've been playing around with Moose, getting a feel for it. I'd like an example of pure virtual functions like in C++ but in Moose parlance (specifically in a C++-looking way). I know that even with Moose imposing a stricter model than normal Perl, there's still more than one way to do what I'm asking (via method modifiers or SUPER:: calls). That is why I'm asking specifically for an implementation resembling C++ as much as possible. As for the "why?" of this restriction? Mostly curiosity, but also planning to port some C++ code to Perl with Moose in a way that C++-centric people could mostly identify with.

+1  A: 

Here is was my attempt (without Roles, for information on Roles see the other answers):

package Abstract;
use Moose;

sub stuff;

package Real;
use Moose;
extends 'Abstract';

override 'stuff' => sub { print "Using child function!\n"; }
Kyle Walsh
I have no idea what you are talking about, but it seems like you want `Abstract` to be an abstract base class and the `stuff` method (not function) to be pure virtual. Just writing `sub stuff {}` immediately violates that. So, base class method should probably be `sub stuff { croak }`.
Sinan Ünür
@Sinan I was going for something like C++'s: virtual void stuff() = 0;
Kyle Walsh
@Sinan I have two concerns with adding the croak to stuff: 1) it didn't compile for me and 2) you could argue that croak is a form of implementation, which (unless I'm misinterpreting the definition of pure virtual functions) is exactly the opposite of what I'm going for. I'm editing sub stuff { ; } to be sub stuff;
Kyle Walsh
`croak` comes from Carp, and must be imported. Add 'use Carp qw(croak);` to any package you wish to use it in.
daotoad
@daotoad Wow...thanks for pointing out a silly oversight on my part. I let my vim syntax highlighting go to my head!
Kyle Walsh
@Kyle Walsh the `croak` was a hack making sure no code invoking `Abstract->stuff` would appear to work whereas an empty sub body would not prevent that.
Sinan Ünür
Moose imports confess() for you so s/croak/confess/ and it will just work. However as was *just* pointed out in #moose sub stuff { confess; } doesn't do _compile_ time checking ... the Role and MX::ABC solutions do.
perigrin
@Sinan Thanks for clearing that up.
Kyle Walsh
@perigrin: From the above answers, looks to me like MX::ABC does construction-time checking, not call-time (both are run-time not compile-time, though).
ijw
+2  A: 

It appears I can't do exactly what I want with Moose, but I can come very close with Roles. Here is the information from the Moose manual entry for Roles:

Roles Versus Abstract Base Classes

If you are familiar with the concept of abstract base classes in other languages, you may be tempted to use roles in the same way.

You can define an "interface-only" role, one that contains just a list of required methods.

However, any class which consumes this role must implement all of the required methods, either directly or through inheritance from a parent. You cannot delay the method requirement check so that they can be implemented by future subclasses.

Because the role defines the required methods directly, adding a base class to the mix would not achieve anything. We recommend that you simply consume the interface role in each class which implements that interface.

Kyle Walsh
snap! Your answer appeared just as I was tidying up mine ;-)
draegtun
@draegtun Funny how that happens! Your answer is really helpful, especially for people who are looking to implement interfaces with Moose. I just came up with an oddball question that I'm finding through further research might not have a deterministic answer. I'm still trying to decide if this is because I fully didn't understand the area before asking, or if Moose is missing this feature ;)
Kyle Walsh
Hmm. Is it just me or is that help actually not very helpful? It seems to say 'if you want to implement an abstract class with a role it doesn't work because they're not the same thing; instead, *look over there, a flying pig*! I'd still be interested in either (a) how do do a hierarchy of abstract classes (specifically if MooseX::ABC is considered good or not) or alternatively (b) why ABCs are bad for Moose programs.
ijw
+4  A: 

I can think of this way using roles instead of subclassing:

{
    package AbstractRole;
    use Moose::Role;
    requires 'stuff';  
}

{
    package Real;
    use Moose;
    with 'AbstractRole';
}

This will give a compilation error because Real doesn't have stuff defined.

Adding stuff method to Real will now make it work:

{
    package Real;
    use Moose;
    with 'AbstractRole';

    sub stuff { print "Using child function!\n" }
}

/I3az/

draegtun
Yeah, this is how it would be done if I only wanted an interface. I'm finding out through research and the discussion here that I might not be able to do _exactly_ what I'm hoping to do.
Kyle Walsh
I think this gets you most of the way though. Have a chat with Moose guys at #moose on irc.perl.org or the mailing list [email protected] if you feel there is a benefit in extending this further.
draegtun
@draegtun Yeah, I think this is the best approximation I can hope for. Thanks for your help!
Kyle Walsh
+4  A: 

You might also want to take a look at Jesse Luehrs' MooseX::ABC. It seems very similar to some of the implementations here. From the synopsis:

package Shape;
use Moose;
use MooseX::ABC;

requires 'draw';

package Circle;
use Moose;
extends 'Shape';

sub draw {
    # stuff
}

my $shape = Shape->new; # dies
my $circle = Circle->new; # succeeds

package Square;
use Moose;
extends 'Shape'; # dies, since draw is unimplemented

I know that Jesse is a C++ programmer during the day.

perigrin
Thanks for the tip, I'll definitely check that out!
Kyle Walsh