Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2009-05

Assigning to inherited property calls setter of the child class

7 messages · 2 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Alexander Klenin

This mail is to discuss issue http://bugs.freepascal.org/view.php?id=13630.

From the issue description:

Given the definitions:

type
  T1 = class
    procedure SetP(AP: Integer); virtual;
    property P: Integer read FP write SetP;
  end;
  T2 = class(T1)
    procedure SetP(AP: Integer); override;
  end;
procedure T1.SetP(AP: Integer);
begin Writeln('T1.SetP'); end;
procedure T2.SetP(AP: Integer);
begin Writeln('T2.SetP'); inherited P := AP; end;
the assignment t2obj.P := 1 causes infinite recursion,
because "inherited P := AP" calls T2.SetP instead of T1.SetP.

This problem was already reported, fixed, but the fix was reverted: http://bugs.freepascal.org/view.php?id=10927
http://bugs.freepascal.org/view.php?id=10979
(sorry for not searching the Mantis myself before posting the issue).

However, I believe that the problem in issue 10979 was caused by incorrect fix to 10927 and it is actually possible (and desirable) to fix both.

inherited P := V

Should:
1) Search base classes to find the definition of P in some class B.
2) If it is not writable, error out.
3) If it writes to a field, do that.
4) If it has setter named "SetP", do the equivalent of "inherited SetP".

it is the presence vs. absence "inherited" in step 4 that should have been changed
to fix 10927, but it sounds like a "B.SetP" was used instead, which caused issue 10979.

Regarding Delphi compatibility -- note that current behavior leads to stack overflow in both Delphi and FPC, so I doubt there are many programs relying on it ;-)

Alexander S. Klenin

Reply by email

Mattias Gaertner
to Alexander Klenin
Show quoted text 41 lines
This mail is to discuss issue http://bugs.freepascal.org/view.php?id=13630. >From the issue description: Given the definitions: type T1 = class procedure SetP(AP: Integer); virtual; property P: Integer read FP write SetP; end; T2 = class(T1) procedure SetP(AP: Integer); override; end; procedure T1.SetP(AP: Integer); begin Writeln('T1.SetP'); end; procedure T2.SetP(AP: Integer); begin Writeln('T2.SetP'); inherited P := AP; end; the assignment t2obj.P := 1 causes infinite recursion, because "inherited P := AP" calls T2.SetP instead of T1.SetP. This problem was already reported, fixed, but the fix was reverted: http://bugs.freepascal.org/view.php?id=10927 http://bugs.freepascal.org/view.php?id=10979 (sorry for not searching the Mantis myself before posting the issue). However, I believe that the problem in issue 10979 was caused by incorrect fix to 10927 and it is actually possible (and desirable) to fix both. inherited P := V Should: 1) Search base classes to find the definition of P in some class B. 2) If it is not writable, error out. 3) If it writes to a field, do that.

So far, so good.

4) If it has setter named "SetP", do the equivalent of "inherited SetP".

Why?

"inherited P" should look up P in the ancestor class. The setter of P belongs to the internal implementation of the class. If you want to access the inherited setter, call it with inherited SetP.

Show quoted text 8 lines
it is the presence vs. absence "inherited" in step 4 that should have been changed to fix 10927, but it sounds like a "B.SetP" was used instead, which caused issue 10979. Regarding Delphi compatibility -- note that current behavior leads to stack overflow in both Delphi and FPC, so I doubt there are many programs relying on it ;-)

Mattias

Reply by email

Alexander Klenin
to Mattias Gaertner
Mattias Gaertner wrote
> 4) If it has setter named "SetP", do the equivalent of "inherited > SetP". Why?

Because this surprises developers and leads to bugs. See the issue http://bugs.freepascal.org/view.php?id=13418 (linked from the discussed one) for a recent example.

"inherited P" should look up P in the ancestor class. The setter of P belongs to the internal implementation of the class. If you want to access the inherited setter, call it with inherited SetP.
Alternative solution would be to issue a warning if
TInherited.SetP contains "inherited P := V" and SetP is virtual.
Alexander S. Klenin

Reply by email

Mattias Gaertner
to Alexander Klenin
Show quoted text 10 lines
On Sat, May 2, 2009 at 01:56, Mattias Gaertner wrote: >> 4) If it has setter named "SetP", do the equivalent of "inherited >> SetP". > > Why? Because this surprises developers and leads to bugs. See the issue http://bugs.freepascal.org/view.php?id=13418 (linked from the discussed one) for a recent example.

As Jonas already noted:
'That entirely depends on what you expect. "inherited property" now means "use the property as declared in the parent class", which in a sense is logical.'

You can create a bug report for the documentation that only mentions methods and maybe this is the reason for the confusion.

For example:

type
  TAncestor = class
  private
    procedure SetP1(const AValue: integer); virtual;
  public
    property P: integer write SetP1;
  end;
  TClassA = class(TAncestor)
  private
    procedure SetP1(const AValue: integer); override;
    procedure SetP2(const AValue: char);
  public
    constructor Create;
    property P: char write SetP2;
  end;
constructor TClassA.Create;
begin
  inherited P:=3; // use property P of the ancestor,
       // which calls SetP1, which is overridden in TClassA
       // It does *not* call SetP1 of the ancestor
  // To call the ancestor SetP1 use
  inherited SetP1(3);
end;
Show quoted text 7 lines
> "inherited P" should look up P in the ancestor class. > The setter of P belongs to the internal implementation of > the class. If you want to access the inherited setter, call it with > inherited SetP. Alternative solution would be to issue a warning if TInherited.SetP contains "inherited P := V" and SetP is virtual.

-1

Mattias

Reply by email

Alexander Klenin
to Mattias Gaertner
Mattias Gaertner wrote 10 lines
On Sat, 2 May 2009 02:17:48 +1100 Alexander Klenin wrote: > Because this surprises developers and leads to bugs. > See the issue http://bugs.freepascal.org/view.php?id=13418 > (linked from the discussed one) for a recent example. As Jonas already noted: 'That entirely depends on what you expect. "inherited property" now means "use the property as declared in the parent class", which in a sense is logical.'

Yes, I see. It is just in this particular case logic and intuition are in conflict.

You can create a bug report for the documentation that only mentions methods and maybe this is the reason for the confusion. For example:

[skipped example]

Although this is classic example of convoluted and bad code, it did convince me. Including _both_ this and my examples in documentation is a good idea. Is there a Mercurial mirror of FPC docs?

> Alternative solution would be to issue a warning if > TInherited.SetP contains "inherited P := V" and SetP is virtual. -1

Why? Your example does not cover this.

Alexander S. Klenin

Reply by email

Mattias Gaertner
to Alexander Klenin
Show quoted text 26 lines
On Sat, May 2, 2009 at 02:39, Mattias Gaertner wrote: > On Sat, 2 May 2009 02:17:48 +1100 > Alexander Klenin wrote: > >> Because this surprises developers and leads to bugs. >> See the issue http://bugs.freepascal.org/view.php?id=13418 >> (linked from the discussed one) for a recent example. > > As Jonas already noted: > 'That entirely depends on what you expect. "inherited property" now > means "use the property as declared in the parent class", which in > a sense is logical.' Yes, I see. It is just in this particular case logic and intuition are in conflict. > You can create a bug report for the documentation that only mentions > methods and maybe this is the reason for the confusion. > > For example: [skipped example] Although this is classic example of convoluted and bad code, it did convince me. Including _both_ this and my examples in documentation is a good idea. Is there a Mercurial mirror of FPC docs?

Don't know.
Will you create the bug report?

Show quoted text 6 lines
>> Alternative solution would be to issue a warning if >> TInherited.SetP contains "inherited P := V" and SetP is virtual. > > -1 Why? Your example does not cover this.

Because properties have nothing to do with methods.

It would be nice it FPC can give a warning/hint if 'inherited' is used and there is no such member in the current class. Because in this case the 'inherited' is useless and the programmer probably intended something other. This warning/hint can be given for all members - properties, methods and variables.

Mattias

Reply by email

Alexander Klenin
to Mattias Gaertner
Mattias Gaertner wrote
> Is there a Mercurial mirror of FPC docs? Don't know. Will you create the bug report?

http://bugs.freepascal.org/view.php?id=13632

Is the mirror would be available, I'd create a patch too.

Show quoted text 8 lines
> >> Alternative solution would be to issue a warning if > >> TInherited.SetP contains "inherited P := V" and SetP is virtual. > > > > -1 > > Why? Your example does not cover this. Because properties have nothing to do with methods.

Of course, SetP should be also write accessor for P property for the warning to occur.

Show quoted text 5 lines
It would be nice it FPC can give a warning/hint if 'inherited' is used and there is no such member in the current class. Because in this case the 'inherited' is useless and the programmer probably intended something other. This warning/hint can be given for all members - properties, methods and variables.

+1

Alexander S. Klenin

Reply by email