Recent

Author Topic: procedure is not procedure of object  (Read 4050 times)

Thaddy

  • Hero Member
  • *****
  • Posts: 19115
  • Glad to be alive.
Re: procedure is not procedure of object
« Reply #15 on: March 26, 2026, 01:27:16 pm »
There is a convenience function for that somewhere.
Forgot where, but is analogous to the KOL version.
Code: Pascal  [Select][+][-]
  1. function MakeMethod(code:pointer;data:pointer = nil):TNotifyEvent;inline;
  2. begin
  3.   TMethod(Result).Code := code;
  4.   TMethod(Result).Data := data;
  5. end;
(Even if I wrote it, which I did, I forgot where it ended up. It is very old.)
« Last Edit: March 26, 2026, 01:32:05 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

kagamma

  • New Member
  • *
  • Posts: 19
Re: procedure is not procedure of object
« Reply #16 on: March 26, 2026, 03:06:16 pm »
You can declare it as class procedure. This way you don't have to instantiate an object.

Code: Pascal  [Select][+][-]
  1. tdummy = class
  2.   class procedure ontimer(Sender: TObject);
  3. end;
  4. ...
  5.  
  6. Timer.OnTimer := @tdummy(nil).ontimer;

PascalDragon

  • Hero Member
  • *****
  • Posts: 6387
  • Compiler Developer
Re: procedure is not procedure of object
« Reply #17 on: March 26, 2026, 11:17:08 pm »
Whether this is good practice is debatable, but sometimes wrapping trivial contextless handlers in a class is overkill.

Please note that you should at least provide a procedure with a suitable signature, namely in case of TNotifyEvent with both Self and Sender parameters, cause depending on the platform and calling convention there might be issues with stack cleanup otherwise.

I need timers for non gui programs and since procedure is not procedure of object I had to introduce an otherwise unnecessary object that I can leave uninstantiated, see code below.

I feel this is a bit clumsy.
Is there a better way?

Using a dummy class is in fact the usual way to go. Or put all your code inside a class and call that from the main function (e.g. something like TMyApplication.Run or so, but without having to inherit from something like TCustomApplication).

hakelm

  • Full Member
  • ***
  • Posts: 173
Re: procedure is not procedure of object
« Reply #18 on: March 27, 2026, 10:14:29 am »
I didn't find any better way than to modify TFPTimer. Find the code attached.

kupferstecher

  • Hero Member
  • *****
  • Posts: 618
Re: procedure is not procedure of object
« Reply #19 on: March 27, 2026, 11:28:33 am »
[...] for non gui programs [...] had to introduce an otherwise unnecessary object [...]
OOP is also for non-GUI programs really helpful. I personally even use it on microcontrollers with static memory (using object instead of class).

Thaddy

  • Hero Member
  • *****
  • Posts: 19115
  • Glad to be alive.
Re: procedure is not procedure of object
« Reply #20 on: March 27, 2026, 12:42:34 pm »
@hakelm
The constructor is wrong: it needs to set the inherited parent.
It may work by accident, but only because you want to initialize as nil.
objects are fine constructs. You can even initialize them with constructors.

rvk

  • Hero Member
  • *****
  • Posts: 7014
Re: procedure is not procedure of object
« Reply #21 on: March 27, 2026, 01:27:26 pm »
The constructor is wrong: it needs to set the inherited parent.
Parent? For a non-visual component?

Do you mean owner?
Even then, it can remain ownerless but you do need to free the instance yourself then.

I would keep the Create the same as the base class. That way you can pass nil in the create code or assign an owner if you want.

I'm also missing the " of object" after the tproc (which is for OnTimer).

Thaddy

  • Hero Member
  • *****
  • Posts: 19115
  • Glad to be alive.
Re: procedure is not procedure of object
« Reply #22 on: March 27, 2026, 02:05:10 pm »
The IDE says so ;) Anyway, do so.
Also: the code flow is otherwise ok, since he sets the OnTimer (TNotifyEvent) from his own OnWhatevertimer, which is NOT a notify event, so that part is correct.
Suggestion is:
Code: Pascal  [Select][+][-]
  1. unit noPoOtimer;
  2. {$mode delphi}{$H+}
  3. interface
  4.  
  5. uses
  6.   Classes, sysutils, fptimer;
  7. type
  8.   TTimerProc=procedure(Sender: TObject); // NOT of object...taken care of
  9.   { tNoPoOTimer }
  10.   TNoPoOTimer=class(TFPTimer)
  11.   private
  12.     fOnNoPoOtimer:TTimerProc;
  13.     procedure setOnNoPoOtimer(AValue: TTimerProc);
  14.     procedure timeisup(Sender: TObject);
  15.   public
  16.     constructor create(aOwner:TComponent);override;
  17.     property OnNoPoOtimer:TTimerProc read fOnNoPoOtimer write setOnNoPoOtimer;
  18.   end;
  19. implementation
  20.  
  21. procedure tNoPoOTimer.timeisup(Sender: TObject);
  22. begin
  23.   if assigned(OnNoPoOtimer) then
  24.     OnNoPoOtimer(sender);
  25. end;
  26.  
  27. procedure tNoPoOTimer.setOnNoPoOtimer(AValue: TTimerProc);
  28. begin
  29.   self.OnTimer:=timeisup;
  30.   fOnNoPoOtimer:=AValue;
  31. end;
  32.  
  33. constructor tNoPoOTimer.create(aOwner:TComponent);
  34. begin
  35.   inherited create(aOwner);
  36.   self.OnTimer:=timeisup; //<-----
  37. end;
  38. end.
What he did is a redirection.


« Last Edit: March 27, 2026, 02:07:30 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

hakelm

  • Full Member
  • ***
  • Posts: 173
Re: procedure is not procedure of object
« Reply #23 on: March 27, 2026, 02:23:08 pm »
I seldom use gui-programs, but you are right a constructor with (AOwner: TComponent) is better.
tproc is used when setting onnopootimer for a "normal" procedure ie not for a "method" procedure so it can't have  an "of object "specification.

valdir.marcos

  • Hero Member
  • *****
  • Posts: 1258
Re: procedure is not procedure of object
« Reply #24 on: March 30, 2026, 06:38:48 am »
Interesting.

hakelm

  • Full Member
  • ***
  • Posts: 173
Re: procedure is not procedure of object
« Reply #25 on: March 30, 2026, 09:58:22 am »
I should perhaps have pointed out that

for methods or procedures of object you use
the inherited tNoPoOTimer.OnTimer

for "normal" procedures you use
tNoPoOTimer.onnopootimer

rvk

  • Hero Member
  • *****
  • Posts: 7014
Re: procedure is not procedure of object
« Reply #26 on: March 30, 2026, 10:12:56 am »
What he did is a redirection.
Ah, yes, you are correct. I missed the point to assigning a normal procedure.

BTW. I would have suggested a slightly adapted code. There would be no need for using the current FOnTimer. That would even break existing code. If you are inheriting the TFPTimer the 'proper' way to would be to override the caller of FOnTimer. In TFPTimer this would be the Timer procedure itself. That way, the original FOnTimer would still usable but you create an extra FOnProcTimer. At least this is how it's done in all classes throughout the VCL code in Delphi. Something like this:

Code: Pascal  [Select][+][-]
  1. type
  2.   TTimerProc = procedure(Sender: TObject);
  3.  
  4.   TProcTimer = class(TFPTimer)
  5.   private
  6.     FOnProcTimer: TTimerProc;
  7.   protected
  8.     procedure Timer; override;
  9.   public
  10.     property OnProcTimer: TTimerProc read FOnProcTimer write FOnProcTimer;
  11.   end;
  12.  
  13. procedure TProcTimer.Timer;
  14. begin
  15.   if Active and Assigned(FOnProcTimer) then
  16.     FOnProcTimer(Self);
  17.   inherited;
  18. end;

But... there is a big problem. TFPTimer is really weirdly designed because it uses Assigned(FOnTime) inside StartTimer. So TFPTimer.Timer is create virtual but if you are overriding that in an inherited class, you don't get the expected functionality. They didn't have 'proper' object orientation and inheritance in mind when creating that class.

I would have used TTimer but unfortunately TTimer is depended on the LCL app loop... so... for a quick hack, 'misusing' TFPTimer.OnTimer is fine, but when using this class in a much bigger project, you might also want to override StartTimer (luckely that's also virtual defined) and remove the "Assigned(FOnTimer)" from the if statement at the top.
« Last Edit: March 30, 2026, 10:18:48 am by rvk »

LeP

  • Sr. Member
  • ****
  • Posts: 290
Re: procedure is not procedure of object
« Reply #27 on: March 30, 2026, 03:00:43 pm »
I use this, I had create it some times ago and used as standard in my project.
It can be used as Component in Design mode (in Delphi), at runtime, in a thread or with a method.

If used at runtime (and with a method or Thread procedure) it doesn't depend from VCL.
Should be compatible with FPC (I tried it few month ago), but I don't know if in FPC needs LCL or not.
« Last Edit: March 30, 2026, 03:05:01 pm by LeP »
Un Sistema per domarli, un IDE per trovarli, un codice per ghermirli e nel framework incatenarli.
An operating system to tame them, an IDE to find them, a code to catch them and in the framework chain them.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1590
    • Lebeau Software
Re: procedure is not procedure of object
« Reply #28 on: May 03, 2026, 11:00:02 pm »
There is a trick one can use: put the procedure pointer in the Code field of a TMethod record, set the Data pointer to nil (not necessary for this example, but try to be explicit anyway) then cast the record as a TNotifyEvent and assign to the event handler

Small nitpick - the procedure should have Self and Sender parameters declared explicitly, since that is how the compiler will actually be calling the procedure, even if the procedure doesn't look at them:

Code: Pascal  [Select][+][-]
  1. procedure onTimerProcedure(Self: Pointer; Sender: TObject);

Like you said, "try to be explicit". The Self will be the TMethod.Data value, and the Sender will be the timer object.



Dang it. I didnt notice that there was a 2nd page to this discussion. PascalDragon had already pointed out that same issue:

Please note that you should at least provide a procedure with a suitable signature, namely in case of TNotifyEvent with both Self and Sender parameters, cause depending on the platform and calling convention there might be issues with stack cleanup otherwise.
« Last Edit: May 03, 2026, 11:04:53 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

Thaddy

  • Hero Member
  • *****
  • Posts: 19115
  • Glad to be alive.
Re: procedure is not procedure of object
« Reply #29 on: May 05, 2026, 04:40:41 pm »
Except that I already pointed out OP did nothing wrong, maybe this old code will help you? (Trunk only):
Code: Pascal  [Select][+][-]
  1. program metref;
  2. {$mode delphi}
  3. type
  4.   TMeth = procedure(x: Integer) of object;
  5.   TMethRef = reference to procedure(x: Integer);
  6.  
  7. procedure MethRefToMethPtr(const MethRef; var MethPtr);
  8. type
  9.   TVtable = array[0..3] of Pointer;
  10.   PVtable = ^TVtable;
  11.   PPVtable = ^PVtable;
  12. begin
  13.   // 3 is offset of Invoke, after QI, AddRef, Release
  14.   TMethod(MethPtr).Code := PPVtable(MethRef)^^[3];
  15.   TMethod(MethPtr).Data := Pointer(MethRef);
  16. end;
  17.  
  18. function MakeMethRef: TMethRef;
  19. var
  20.   y: Integer;
  21. begin
  22.   y := 30;
  23.   Result := procedure(x: Integer)
  24.   begin
  25.     Writeln('x = ', x, ' and y = ', y);
  26.   end;
  27. end;
  28.  
  29. procedure P;
  30. var
  31.   x: TMethRef;
  32.   m: TMeth;
  33. begin
  34.   x := MakeMethRef();
  35.   MethRefToMethPtr(x, m);
  36.   Writeln('Using x:');
  37.   x(10);
  38.   Writeln('Using m:');
  39.   m(10);
  40. end;
  41.  
  42. begin
  43.   p();
  44. end.
Courtesy of Barry Kelly.
objects are fine constructs. You can even initialize them with constructors.

 

TinyPortal © 2005-2018