Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

Proposal for Interface Delegation #7434

Open
marklester opened this issue Oct 30, 2018 · 4 comments
Open

Proposal for Interface Delegation #7434

marklester opened this issue Oct 30, 2018 · 4 comments

Comments

@marklester
Copy link

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:

delegate <query> to object

the query would have several forms

  • delegate all methods:
    • Interface::* or Interface
  • delegate some methods:
    • Interface::<methodname>,<methodname>...
  • any method defined in the class would take precedent over the delegation

example:

interface Shape{
	shared formal Number area();
	shared format String name();
}

interface Rectangle extends Shape{
	shared formal Number length();
	shared format Number width();
}

class StandardRectangle(Number length,Number width) implements Rectangle{
	shared actual Number area(){
		return length*width;
	}
	
	shared actual String name(){
	  return "Rectangle"
	}
}

class Square(length) implements Rectangle{
	value rectangle = StandardRectangle(length,length);
	delegate Rectangle::* to rectangle;
	//or 	delegate Rectangle::length,width,area to rectangle;
	//or 	delegate Rectangle to rectangle;

	shared actual String name(){
	  return "Square"
	}	
}
@CPColin
Copy link
Contributor

CPColin commented Oct 30, 2018

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.

@jvasileff
Copy link
Contributor

jvasileff commented Oct 30, 2018

@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";
}

@marklester
Copy link
Author

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

@guai
Copy link

guai commented Feb 1, 2019

@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

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants