Recent

Author Topic: Compiler not understand "inherited;"  (Read 1647 times)

ASerge

  • Hero Member
  • *****
  • Posts: 1411
Compiler not understand "inherited;"
« on: February 21, 2019, 04:17:41 pm »
Code: Pascal  [Select]
  1. program Project1;
  2.  
  3. {$MODE OBJFPC}{$H+}
  4.  
  5. uses Interfaces, StdCtrls, LMessages;
  6.  
  7. type
  8.   TTest = class(TComboBox)
  9.     procedure CNCommand(var TheMessage: TLMCommand); message CN_COMMAND; // Copied from TCustomComboBox declaration
  10.   end;
  11.  
  12. procedure TTest.CNCommand(var TheMessage: TLMCommand);
  13. begin
  14.   //inherited CNCommand(TheMessage); // project1.lpr(14,13) Error: Identifier idents no member "CNCommand"
  15.   //inherited; // project1.lpr(15,12) Error: Wrong number of parameters specified for call to "CNCommand"
  16.                // customcombobox.inc(1078,27) Error: Found declaration: CNCommand(var TLMCommand);
  17. end;
  18.  
  19. begin
  20. end.
Uncomment to see errors. Tested on FPC 3.0.4 and FPC 3.1.1 in Windows.
If change to unrealized method-message, than it understands. For example, change to CNCommand + 1.
I can understand the first error - calling an inherited method from the private section. For the second error - not.
In Delphi such code does not generate a compiler error.

rvk

  • Hero Member
  • *****
  • Posts: 3842
Re: Compiler not understand "inherited;"
« Reply #1 on: February 21, 2019, 04:52:45 pm »
In Delphi such code does not generate a compiler error.
Then use {$MODE DELPHI}  8)

ASerge

  • Hero Member
  • *****
  • Posts: 1411
Re: Compiler not understand "inherited;"
« Reply #2 on: February 21, 2019, 06:06:16 pm »
Then use {$MODE DELPHI}  8)
Yeah, then it'll work. But it's still weird. As then in mode OBJFPC override methods messages? They are usually defined in the private section. And usually the parent handler is called. OBJFPC mode does not allow this scenario.

Zoran

  • Hero Member
  • *****
  • Posts: 1464
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Compiler not understand "inherited;"
« Reply #3 on: February 21, 2019, 09:37:54 pm »
Then use {$MODE DELPHI}  8)
Yeah, then it'll work. But it's still weird. As then in mode OBJFPC override methods messages? They are usually defined in the private section. And usually the parent handler is called. OBJFPC mode does not allow this scenario.

You are right. I tried to find this difference in documentation, but without success. Please report it, this should at least be documented.

I don't think that this can be changed by modeswitches, so you cannot do anything except using delphi mode.

As a workaround, you might create an intermediate class in separate unit, which only overrides the needed message method in protected block. For example:
Code: Pascal  [Select]
  1. unit UnitTestExposeMessage;
  2.  
  3. {$mode delphi}
  4.  
  5. interface
  6.  
  7. uses
  8.   StdCtrls, LMessages;
  9.  
  10. type
  11.   TComboBoxExposeMessage = class(TComboBox)
  12.   protected
  13.     procedure CNCommand(var TheMessage: TLMCommand); message CN_COMMAND;
  14.   end;
  15.  
  16. implementation
  17.  
  18. procedure TComboBoxExposeMessage.CNCommand(var TheMessage: TLMCommand);
  19. begin
  20.   //inherited CNCommand(TheMessage); // This still does not compile.
  21.   inherited; // But this compiles.
  22. end;
  23.  
  24. end.
  25.  

Only this intermediate unit has to be compiled in delphi mode, and then derive your class from this intermediate class:
Code: Pascal  [Select]
  1. unit UnitTest;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, StdCtrls, UnitTestExposeMessage, LMessages;
  9.  
  10. type
  11.   TTest = class(TComboBoxExposeMessage)
  12.   private
  13.     // ...
  14.   protected
  15.     procedure CNCommand(var TheMessage: TLMCommand); message CN_COMMAND;
  16.    // ...
  17.   public
  18.    // ...
  19.   end;
  20.  
  21. implementation
  22.  
  23. procedure TTest.CNCommand(var TheMessage: TLMCommand);
  24. begin
  25.   inherited CNCommand(TheMessage);
  26.   // more code...
  27. end;
  28.  
  29. end.
  30.          
  31.  


lucamar

  • Hero Member
  • *****
  • Posts: 2081
Re: Compiler not understand "inherited;"
« Reply #4 on: February 21, 2019, 10:54:21 pm »
I'm not sure of this (never tested it) but I think that to be able to call inherited, the method must be virtual in the parent class and you must override it in the child; otherwise the child's method just hides the parent's

However, this can't be done with message methods, if I'm reading the documentation properly, because they are somehow "special". Or maybe they can? Can you try this?:

Code: Pascal  [Select]
  1. program Project1;
  2.  
  3. {$MODE OBJFPC}{$H+}
  4.  
  5. uses Interfaces, StdCtrls, LMessages;
  6.  
  7. type
  8.   TTest = class(TComboBox)
  9.     procedure CNCommand(var TheMessage: TLMCommand); override; {message CN_COMMAND;}
  10.   end;
  11.  
  12. procedure TTest.CNCommand(var TheMessage: TLMCommand);
  13. begin
  14.   inherited CNCommand(TheMessage);
  15.  { Or just:
  16.   inherited;
  17.   }
  18. end;
  19.  
  20. begin
  21. end.

Since message methods are also virtual, it may work :-\
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.2/2.0.4  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

rvk

  • Hero Member
  • *****
  • Posts: 3842
Re: Compiler not understand "inherited;"
« Reply #5 on: February 21, 2019, 11:18:19 pm »
I'm not sure of this (never tested it) but I think that to be able to call inherited, the method must be virtual in the parent class and you must override it in the child; otherwise the child's method just hides the parent's

Actually, the inherited call is a special one where there does not need to be virtual/override.
Also see note #2 here https://castle-engine.io/modern_pascal_introduction.html#_calling_inherited_method

Quote
But the inherited keyword works regardless if the method is virtual or not. The inherited always means that the compiler starts searching for the method in an ancestor, and it makes sense for both virtual and not virtual methods.

The problem is that CNCommand is private in the ancestor so it can't be reached (in objfpc-mode).
« Last Edit: February 21, 2019, 11:19:56 pm by rvk »

Zoran

  • Hero Member
  • *****
  • Posts: 1464
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Compiler not understand "inherited;"
« Reply #6 on: February 21, 2019, 11:18:51 pm »

Since message methods are also virtual, it may work :-\

As you can see in ASerge's and my posts, it does not work in objfpc mode -- when the message method is private in parent class you cannot use inherited. However, in delphi mode you can (but only without the method name).

This difference between modes doesn't seem to be documented. However, it was probably made so intentionally -- for Delphi compatibility. If I remember well (I don't have Delphi any more), in VCL components message methods are almost always declared in private section, but this doesn't prevent overriding them in derived classes, this is allowed in Delphi. In LCL however, these methods are usually declared in published protected section (but not always, not in this case).

Edit: corrected lapsus - protected instead of published
« Last Edit: February 22, 2019, 09:09:53 pm by Zoran »