2016-06-30 6 views
2

Base.pm:Moose :: Role Seltsamkeit mit überschriebene Methoden

package Base; 
use Moose::Role; 

sub f { 
    my ($self) = @_; 
    print "In role.\n"; 
} 

1; 

X.pm:

package X; 
use Moose; 

with 'Base'; 

around 'f' => sub { 
    my ($next, $self) = @_; 
    print "Nevermind, we are in class X.\n"; 
}; 

__PACKAGE__->meta->make_immutable; 
1; 

Y.pm:

package Y; 
use Moose; 

with 'Base'; 

override 'f' => sub { 
    my ($self) = @_; 
    print "Nevermind, we are in class Y.\n"; 
}; 

__PACKAGE__->meta->make_immutable; 
1; 

Dann X funktioniert und Y nicht. Es ist ein komisches Design, da override nur ein Spezialfall von around ist und als Sonderfall auch funktionieren sollte.

Kann jemand erklären, warum diese Designentscheidung und warum es so seltsam ist?

$ perl X.pm 
$ perl Y.pm 
Cannot add an override method if a local method is already present at /usr/lib/i386-linux-gnu/perl5/5.22/Moose/Exporter.pm line 419 
    Moose::override('f', 'CODE(0x9c002f8)') called at Y.pm line 9 

Antwort

3

Die documentation describes override als:

Eine Überschreibung Methode eine Möglichkeit ausdrücklich sagt, ist „Ich habe diese Methode von meiner übergeordneten Klasse bin überwiegende“. Sie können innerhalb dieser Methode super aufrufen, und es wird wie erwartet funktionieren. Dasselbe kann mit einem normalen Methodenaufruf und dem Pseudo-Paket SUPER:: erreicht werden; es ist wirklich deine Entscheidung.

Was Sie tun, widerspricht dieser Definition. Mit einer Rolle ist f in Ihrem Paket installiert. Sie versuchen, ein anderes f in demselben Paket zu definieren.

Die Tatsache, dass Ihre Rolle Base genannt wird bedeutet für mich, dass Sie etwas Verwirrung haben, wenn es um den Unterschied zwischen Vererbung und Zusammensetzung kommt.

Die purpose of around ist, ein Verfahren in der aktuellen Klasse zu wickeln, unabhängig davon, ob es in dem gleichen Paket implementiert wurde oder ererbten oder zusammengesetzt:

Method Modifikatoren verwendet werden kann, ohne Änderung der Definition Verhalten Methoden hinzufügen dieser Methoden.

Nur ein einfaches Lesen dieser zwei Schnipsel macht die Unterscheidung für mich klar.

Wenn Sie die Rolle anwenden, die f definiert, überschreibt diese selbst alle geerbten Methoden f. Wenn Sie dann override 'f' sagen, erklären Sie Ihre Absicht, f erneut zu überschreiben. Nun, es kann nur eine Methode f in einer Klasse geben. Welcher sollte zählen? Der eine, den Sie bekommen, indem Sie die Rolle anwenden, oder die, die Sie gerade definiert haben? Die Methoden, die Sie beim Erstellen einer Rolle erhalten, sind in etwa dieselben wie Methoden, die Sie manuell in der Klasse definiert haben. Es gibt keinen Grund a priori einer sollte wichtiger sein als der andere.

Betrachten Sie dies als Flugreisen. Denken Sie an die Methode Modifikatoren als Klassen: Erstens, Wirtschaft, Wirtschaft usw. Also, in der ersten Klasse, get_dinner_menu vielleicht verpackt mit Vorspeisen, Süßigkeiten, Desserts usw.

Auf der anderen Seite, override ist wie die Flucht zu verändern. Es ist, als ob du sagst "Ich möchte sowohl auf TK 1 als auch auf UIA 213 fliegen". Macht keinen Sinn.

Vielleicht wird das folgende Skript die Dinge etwas klarer machen, indem es eine naive Implementierung von around zeigt und eine Methode überschreibt, ohne override zu verwenden.

#!/usr/bin/env perl 

use strict; 
use warnings; 

{ 
    package MyRole; 

    use Moose::Role; 

    sub f { 
     print "in role\n"; 
    } 
} 

{ 
    package X; 
    use Moose; 

    with 'MyRole'; 

    around 'f' => sub { 
     my ($orig, $self) = @_; 
     print "In wrapper\n"; 
     return $self->$orig(@_); 
    }; 

    { 
     my $f = \&f; 
     { 
      no warnings 'redefine'; 
      *f = sub { 
       my ($self) = @_; 
       print "In wrapper wrapper\n"; 
       return $self->$f(@_); 
      } 
     } 
    } 
} 

{ 
    package Y; 

    use Moose; 
    with 'MyRole'; 

    sub f { 
     print "In overridden method\n"; 
    } 
} 

print '=-=' x 22, "\n"; 

my $x = X->new; 
$x->f; 

print '=-=' x 22, "\n"; 

my $y = Y->new; 
$y->f; 

Ausgang:

+0

Aber warum auf der Erde, 'around' in diesem Fall ** nicht ** arbeiten? Kann man nicht über "herum" sagen, dass es nicht funktionieren soll? – porton

+0

Verstanden. Aber "sowohl" als auch "um" für die gleiche Methode in einer Klasse zuzulassen, sieht für mich wie ein Designfehler aus. – porton

+1

Es gibt nichts, was man durch *** verbieten von *** 'sub f' und' around'f erreichen könnte '' im selben Paket, weil das Komponieren einer Rolle, die 'f' bereitstellt, 'f' als eine Untereinheit in dem Paket installiert. Dieses Verbot macht es also unmöglich, "um" mit zusammengesetzten Methoden zu umgehen oder sie zu umgehen. Ich habe nicht zu viel darüber nachgedacht. –