Open marklester opened 5 years ago
For that example code, you could do this (I replaced Number
with Integer
so it would compile):
interface Shape {
shared formal Integer area;
shared formal String name;
}
interface Rectangle satisfies Shape {
shared formal Integer length;
shared formal Integer width;
shared default actual Integer area => length * width;
}
class Square(length) satisfies Rectangle {
shared actual Integer length;
width = length;
shared actual String name => "Square";
}
Since you can use the default
annotation for Rectangle.area
, you don't need StandardRectangle
.
@CPColin the point was to use composition, no?
drawbacks ... is boilerplate associated with implementing pass through methods of the interface a class wants to support
Yeah. But I guess a question is how bad is this in Ceylon, given the possibility of using Ceylon's abbreviated syntax? And, is doing something like Rectangle::*
good, or would it always be better to list each member separately, to protect against future additions to the interface that you would want to review before simply delegating? I don't have a strong opinion on either.
For comparison, a streamlined implementation that's possible today:
interface Shape {
shared formal Integer area();
shared formal String name;
}
interface Rectangle satisfies Shape {
shared formal Integer length;
shared formal Integer width;
}
class StandardRectangle(
shared actual Integer length,
shared actual Integer width)
satisfies Rectangle {
area() => length * width;
name => "Rectangle";
}
class Square(Integer l) satisfies Rectangle {
value rectangle = StandardRectangle(l, l);
// delegate to StandardRectangle
length => rectangle.length;
width => rectangle.width;
area = rectangle.area;
name => "Square";
}
The idea would be to make composition as easy as implementation inheritance. The problem seems to be a common issue: https://en.wikipedia.org/wiki/Composition_over_inheritance#Drawbacks and other languages have come up with their solutiosn for it. https://kotlinlang.org/docs/reference/delegation.html
If you had something like this I don't think you would need extend on class
@marklester, kotlin is not a good example, it does not allow to delegate to its own property or some external object, but only to a constructor parameter which is very limiting I'd also prefer not to describe what to include but what to exclude in delegation declaration. like lombok does
Interface delegation would be a great addition to Ceylon. One of the drawbacks of composition over inheritance is boilerplate associated with implementing pass through methods of the interface a class wants to support. I believe this could be mitigated if the language supported Interface Delegation. The idea would be to have a keyword/annotation that allows for delegating parts of the implementing interface to child objects of a class
The statement would be in a constuctor of a class in form of:
the query would have several forms
Interface::* or Interface
Interface::<methodname>,<methodname>...
example: