http://qs321.pair.com?node_id=905965


in reply to Inherit from a Role (or something like that)

Have you read the original "traits" paper?

but now how do I write my other classes against this role?
Other code should be written to use only the API provided by the RemoteConnection role, without caring what class it is otherwise. Any type checking should use the role name.

but then I can't easily inherit from both of them in Server and Client.
That sounds like a different problem. Maybe you didn't explain it well? Are you saying that Server and Client each want a different derived class of the Connection, but the Connection may already be different concrete classes?

You need to aggregate rather than further derive. Have the Connection class that you will be deriving from contain a SSH or Socket back-end instance, rather than being derived from it.

In fact, you might not need inheritance in the other place, either. Look at using collaborating instances instead. You can use delegation to make the result just as slick as inheritance rather than having to forward everything all over the place. Delegation can easily behave like inheritance from a run-time specified instance.

See this node for more recent discussion on delegation.

  • Comment on Re: Inherit from a Role (or something like that)

Replies are listed 'Best First'.
Re^2: Inherit from a Role (or something like that)
by elTriberium (Friar) on May 20, 2011 at 20:44 UTC
    Thanks, the other node you're referring to was an answer to my previous question :)
    Are you saying that Server and Client each want a different derived class of the Connection, but the Connection may already be different concrete classes?
    I'm not sure if I understand you here correctly: The basic idea is to have 2 interchangeable ways of providing "remote access" functionality to the Server and Client objects. The application will then do something like:
    my $server = Server->new(type => "ssh"); # to create an SSH connection $server->run("ifconfig"); my $server2 = Server->new(type => "socket"); # to create a socket conn +ection $server2->run("ifconfig"); my $client = Client->new(type => "ssh"); $client->run("ls");
    Where in this example "run" is defined in the Role and implemented by SSH and Socket.
      So Server and Client are both different from each other (though may share some stuff), and SSH and Socket are also different from each other but share a common interface.

      So, Server and Client (or their base class) "has" (not "is"!) a Connection. A Connection may be different concrete classes, or may be a single class that "has" a BackEnd. Note that in Perl you are more flexible in not having to define an "Interface" or have explicit base/derived relationships. Each concrete class can be implemented in any way it likes.

        Currently I only have the SSH module and now Server / Client "is" a SSH connection. The benefit of that is that I can just do things like:
        package SSH; has username => (is => 'rw', isa => 'Str'); sub connect { [...] $self->send($self->username); } package Client; extends qw(SSH); has username => (... default => 'admin'); package Server; extends qw(SSH); has username => (... default => 'root'); package main; my $client = Client->new(); my $server = Server->new(); $client->connect(); $server->connect();
        It's automatically using the correct username, because I'm overwriting this attribute of the SSH class in Client and Server. So, the point is, with SSH alone it works perfectly fine. I just have trouble adding the Socket alternative.