View Issue Details

IDProjectCategoryView StatusLast Update
0036354FPCCompilerpublic2019-11-30 13:21
ReporterZamrony P. JuharaAssigned To 
PrioritynormalSeverityminorReproducibilityalways
Status newResolutionopen 
Product Version3.0.4Product Build 
Target VersionFixed in Version 
Summary0036354: Feature request: Add ability for an interface to inherit from multiple interfaces
Descriptiontype

     IInterfaceA = interface
           procedure callA();
     end;

     IInterfaceB = interface
           procedure callB();
     end;

     IInterfaceAB = interface(IInterfaceA, IInterfaceB)
     end;

IInterfaceAB will automatically has callA() and callB() method and compatible with IInterfaceA or IInterfaceB without need to use as operator.
TagsNo tags attached.
Fixed in Revision
FPCOldBugId
FPCTarget
Attached Files

Activities

Ugochukwu Mmaduekwe

2019-11-25 08:59

reporter   ~0119483

Supported, this would be a very welcome addition.

Thaddy de Koning

2019-11-25 12:34

reporter   ~0119487

How? Are duplicate methods to be supported? (many discussions about multiple inheritance)
On class level and with as/is this is already supported. Which avoids the above.
I don't think this is a feasable option. It would require maintenance of a list of interfaces per interface and would introduce ambiguity.

Zamrony P. Juhara

2019-11-26 01:54

reporter   ~0119502

The purpose of feature I request is to avoid duplicate method by segregated interface but also combine them if required.

For example, sometime I only want a method to callA() only, sometime callB only, but other time I may need to call both.

procedure needCallA(a : IInterfaceA);
begin
      a.callA();
end;

procedure needCallB(b : IInterfaceB);
begin
      b.callB();
end;

procedure needBoth(ab : IInterfaceAB);
begin
       ab.callA();
       ab.callB();
end;

and example implementation

TAB= class(TInterfacedObject, IInterfaceAB)
public
     procedure callA();
     procedure callB();
end;

var ab : IInterfaceAB;
ab := TAB.create();
needCallA(ab);
needCallB(ab);
needCallBoth(ab);

In Free Pascal 3.0.4, if I need to be able to call both method and still using segregated interface

procedure needBoth(a : IInterfaceA; b : IInterfaceB);
begin
       a.callA();
       b.callB();
end;

even though underlying implementation may be coming from same class

var a: IInterfaceA;
      b : IInterfaceB;

a := TAB.create();
b := a as IInterfaceB;
needBoth(a, b);

so more variable to handle. I can create IInterfaceAB extends from IInterfaceA, but then I need to duplicate callB() method signature code

IInterfaceAB = interface(IInterfaceA)
     procedure callB();
end;

I know its hard but it is not impossible. Java, C#, Go, PHP, they allow an interface to extends from one or more interfaces.

Thaddy de Koning

2019-11-26 08:32

reporter   ~0119504

It is not quite the same, but there is support to extend an existing interface through type helpers from 3.2.0
https://wiki.freepascal.org/FPC_New_Features_3.2#Support_for_helper_types_extending_interface_types
And in trunk, multiple helpers can be in scope at the same time:
https://wiki.freepascal.org/FPC_New_Features_Trunk#Support_for_multiple_active_helpers_per_type

This can be used to achieve the same effect (and has the same drawbacks as e.g. in Java)

Thaddy de Koning

2019-11-26 12:24

reporter   ~0119505

See also https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem

Zamrony P. Juhara

2019-11-27 02:26

reporter   ~0119522

I am aware of diamond problem when dealing with class multiple inheritance. But feature I request is not about a class inherit from multiple classes. CMIIW, interface extends from multiple interfaces does not have diamond problem because an interface only defines method signature not how it should be implemented. So if multiple interfaces shares indentical method signature, descendant interface can merge them as one.

Marco van de Voort

2019-11-29 11:47

manager   ~0119549

Last edited: 2019-11-29 11:51

View 3 revisions

I thought about it, but the trick will be how to get the sub interface. IOW if objectA implements the both interface, how do I get a reference for only the A or B interface?

With single inheritance ancestors still start at the first item, just the length varies. With this construct, also an offset is needed since one of the two will be at an offset of A. Maybe importing into object a can take care of that in the tables, maybe not, but my guess is that's where the trouble is.

Sven Barth

2019-11-30 13:21

manager   ~0119560

There is also the following to consider:

=== code begin ===

type
  IInterfaceA = interface
    procedure callA;
  end;

  IInterfaceB = interface
    procedure callB;
  end;

  IInterfaceAB = interface({IInterfaceA, }IInterfaceB)
  end;

  TMyClass = class(TInterfacedObject, IInterfaceAB, IInterfaceA)
    procedure IInterfaceA.callA = myCallA;
    procedure myCallA;
    procedure callB;
  end;

=== code end ===

Now do I need to have to declare callA nevertheless, because IInterfaceAB requires it? Or do I have to alias IInterfaceAB.callA as well? (I'd say the later, cause that is then consistent with how inherited interfaces behave currently)

And the point that Marco mentioned is important as well: you can only get directly implemented interfaces through GetInterface, this is not going to change, because that opens a whole other can of worms. If you only implement IInterfaceAB then you *can not* get a direct reference to an IInterfaceA without first retrieving the IInterfaceAB and then converting that to an IInterfaceA. And there we'll then have the problem of correctly constructing the method tables: We'll essentially have to copy the way vtables work in MSVC, because the whole concept of interfaces is supposed to be COM compatible which is essentially MS Visual C++.

Issue History

Date Modified Username Field Change
2019-11-25 06:40 Zamrony P. Juhara New Issue
2019-11-25 08:59 Ugochukwu Mmaduekwe Note Added: 0119483
2019-11-25 12:34 Thaddy de Koning Note Added: 0119487
2019-11-26 01:54 Zamrony P. Juhara Note Added: 0119502
2019-11-26 08:32 Thaddy de Koning Note Added: 0119504
2019-11-26 12:24 Thaddy de Koning Note Added: 0119505
2019-11-27 02:26 Zamrony P. Juhara Note Added: 0119522
2019-11-29 11:47 Marco van de Voort Note Added: 0119549
2019-11-29 11:48 Marco van de Voort Note Edited: 0119549 View Revisions
2019-11-29 11:51 Marco van de Voort Note Edited: 0119549 View Revisions
2019-11-30 13:21 Sven Barth Note Added: 0119560