Corso di Raku / Appendice 🆕 / Tipi e macchine per il testo / Oggetti e classi / Exercises / Figure che condividono un ruolo
Soluzione: Figure che condividono un ruolo
Ecco una possibile soluzione del compito.
Codice
role Shape {
method area { ... }
}
class Circle does Shape {
has $.radius;
method area { 3.14159 * $.radius ** 2 }
}
class Square does Shape {
has $.side;
method area { $.side ** 2 }
}
sub describe(Shape $shape) {
say "{$shape.^name}: {$shape.area}";
}
for Circle.new(radius => 2), Square.new(side => 3) -> $shape {
describe($shape);
}🦋 Trova il programma nel file shapes-role.raku.
Output
Circle: 12.56636
Square: 9Commenti
A rigore, la chiamata
$shape.areafunzionerebbe senza alcun ruolo. Raku risolve i metodi per nome nel momento della chiamata, quindi finché ogni oggetto ha per caso un metodoarea, il ciclo gira — è ciò che si chiama tipizzazione a papera. Che cosa ci porta allora davvero il ruolo? Due garanzie.Il ruolo è un tipo che puoi richiedere.
describeè dichiarata comesub describe(Shape $shape), quindi accetta solo oggetti che assumonoShapee rifiuta tutto il resto prima che il corpo giri. Passale un semplice numero e il programma si rifiuta di compilare:describe(42); # Calling describe(Int) will never work with declared signature (Shape $shape)
Senza il ruolo non esiste un tipo simile: una routine tipizzata a papera prenderebbe qualunque argomento ed esploderebbe solo più tardi, in profondità, quando arriva a
.area.Il ruolo è un contratto. Dichiarare
areacome abbozzo (method area { ... }) costringe ogni classe che assume il ruolo a fornire il proprioarea. Dimenticalo, e l’errore non può passare inosservato:class Triangle does Shape { has $.base; has $.height; } # Method 'area' must be implemented by Triangle because it is required by roles: Shape. my $t = Triangle.new(base => 3, height => 4); say $t.area; # Stub code executed
Rakudo segnala il metodo mancante non appena la classe viene composta: il programma si rifiuta di compilare prima ancora che esista un solo oggetto
Triangle. E anche in un’implementazione che accettasse la definizione della classe, l’errore emergerebbe al più tardi quando il metodo viene usato: l’abbozzo{ ... }ereditato dal ruolo è codice vero che muore conStub code executednon appena qualcuno lo chiama.$shape.^namechiede all’oggetto il nome della sua classe, quindi lo stessodescribeetichetta correttamente ogni risultato senza conoscere il tipo in anticipo.