Recent

Author Topic: Helper declaration changes behaviour  (Read 1680 times)

damieiro

  • Full Member
  • ***
  • Posts: 200
Helper declaration changes behaviour
« on: December 18, 2018, 01:07:22 pm »
Hi!

I do not know if this is a feature or a bug. I have been testing helpers, and i note that the order in which is declared, changes the behaviour.

Example

Code: Pascal  [Select][+][-]
  1. program tohelperstest;
  2. {in this code, inherited calls tobject helper method}
  3.  
  4.  
  5. uses classes, sysutils;
  6.  
  7. type
  8. TObjectHelper = class helper for TObject
  9.   public
  10.   procedure AfterConstruction; {hide TObject.Afterconstruction}
  11.   procedure BeforeDestruction;
  12. end;
  13.  
  14.  
  15. procedure TObjectHelper.AfterConstruction;
  16. begin
  17.   writeln ('TOH AC:',self.classname);
  18. end;
  19.  
  20. procedure TObjectHelper.BeforeDestruction;
  21. begin
  22.   writeln ('TOH BD:',self.classname);
  23. end;
  24.  
  25.  
  26. type
  27. TDescendant= class (Tobject)
  28.   public
  29.   procedure AfterConstruction;override;
  30.   procedure BeforeDestruction;override;
  31. end;
  32.  
  33. procedure TDescendant.AfterConstruction;
  34. begin
  35.   inherited;
  36.   writeln ('TDe AC:',self.classname);
  37. end;
  38.  
  39. procedure TDescendant.BeforeDestruction;
  40. begin
  41.   inherited;
  42.   writeln ('TDe BD:',self.classname);
  43. end;
  44.  
  45. type
  46. TDescendant2= class (TDescendant)
  47. end;
  48.  
  49.  
  50.  
  51. var
  52.   MyClass: TObject;
  53.   MyDescendant:TDescendant;
  54.   MyDescendant2:TDescendant2;
  55.  
  56.  
  57. begin
  58.   MyClass:=TObject.Create;
  59.   MyDescendant:=TDescendant.Create;
  60.   MyDescendant2:=TDescendant2.Create;
  61.  
  62.   writeln;
  63.   writeln ('Hi World');
  64.   writeln;
  65.  
  66.   FreeAndNil (MyClass);
  67.   FreeAndNil (MyDescendant);
  68.   FreeAndNil (MyDescendant2);
  69.   readln;
  70.  
  71. end.
  72.                                      
  73.  

But if the helper is declared After the other classes declaration is ignored.

Code: Pascal  [Select][+][-]
  1. program tohelperstest;
  2. {in this code, inherited does nothing, so i guess is called former TObject methods and not the helper ones...}
  3.  
  4.  
  5. uses classes, sysutils;
  6.  
  7. type
  8. TDescendant= class (Tobject)
  9.   public
  10.   procedure AfterConstruction;override;
  11.   procedure BeforeDestruction;override;
  12. end;
  13.  
  14. procedure TDescendant.AfterConstruction;
  15. begin
  16.   inherited;
  17.   writeln ('TDe AC:',self.classname);
  18. end;
  19.  
  20. procedure TDescendant.BeforeDestruction;
  21. begin
  22.   inherited;
  23.   writeln ('TDe BD:',self.classname);
  24. end;
  25.  
  26. type
  27. TDescendant2= class (TDescendant)
  28. end;
  29.  
  30.  
  31. {declared after}
  32. type
  33. TObjectHelper = class helper for TObject
  34.   public
  35.   procedure AfterConstruction; {hide TObject.Afterconstruction}
  36.   procedure BeforeDestruction;
  37. end;
  38.  
  39.  
  40. procedure TObjectHelper.AfterConstruction;
  41. begin
  42.   writeln ('TOH AC:',self.classname);
  43. end;
  44.  
  45. procedure TObjectHelper.BeforeDestruction;
  46. begin
  47.   writeln ('TOH BD:',self.classname);
  48. end;
  49.  
  50.  
  51.  
  52.  
  53. var
  54.   MyClass: TObject;
  55.   MyDescendant:TDescendant;
  56.   MyDescendant2:TDescendant2;
  57.  
  58.  
  59. begin
  60.   MyClass:=TObject.Create;
  61.   MyDescendant:=TDescendant.Create;
  62.   MyDescendant2:=TDescendant2.Create;
  63.  
  64.   writeln;
  65.   writeln ('Hi World');
  66.   writeln;
  67.  
  68.   FreeAndNil (MyClass);
  69.   FreeAndNil (MyDescendant);
  70.   FreeAndNil (MyDescendant2);
  71.   readln;
  72.  
  73. end.
  74.                                      
  75.  



damieiro

  • Full Member
  • ***
  • Posts: 200
Re: Helper declaration changes behaviour
« Reply #1 on: December 18, 2018, 01:14:59 pm »
Even an intercalate declaration changes behaviour

TDescendant doesn't go in helper scope, but TDescendant2, yes. I do not know it this is intended to work this way

Code: Pascal  [Select][+][-]
  1. program tohelperstest;
  2.  
  3. uses classes, sysutils;
  4.  
  5.  
  6. type
  7. TDescendant= class (Tobject)
  8.   public
  9.   procedure AfterConstruction;override;
  10.   procedure BeforeDestruction;override;
  11. end;
  12.  
  13. procedure TDescendant.AfterConstruction;
  14. begin
  15.   inherited;
  16.   writeln ('TDe AC:',self.classname);
  17. end;
  18.  
  19. procedure TDescendant.BeforeDestruction;
  20. begin
  21.   inherited;
  22.   writeln ('TDe BD:',self.classname);
  23. end;
  24.  
  25. type
  26. TObjectHelper = class helper for TObject
  27.   public
  28.   procedure AfterConstruction; {hide TObject.Afterconstruction}
  29.   procedure BeforeDestruction;
  30. end;
  31.  
  32.  
  33. procedure TObjectHelper.AfterConstruction;
  34. begin
  35.   writeln ('TOH AC:',self.classname);
  36. end;
  37.  
  38. procedure TObjectHelper.BeforeDestruction;
  39. begin
  40.   writeln ('TOH BD:',self.classname);
  41. end;
  42.  
  43.  
  44.  
  45. type
  46. TDescendant2= class (Tobject)
  47.   public
  48.   procedure AfterConstruction;override;
  49.   procedure BeforeDestruction;override;
  50. end;
  51.  
  52. procedure TDescendant2.AfterConstruction;
  53. begin
  54.   inherited;
  55.   writeln ('TDe AC:',self.classname);
  56. end;
  57.  
  58. procedure TDescendant2.BeforeDestruction;
  59. begin
  60.   inherited;
  61.   writeln ('TDe BD:',self.classname);
  62. end;
  63.  
  64.  
  65. var
  66.   MyClass: TObject;
  67.   MyDescendant:TDescendant;
  68.   MyDescendant2:TDescendant2;
  69.  
  70.  
  71. begin
  72.   MyClass:=TObject.Create;
  73.   MyDescendant:=TDescendant.Create;
  74.   MyDescendant2:=TDescendant2.Create;
  75.  
  76.   writeln;
  77.   writeln ('Hi World');
  78.   writeln;
  79.  
  80.   FreeAndNil (MyClass);
  81.   FreeAndNil (MyDescendant);
  82.   FreeAndNil (MyDescendant2);
  83.   readln;
  84.  
  85. end.
  86.  
  87.  
  88.  

Thaddy

  • Hero Member
  • *****
  • Posts: 14200
  • Probably until I exterminate Putin.
Re: Helper declaration changes behaviour
« Reply #2 on: December 18, 2018, 02:26:30 pm »
The helper needs always be the LAST in scope, not only in a single program, but also in unit order. This is documented.
[edit] but even if I change it to a proper order there is something fishy going on....
« Last Edit: December 18, 2018, 02:40:42 pm by Thaddy »
Specialize a type, not a var.

damieiro

  • Full Member
  • ***
  • Posts: 200
Re: Helper declaration changes behaviour
« Reply #3 on: December 18, 2018, 02:52:36 pm »
Sorry for my bad english (i'm not english native speaker/writer)...

But if Last in scope, it would be ignored as i point in my example (first post). (Last scope, last declaration or am i understanding wrong?)

I only see that the order in which is processed is when taken into account (second post). I do not like that behaviour because i think it can be a source of errors. (well, i disklike helpers.). Just for testing..

Thaddy

  • Hero Member
  • *****
  • Posts: 14200
  • Probably until I exterminate Putin.
Re: Helper declaration changes behaviour
« Reply #4 on: December 18, 2018, 04:00:19 pm »
No, you understand correctly: it should work as you expect, but it doesn't in a simple program.
If I can determine it is a real bug, I will report it.
Specialize a type, not a var.

ASerge

  • Hero Member
  • *****
  • Posts: 2222
Re: Helper declaration changes behaviour
« Reply #5 on: December 18, 2018, 06:58:12 pm »
I think this is a compiler error and it should not work!

When you used the type TObjectHelper = class helper for TObject, this means that from this point the compiler will implicitly insert TObjectHelper instead of TObject.
First. AfterConstruction and BeforeDestruction hide the base virtual methods. And there should be a compiler warning about this.
Second.
Code: Pascal  [Select][+][-]
  1. TDescendant2 = class(TObject)
  2. public
  3.   procedure AfterConstruction; override;
  4.   procedure BeforeDestruction; override;
  5. end;
This code should not be compiled because the methods being overridden are not virtual (in helper). The compiler should throw an error.

For comparison, Delphi also does not issue a warning for the first case, but gives a compilation error for the second.


Thaddy

  • Hero Member
  • *****
  • Posts: 14200
  • Probably until I exterminate Putin.
Re: Helper declaration changes behaviour
« Reply #6 on: December 18, 2018, 08:44:26 pm »
@ASerge
The program and the theory differ:
There is an issue.
Consider this and examine its output:
Code: Pascal  [Select][+][-]
  1. program tohelperstest;
  2. {$mode delphi}
  3. uses classes, sysutils;
  4.  
  5. type
  6. TDescendant= class (Tobject)
  7.   public
  8.   procedure AfterConstruction;override;
  9.   procedure BeforeDestruction;override;
  10. end;
  11.  
  12. TDescendant2= class (Tobject)
  13.   public
  14.   procedure AfterConstruction;override;
  15.   procedure BeforeDestruction;override;
  16. end;
  17.  
  18. TObjectHelper = class helper for TObject
  19.   public
  20.   procedure AfterConstruction;reintroduce; {hide TObject.Afterconstruction}
  21.   procedure BeforeDestruction;reintroduce;
  22. end;
  23.  
  24.  
  25. procedure TDescendant.AfterConstruction;
  26. begin
  27.   inherited;
  28.   writeln ('Object scope --> TDe AC:',self.classname);
  29. end;
  30.  
  31. procedure TDescendant.BeforeDestruction;
  32. begin
  33.   inherited;
  34.   writeln ('Object scope --> TDe BD:',self.classname);
  35. end;
  36.  
  37. procedure TDescendant2.AfterConstruction;
  38. begin
  39.   inherited;
  40.   writeln ('Object scope --> TDe AC:',self.classname);
  41. end;
  42.  
  43. procedure TDescendant2.BeforeDestruction;
  44. begin
  45.   inherited;
  46.   writeln ('Object scope -->TDe BD:',self.classname);
  47. end;
  48.  
  49. procedure TObjectHelper.AfterConstruction;
  50. begin
  51.   writeln ('helper scope --> TOH AC:',self.classname);
  52. end;
  53.  
  54. procedure TObjectHelper.BeforeDestruction;
  55. begin
  56.   writeln ('helper scope --> TOH BD:',self.classname);
  57. end;
  58.  
  59. var
  60.   MyClass: TObject;
  61.   MyDescendant:TDescendant;
  62.   MyDescendant2:TDescendant2;
  63. begin
  64.   MyClass:=TObject.Create;
  65.   MyDescendant:=TDescendant.Create;
  66.   MyDescendant2:=TDescendant2.Create;
  67.  
  68.   writeln;
  69.   writeln ('Hi World');
  70.   writeln;
  71.  
  72.   FreeAndNil (MyClass);
  73.   FreeAndNil (MyDescendant);
  74.   FreeAndNil (MyDescendant2);
  75.   readln;
  76.  end.
Specialize a type, not a var.

 

TinyPortal © 2005-2018