Cursus Raku / Addendum 🆕 / Types en tekstmachines / Objecten en klassen / Exercises / Vormen met een gedeelde rol
Oplossing: Vormen met een gedeelde rol
Hier is een mogelijke oplossing voor de taak.
Code
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);
}🦋 Je kunt de broncode vinden in het bestand shapes-role.raku.
Uitvoer
Circle: 12.56636
Square: 9Opmerkingen
Strikt genomen zou de aanroep
$shape.areazonder de rol ook werken. Raku lost methoden op naam op op het moment van de aanroep, dus zolang elk object toevallig een methodeareaheeft, draait de lus — dat staat bekend als duck typing. Wat levert de rol ons hier dan werkelijk op? Twee garanties.De rol is een type dat je kunt eisen.
describeis gedeclareerd alssub describe(Shape $shape), dus accepteert ze alleen objecten dieShapedoen en weigert ze al het andere voordat de body draait. Geef haar een gewoon getal en het programma weigert te compileren:describe(42); # Calling describe(Int) will never work with declared signature (Shape $shape)
Zonder de rol bestaat zo’n type niet — een duck-getypeerde routine zou elk argument aannemen en pas later, diep binnenin, ontploffen wanneer ze bij
.areakomt.De rol is een contract.
areaals stomp declareren (method area { ... }) dwingt elke klasse die de rol doet haar eigenareate leveren. Vergeet die, en de fout kan niet onopgemerkt blijven: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 meldt de ontbrekende methode zodra de klasse samengesteld wordt — het programma weigert te compileren voordat er ook maar één
Triangle-object bestaat. En zelfs in een implementatie die de klassedefinitie aanvaardt, komt de fout uiterlijk aan het licht wanneer de methode gebruikt wordt: de stomp{ ... }die van de rol geërfd is, is echte code die metStub code executedsterft zodra iemand haar aanroept.$shape.^namevraagt het object om zijn klassenaam, dus labelt dezelfdedescribeelk resultaat correct zonder het type van tevoren te kennen.