Recent

Author Topic: Name of calling procedure?  (Read 1409 times)

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1198
Name of calling procedure?
« on: November 04, 2024, 12:18:53 am »
I have some code for freeing a class instance that can be shared amongst several classes. When this class is shared I only want the class where it was created to be able to free it. The name of the class which created it is stored in the OWNER_NAME field. Currently I pass the name of class being destroyed as a parameter when this is called inside the destructor.
Code: Pascal  [Select][+][-]
  1. PROCEDURE TTABLE_WHERE.REMOVE( CONST OWNERNAME: SHORTSTRING) ;
  2.  BEGIN
  3.  IF (SELF <> NIL) AND (OWNER_NAME = OWNERNAME)
  4.     THEN SELF.Free;
  5.  END;
  6.  
  7. DESTRUCTOR TSQL_TEXTBOX.DESTROY;
  8. BEGIN
  9. TW.REMOVE(NAME);
  10. INHERITED;
  11. END;  

Is there a way to do this without using a parameter for the ownername. Is it possible to get the information about the class calling the procedure maybe?
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

MarkMLl

  • Hero Member
  • *****
  • Posts: 7999
Re: Name of calling procedure?
« Reply #1 on: November 04, 2024, 09:54:35 am »
What I've done in the past is explicitly push the name of each procedure when I enter it, and pop it on exit. Then when I have an error
I can output the top couple of entries from the stack.

See PushRule() etc. in https://github.com/MarkMLl/pesdump/blob/main/pesdump.lpr, but please note that in that specific program there's a modicum of cruft since $I %CURRENTROUTINE% was introduced in 3.2 which was "bleeding edge" at the time.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Zvoni

  • Hero Member
  • *****
  • Posts: 2737
Re: Name of calling procedure?
« Reply #2 on: November 04, 2024, 10:03:43 am »
Is there a way to do this without using a parameter for the ownername. Is it possible to get the information about the class calling the procedure maybe?
What about ClassInfo, ClassName et al?

EDIT: The Check "if Self <> Nil" confuses me, though.
I'm guessing that this Procedure is not a class procedure, so there MUST be an instance of "Self", so Self can never be Nil
« Last Edit: November 04, 2024, 10:08:00 am by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

Thaddy

  • Hero Member
  • *****
  • Posts: 16138
  • Censorship about opinions does not belong here.
Re: Name of calling procedure?
« Reply #3 on: November 04, 2024, 10:11:29 am »
I had a similar wish/idea and implemented it: did not work,
but @Warfley implemented it in the compiler and there is a merge request for it.
All this is very recent and we can not promise anything.
This is not so much about the name of the calling procedure, but about what you actually mean: release the class when it is no longer needed.
What we devised is a way to add an iinterface to any class that does not derive from TinterfacedObject, so you can initialize through the interface and release will be automatic.
« Last Edit: November 04, 2024, 10:15:43 am by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

rvk

  • Hero Member
  • *****
  • Posts: 6572
Re: Name of calling procedure?
« Reply #4 on: November 04, 2024, 11:10:42 am »
I have some code for freeing a class instance that can be shared amongst several classes. When this class is shared I only want the class where it was created to be able to free it. The name of the class which created it is stored in the OWNER_NAME field. Currently I pass the name of class being destroyed as a parameter when this is called inside the destructor.
What type of class is TTABLE_WHERE?
Why don't you just use the standard Owner parameter of TComponent?

So just inherit TTABLE_WHERE from TComponent (or higher) and you can use TTABLE_WHERE.Create(Owner).
After that... the owner will automatically Free the TTABLE_WHERE when it's destroyed.

If you really want to mess with calling Free like this for a non-owner-like component, then you might want to pass a pointer instead of a Name. But my guess is that you complicate things too much at this point (by not following the standard methods available to you).

Is there a way to do this without using a parameter for the ownername. Is it possible to get the information about the class calling the procedure maybe?
Yes, there is. But you first need to show us the interface of that TTABLE_WHERE.

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1198
Re: Name of calling procedure?
« Reply #5 on: November 04, 2024, 01:41:32 pm »
Thanks for the answers, maybe I should elaborate
Tableware is a class that is not an lcl componet it holds information about an sqlite table such as table name, where condition for sql statements,name of class where it was created and type of columns to be used.

I use this ttablewhere class with my gui controls to load things from table into them.

Sometimes I have two gui controls working together on the same columns from the same table so I want to have the typed pointer for table where point to an instance of table where created in another class rather than having to create and instantiate two instances of table where.

In the destructor I want to free tablewhere but if it’s being shared I certainly don’t want to free it twice. So I came up with idea that only the class that created it should be allowed to free it.

This could cause trouble if class that created it is destroyed before class sharing it. Maybe I’m going about this in the wrong way. Maybe I need to have a flag in the class that has Ttablewhere pointer that lets me know if it should be freed....

Nonetheless I’m still curious if it’s possible to be able to know where a call to a method came from just like the stacktrace knows where the method call originated.

Also I find it strange how a nil Typed pointer can access class methods
« Last Edit: November 04, 2024, 01:58:02 pm by Joanna from IRC »
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

Fibonacci

  • Hero Member
  • *****
  • Posts: 594
  • Internal Error Hunter
Re: Name of calling procedure?
« Reply #6 on: November 04, 2024, 01:57:35 pm »
Here is an example of auto-destroying class if refcount drops to 0. Maybe you'll make use of it. "Destroy" isnt called, its auto destroyed once out of scope, so after "main" ends.

Code: Pascal  [Select][+][-]
  1. program app;
  2.  
  3. type
  4.   tsomeclass = class(TInterfacedObject, IUnknown)
  5.     constructor Create;
  6.     destructor Destroy; override;
  7.     procedure hi;
  8.   end;
  9.  
  10. constructor tsomeclass.Create;
  11. begin
  12.   writeln('Create');
  13. end;
  14.  
  15. destructor tsomeclass.Destroy;
  16. begin
  17.   writeln('Destroy');
  18. end;
  19.  
  20. procedure tsomeclass.hi;
  21. begin
  22.   writeln('hi');
  23. end;
  24.  
  25. procedure main;
  26. var
  27.   t: tsomeclass;
  28. begin
  29.   t := tsomeclass.Create as IUnknown as tsomeclass;
  30.   t.hi;
  31. end;
  32.  
  33. begin
  34.   main;
  35.   writeln('end of program');
  36.   readln;
  37. end.
« Last Edit: November 04, 2024, 01:59:29 pm by Fibonacci »

MarkMLl

  • Hero Member
  • *****
  • Posts: 7999
Re: Name of calling procedure?
« Reply #7 on: November 04, 2024, 02:01:46 pm »
Nonetheless I’m still curious if it’s possible to be able to know where a call to a method came from just like the stacktrace knows where the method call originated.

Stacktrace looks at the stack (duh! :-) After that it uses the debugging information in the executable (provided that it was appended and hasn't been stripped) to get line numbers, enclosing function names and so on.

That's not going to work for the sort of protection you need. You could gain a certain amount by always using an Assigned()...FreeAndNil() pair, but would have to put those in a critical section if there's a risk that you'll be using multiple threads. And if there's a risk that the same thread could be going reentrant then you'll need to wrap the critical section in an indivisible inc/dec pair. At this point we'll get Thaddy jumping in complaining that anybody who even considers discussing that sort of thing is clearly an inferior programmer, and I'll tell him to shut up every bit as brutally as I tell you to shut up on occasion :-)

I for one accept that this sort of thing can be a problem. My background is such that I'd seriously consider using some sort of token-based authentication, i.e. the constructor is given a random token by its caller, and the destructor raises an error if its caller cannot demonstrate that it still knows the token.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1198
Re: Name of calling procedure?
« Reply #8 on: November 04, 2024, 02:03:29 pm »
Fibonacci, Thanks for code,
Wow that’s strange I’ve never seen type casting used with create before .
Iunknown is the interface I presume, I don’t remember how interfaces work is it possible to do using inheritance as well?
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

Thaddy

  • Hero Member
  • *****
  • Posts: 16138
  • Censorship about opinions does not belong here.
Re: Name of calling procedure?
« Reply #9 on: November 04, 2024, 02:04:44 pm »
Also I find it strange how a nil Typed pointer can access class methods
This is normal, since class methods do not rely on an instance at all. They rely on the type declaration only.
Here nil is an example that nil is a valid pointer.
« Last Edit: November 04, 2024, 02:09:13 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

MarkMLl

  • Hero Member
  • *****
  • Posts: 7999
Re: Name of calling procedure?
« Reply #10 on: November 04, 2024, 02:11:01 pm »
Also I find it strange how a nil Typed pointer can access class methods
This is normal, since class methods do not rely on an instance at all. They rely on the type declaration only.
Here nil is an example that nil is a valid pointer.

I think PascalDragon reminded us all of that a couple of weeks ago when somebody else was asking about class variables. TBH it's not something which would really have occurred to me...

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

rvk

  • Hero Member
  • *****
  • Posts: 6572
Re: Name of calling procedure?
« Reply #11 on: November 04, 2024, 02:17:49 pm »
Thanks for the answers, maybe I should elaborate
Tableware is a class that is not an lcl componet it holds information about an sqlite table such as table name, where condition for sql statements,name of class where it was created and type of columns to be used.
You do know TComponent isn't part of Lazarus but part of FPC, don't you?

TComponent (native FPC class) has an Owner. So if you inherit from TComponent you can just use the Owner methods (and automatic freeing) of that class.

Fibonacci

  • Hero Member
  • *****
  • Posts: 594
  • Internal Error Hunter
Re: Name of calling procedure?
« Reply #12 on: November 04, 2024, 02:19:04 pm »
is it possible to do using inheritance as well?

If your first class is inherited from TInterfacedObject

Code: Pascal  [Select][+][-]
  1. program app;
  2.  
  3. type
  4.   tfirstclass = class(TInterfacedObject)
  5.     constructor Create;
  6.     destructor Destroy; override;  
  7.     procedure hi;
  8.   end;
  9.  
  10. constructor tfirstclass.Create;
  11. begin
  12.   writeln('tfirstclass.Create');
  13. end;
  14.  
  15. destructor tfirstclass.Destroy;
  16. begin
  17.   writeln('tfirstclass.Destroy');
  18. end;
  19.  
  20. procedure tfirstclass.hi;
  21. begin
  22.   writeln('hi from parent class');
  23. end;
  24.  
  25. type
  26.   tsomeclass = class(tfirstclass, IUnknown)
  27.     constructor Create;
  28.     destructor Destroy; override;
  29.     procedure other_hi;
  30.   end;
  31.  
  32. constructor tsomeclass.Create;
  33. begin
  34.   writeln('tsomeclass.Create');
  35. end;
  36.  
  37. destructor tsomeclass.Destroy;
  38. begin
  39.   writeln('tsomeclass.Destroy');
  40. end;
  41.  
  42. procedure tsomeclass.other_hi;
  43. begin
  44.   writeln('hi');
  45. end;
  46.  
  47. procedure main;
  48. var
  49.   t: tsomeclass;
  50. begin
  51.   t := tsomeclass.Create as IUnknown as tsomeclass;
  52.   t.hi;
  53.   t.other_hi;
  54. end;
  55.  
  56. begin
  57.   main;
  58.   writeln('end of program');
  59.   readln;
  60. end.

rvk

  • Hero Member
  • *****
  • Posts: 6572
Re: Name of calling procedure?
« Reply #13 on: November 04, 2024, 02:20:36 pm »
Why invent the wheel while TComponent already does this via AOwner??

Code: Pascal  [Select][+][-]
  1.   TComponent = class(TPersistent,IUnknown,IInterfaceComponentReference)
  2.   private
  3.     FOwner: TComponent;
  4.     FName: TComponentName;
  5. //...
  6.     constructor Create(AOwner: TComponent); virtual;

Warfley

  • Hero Member
  • *****
  • Posts: 1734
Re: Name of calling procedure?
« Reply #14 on: November 04, 2024, 02:28:04 pm »
EDIT: The Check "if Self <> Nil" confuses me, though.
I'm guessing that this Procedure is not a class procedure, so there MUST be an instance of "Self", so Self can never be Nil
Not necessarily, self can be nil. It's actually desired behavior for one of the most common functions in all of pascal:
Code: Pascal  [Select][+][-]
  1.       procedure TObject.Free;
  2.  
  3.         begin
  4.            // the call via self avoids a warning
  5.            if self<>nil then
  6.              self.destroy;
  7.         end;
  8.  
It's specifically build in a way that you can set a variable to nil and still call free on it. It's a terrible idea, especially in combination with FreeAndNil, but it is fully intended to be used that way.

The confusing thing here is:
I have some code for freeing a class instance that can be shared amongst several classes. When this class is shared I only want the class
Code: Pascal  [Select][+][-]
  1. PROCEDURE TTABLE_WHERE.REMOVE( CONST OWNERNAME: SHORTSTRING) ;
  2.  BEGIN
  3.  IF (SELF <> NIL) AND (OWNER_NAME = OWNERNAME)
  4.     THEN SELF.Free;
  5.  END;
  6.  
Because if you look at the implementation of nil, this code boils down to:
Code: Pascal  [Select][+][-]
  1. if (self<>nil) and (owner_name=ownername) then
  2.   if free<>nil then
  3.     self.destroy;

So the first self<>nil check can be avoided because free does exactly that. If you don't want to have that nil check, you should be using destroy directly instead of free as a proxy

 

TinyPortal © 2005-2018