[fpc-pascal] Traits Proposal

Sven Barth pascaldragon at googlemail.com
Fri Feb 19 07:30:45 CET 2021


Am 18.02.2021 um 23:58 schrieb Ryan Joseph via fpc-pascal:
>
>> On Feb 18, 2021, at 3:07 PM, Sven Barth <pascaldragon at googlemail.com> wrote:
>>
>>> So "class type method resolution" is what's missing? I never used the interface method resolution so I don't really understand this feature. What needs to happen as far as the compiler is concerned?
>> The problem is this: if you have a property with an interface type the compiler can simply build the interface's VMT for this. However for classes (or objects or records) the compiler needs to generate slightly different thunks that fixup the correct Self value, especially if things are mixed between the subclass and the container class.
> Then this is the real challenge to implement a "default implements property" and something I know nothing about. :) The rest is pretty easy actually though.

Correct, that is the real challenge ;)


>>> type
>>>    TMyShape = class(TShape, ICircle)
>>>      private
>>>        m_circle: TCircle;
>>>      protected
>>>        procedure ICircle.Draw = Draw;
>>>      public
>>>        property circle: TCircle read m_circle implements ICircle;
>>>    end;
>> Your specific example is rather useless, cause your interface only has a single method that you redirect to the class' method thus you wouldn't need to use interface delegation. But anyway, your code would generate a runtime error, because your TMyShape.Draw would still be abstract.
> Maybe it's a bad example but I'm trying to illustrate how method resolution could be used for overriding (or what ever it would be called in this context.
>
> I know this isn't correct syntax but it's more of this direction:
>
> procedure Draw =  ICircle.Draw;
>
> TShape.Draw is resolved by ICircle.Draw, which is implemented via TCircle. It's quasi-overriding but the VMT table should point to m_circle.Draw so Draw could be called on TShape and get property resolved by the "implements ICircle" property. Hope that makes sense.
Let me get it straight: your example is that both TShape and TCircle 
provide a Draw method, but in TMyShape you want TCircle.Draw to be used 
instead of TShape.Draw when TMyShape.Draw is called. Correct so far?

Well that would work without any additional declarations. The idea would 
be that the "default" modifier would lead to conflicts only if a Draw 
method exists in TMyShape itself. If it's declared in one of the parents 
then that won't matter.

The only thing that will not work and which will continue not to work is 
that m_circle.Draw will not be called if you access the TMyShape through 
a TShape.Draw call. For that one needs to use an explicit declaration:

=== code begin ===

type
   TMyShape = class(TShape, ICircle)
   private
     m_circle: TCircle;
   public
     procedure ICircle.Draw = Draw;
     property Circle: TCircle read m_circle implements ICircle;
     procedure Draw; override;
   end;

procedure TMyShape.Draw;
begin
   m_circle.Draw;
end;

=== code end ===

This way it does not matter if TCircle is a class, a record or an 
object, cause it will always work correctly.

Regards,
Sven


More information about the fpc-pascal mailing list