2017-01-22 45 views
8

Wyobraź sobie szereg skomplikowanych gramatyk reprezentowane ról, choć prosty przykład wystarczy, aby pokazać konflikt:Czy Perl 6 powinien móc rozplątać włączenie tej samej roli z różnych źródeł?

role Alpha { 
    token alpha { :i <[A..Z]> } 
    } 

role Digit { 
    token digit { <[0..9]> } 
    } 

role Either 
    does Alpha 
    does Digit { 
    token either { <alpha> | <digit> } 
    } 

grammar Thingy 
    does Either 
    does Alpha 
    { 
    token TOP { <alpha> <either>* } 
    } 

my $match = Thingy.parse('1a3'); 
dd $match; 

To nie działa, ponieważ Perl 6 nie rozwikłać relacje, aby dowiedzieć się, że konflikt jest rzeczywiście samo z tego samego źródła:

Metoda „alpha” musi być rozwiązany przez klasy thingy, ponieważ występuje w wielu rolach

Ale czytając S14, Rozumiem:

Rola może nie dziedziczyć z klasy, ale może składać się z innych ról. Jednak ta kompozycja "kolesia" nie jest oceniana do czasu komponowania klasy. Oznacza to, że jeśli dwie role sprowadzają się do tego samego kumpla, nie ma konfliktu - to tak, jakby klasa wcieliła się w rolę kolesiów, a odpowiednie role nie. Rola może nigdy nie być w konflikcie z samym sobą, bez względu na metodę jej inkorporacji.

Czytałem, że oznaczać, że role są stosowane tak późno, jak to możliwe, więc klasa Thingy będzie w stanie wyplątać że Alpha jest zawarta w dwóch różnych części. Pomyślałem, że to będzie działać jak tworzenie listy wszystkich ról, które będą składać się na końcową klasę, a następnie stosowanie tej listy tylko do ostatniej klasy. W ten sposób coś takiego jak Either może łączyć tylko te rzeczy, które zdefiniował i będzie polegało na późniejszej kompozycji, aby wprowadzić Alpha.

Przebiegłem to, gdy próbowałem implementować gramatykę dla różnych (IETF) dokumentów RFC. Wiele z nich odwołuje się do gramatyk z innych RFC, co uniemożliwia Perlowi 6 rozstrzyganie dziedziczenia przez C3. Pomyślałem więc, że role oderwą związki. Najwyraźniej tak nie jest.

+0

Czy ma to coś wspólnego z gramatyką? Następujące błędy kończą się tak samo (i zgodnie z oczekiwaniami): 'perl6 -e 'rola Foo {method bar {}}; rola Baz {pasek metod {}}; class My :: Grammar {także robi Foo; również robi Baz; } '' W przeciwnym razie możesz, oczywiście, rozwiązać go samodzielnie (co jest wymienione w dokumentach dla ról):' Host tokena {$ = [' : "<.port>]? } ' – ugexe

+0

Nie jest to zasadniczo specyficzne dla gramatyk, ale o wiele bardziej użyteczne dla nazwanych reguł, które mogą pojawić się w kilku częściach gramatyki. Wolałbym nie rozwiązywać problemów samemu, ponieważ jest to ogromny bałagan, gdy gramatyki są ogromne. –

+2

Odpowiedź na pytanie w tytule brzmi "tak, powinno". –

Odpowiedz

3

Tak, Perl 6 powinien być w stanie rozłączyć włączenie tej samej roli z różnych źródeł.

Proste definition s o role są:

Rola obudowuje jakiś kawałek zachowania lub stanu, które mogą być dzielone między klasami.

lub

Rola to nazwa dla dyskretnego zbioru zachowań.

Więc powiedzmy, że mamy Floatable zachowanie dla obiektów, które mogą być położone na wodzie i Sailable zachowanie dla obiektów, które mogą być wypłynął. Oczywiście obiekty, które można popłynąć, mogą pływać. A Sloop jest naturalnie pływający i nadaje się do żeglugi. Nie ma konfliktu w tym, że zachowanie jest przenoszone zarówno przez role , jak i Sailable.

W Perl, to działa zgodnie z oczekiwaniami (działa z Moose również):

#!/usr/bin/env perl 

use v5.24; # why not 
use warnings; 

package Floatable { 
    use Moo::Role; 
    sub float { say "float" } 
} 

package Sailable { 
    use Moo::Role; 
    with 'Floatable'; 
    sub sail { $_[0]->float; say "sail" }; 
} 

package Sloop { 
    use Moo; 
    with qw(Floatable Sailable); 
} 

my $s = Sloop->new; 

$s->sail; 

Takie zachowanie jest intuicyjnie oczywiste.

Jeden problem zauważyłem kiedy patrząc na Perl6 documentation for roles jest brak prostych, definicji jedno zdanie:

Role są pod pewnymi względami podobne do klas, w tym są one zbiorem atrybutów i metod. Różnią się one tym, że role służą także do opisywania tylko części zachowania obiektu i sposobu, w jaki role są stosowane do klas. Lub, aby sformułować to inaczej, klasy służą do zarządzania obiektami, a role służą do zarządzania zachowaniem i ponownym użyciem kodu.

...

aplikacja Rola znacznie różni się od klasy dziedziczenia. Gdy rola zostanie zastosowana do klasy, metody tej roli są kopiowane do klasy. Jeśli wiele klas zostanie zastosowanych do tej samej klasy, konflikty (na przykład atrybuty lub metody inne niż wiele o tej samej nazwie) powodują błąd kompilacji, który można rozwiązać, podając w klasie metodę o tej samej nazwie.

Podobno kiedy perl6 napotyka dwie role, które zapewniają dokładnie taki sam zachowanie , że myśli o tym, jak konflikt w sposób znajdę nierozsądne.

Uwaga subtelne rozróżnienie w poniższym przykładzie:

#!/usr/bin/env perl 

use v5.24; # why not 
use warnings; 

package Floatable { 
    use Moo::Role; 
    sub float { say "float" } 
} 

package Sailable { 
    use Moo::Role; 
    sub float { say "floating bonds to finance journey "} 
    sub sail { $_[0]->float; say "sail" }; 
} 

package Sloop { 
    use Moo; 
    with qw(Floatable Sailable); 
} 

my $s = Sloop->new; 

$s->sail; 

W tym przypadku konflikt należy się spodziewać, ponieważ dwie różne role chcą zastrzeżenia, aby zapewnić te same zachowania.