Recent

Author Topic: Implementing interface methods with descendent types  (Read 1922 times)

daniel_sap

  • Jr. Member
  • **
  • Posts: 64
Implementing interface methods with descendent types
« on: February 17, 2024, 04:00:05 pm »
Hi,
In some languages the following feature is provided

1. You have one interface declaration with method which returns interface as result
2. some class implements the interface but changes the type of the Result to be descendant of the interface (or class which implements the interface, or class descendant of the descendant ... of class which implements interface).
It considers it as valid implementation of interface method.

Quote
  IMyInterface = interface
    function getNext(): IMyInterface;
  end;

  { TMyClass }

  TMyClass = class(TObject, IMyInterface)
  public
    function getNext(): TMyClass;
  end;


Do you know if it is planned to implement such feature.
Does this sound good for you to be implemented.

For me it is really helpful. I use it a lot in java


cdbc

  • Hero Member
  • *****
  • Posts: 1744
    • http://www.cdbc.dk
Re: Implementing interface methods with descendent types
« Reply #1 on: February 17, 2024, 05:12:47 pm »
Hi
Hmmm.... I think the objpascal language itself is too type-strict, to allow that.
Even if I see your point, it goes against the 'type-safe' nature of pascal ...and /this is not java/  :D
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11980
  • FPC developer.
Re: Implementing interface methods with descendent types
« Reply #2 on: February 17, 2024, 05:25:35 pm »
It would not work, because IMyInterface is references counted and TMyClass not.

ASerge

  • Hero Member
  • *****
  • Posts: 2347
Re: Implementing interface methods with descendent types
« Reply #3 on: February 17, 2024, 06:26:07 pm »
Does this sound good for you to be implemented.
For me it is really helpful. I use it a lot in java
It is not clear to me yet how this can be useful. But I can give you an example of how to simulate this:
Code: Pascal  [Select][+][-]
  1. type
  2.   IMyInterface = interface
  3.     function GetNext: IMyInterface;
  4.   end;
  5.  
  6.   TMyClass = class(TInterfacedObject, IMyInterface)
  7.   private
  8.     function GetMyInterface: IMyInterface; inline;
  9.     property X: IMyInterface read GetMyInterface implements IMyInterface;
  10.   public
  11.     function GetNext: TMyClass;
  12.   end;
  13.  
  14. function TMyClass.GetMyInterface: IMyInterface;
  15. begin
  16.   Result := IMyInterface(GetNext);
  17. end;

PascalDragon

  • Hero Member
  • *****
  • Posts: 5791
  • Compiler Developer
Re: Implementing interface methods with descendent types
« Reply #4 on: February 18, 2024, 02:00:03 pm »
Do you know if it is planned to implement such feature.
Does this sound good for you to be implemented.

This feature is called “result covariance” and FPC supports it for types that directly inherit from one another (e.g. classes), but for interface vs. implementing class this would not be possible (as marcov said), because classes are not reference counted but interfaces are (at least by default), thus the result would be handled differently, but calling code would not handle that correctly. In Java that is no problem due to the internal structure of the JVM, but in a language like Pascal it is.

Does this sound good for you to be implemented.
For me it is really helpful. I use it a lot in java
It is not clear to me yet how this can be useful.

You can make clear to users of the type that your function will always return a specfic subtype. E.g. imagine a virtual method returning TStrings and have a sub class that changes the result type to be TStringList, so it will be clear that this sub class will at least return descendant of TStringList (and yes, FPC supports that).

daniel_sap

  • Jr. Member
  • **
  • Posts: 64
Re: Implementing interface methods with descendent types
« Reply #5 on: February 19, 2024, 11:40:36 am »
Thank you all for the thoughts and for the information

About the interfaces reference counting sometimes I use the 'as' operator to get the actual object behind the interface
Quote
function TMyClass.getNext: TMyClass;
begin
  Result := fIntf as TMyClass;
end;

I read that this is Ok somewhere in the forum and it works fine for me.
So, I thought that if this does not affect reference counting, also if the compiler does it for me it will not affect reference counting too.

I'm not aware how the ref counting is implemented. May be after building the symbol tables and stacks during the code generation. But will check it.
I'm sure you know it very good and see the issue very clearly. But still at the moment I'm not sure how reference counting prevents the implementation of such feature.

ASerge

  • Hero Member
  • *****
  • Posts: 2347
Re: Implementing interface methods with descendent types
« Reply #6 on: February 20, 2024, 12:00:00 am »
But still at the moment I'm not sure how reference counting prevents the implementation of such feature.
Simple example with a reference counting, why is it dangerous to mix classes and interfaces:
Code: Pascal  [Select][+][-]
  1. uses Classes;
  2.  
  3. procedure Test;
  4. var
  5.   Obj: TInterfacedObject;
  6.   Inf: IInterface;
  7. begin
  8.   Obj := TInterfacedObject.Create;
  9.   try
  10.     Inf := Obj as IInterface;
  11.   finally
  12.     Obj.Free; // Error this: double free
  13.   end;
  14. end;
  15.  
  16. begin
  17.   Test;
  18. end.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5791
  • Compiler Developer
Re: Implementing interface methods with descendent types
« Reply #7 on: February 20, 2024, 09:46:02 pm »
About the interfaces reference counting sometimes I use the 'as' operator to get the actual object behind the interface
Quote
function TMyClass.getNext: TMyClass;
begin
  Result := fIntf as TMyClass;
end;

I read that this is Ok somewhere in the forum and it works fine for me.
So, I thought that if this does not affect reference counting, also if the compiler does it for me it will not affect reference counting too.

While casting an interface (that is implemented by a Pascal class) back to a Pascal class is explicitely supported through the as-operator, it does not mean that it's a good idea. If you access the class instance, but the interface that keeps it alive goes out of scope then you'll have a problem (as ASerge showed).

I'm not aware how the ref counting is implemented. May be after building the symbol tables and stacks during the code generation.

The compiler essentially inserts calls to _AddRef and _Release for an interface type. This would however be wrong for a class type, because class types are not reference counted.

daniel_sap

  • Jr. Member
  • **
  • Posts: 64
Re: Implementing interface methods with descendent types
« Reply #8 on: February 21, 2024, 08:22:34 pm »
Thank you, again for the info.

I will try to implement something specific for my needs, cause the classes which implement my interfaces never take advantage of reference counting.

I asked ChatGPT4 the same question from this topic and this is the answer :)
Quote
The feature you're describing relates to covariant return types.
Covariant return types allow a method in a subclass to have a return type that is a subtype of
the return type declared in the superclass or interface it overrides.
This feature is quite common in object-oriented programming languages like Java,
where it increases flexibility and allows for more specific return types in subclasses.

As of my last update in April 2023, Free Pascal (FPC) does not directly support covariant return types
in the way you've described for interfaces and classes.
In FPC, the return type of a method in a class that implements an interface must match exactly
the return type specified in the interface.
This strict typing is in line with the language's design goals of being strongly and statically typed,
prioritizing safety and clarity.

However, FPC is an actively developed language, and its feature set evolves over time.
The language's roadmap and feature planning are determined by its development team,
based on the needs of its user base, the language's design philosophy, and technical considerations.
Whether a feature like covariant return types for interfaces is planned or considered beneficial would
depend on these factors. Such a feature could indeed be useful for certain design patterns and could provide
additional flexibility and expressiveness in type hierarchies.

To find out if there are any plans to implement covariant return types or similar features in Free Pascal,
I recommend checking the official Free Pascal documentation, the Free Pascal roadmap,
or reaching out directly to the Free Pascal community through their forums or mailing lists.
These resources are often the best source of information about upcoming features, enhancements,
and design decisions within the language.

 

TinyPortal © 2005-2018