How to get the equivalent of a static(class) field in Delphi?
Asked Answered
G

3

5

I have a certain operation in a class that is very expensive. (on the order of about 8 seconds to fully run) So, now I've decided it should probably run at the beginning of the program during an "initialization" screen. I can't find anywhere in Delphi indicating that there is such a thing as a static field however.

What I basically need to do is load a list of records and keep them alive throughout the life of the program. What is the best way to do this in Delphi?

I would do this in C# quite simply:

class Foo{
  static List<...> Bar;
}

However in Delphi, I'm not seeing anything for creating a static field. All I see is the class keyword for creating static methods

Gibrian answered 2/1, 2012 at 15:57 Comment(5)
In modern Delphi you can use class var to have the equivalent of static member fields, but in Delphi 7 you need to use a global variable.Old
class methods and static methods are similar, but slightly different. class methods receive the class they are called on as implicit parameter, similar to how instance methods receive the instance. static methods receive no such parameter. Old versions of Delphi only have class methods, but I think newer versions also have static methods for increased .net compatibility.Inae
@CodeInChaos I wasn't aware of that distinction. It's rather esoteric since the equivalent of Self parameter of a class method is pretty easy to come by in a static method. But the use of Self does avoid repeating yourself. P.S. You are correct that D7 does not have class var and I was about to comment to that effect in your original answer but your grace period edit cleared it up!Old
To simulate non virtual class methods with static one would need to introduce an additional parameter, since the self parameter points to the class the method is called on, which might be a child class. And virtual class methods have no straight forward mapping at all. I sometimes miss class methods since I migrated to C#, which doesn't have them.Inae
@code ah, I had not thought about calling class methods from derived classes or even instance methods. By the way don't forget to @ the recipient in commentsOld
I
5

You can just use a global variable. Add it in the implementation section of a unit to make it local to that unit.

My Turbo Delphi supports class var x:integer;, but I'm pretty sure Delphi 7 doesn't.

Inae answered 2/1, 2012 at 16:17 Comment(0)
N
4

I think this is a good time to use initialization and finalization in Delphi. This goes at the end of a unit, just before end. You can use it to create/free global instances like this, or just set default variables...

unit Unit1;

interface

uses
  Classes;

function MyList: TStringList;    

implementation

var
  GMyList: TStringList;

function MyList: TStringList;
begin
  Result:= GMyList;
end;

initialization
  GMyList:= TStringList.Create;
  MyList.Append('Value 1'); 
  MyList.Append('Value 2');
  MyList.Append('Value 3');

finalization
  GMyList.Free;

end.

This only calls for special scenarios like this one. MyList will be alive for the duration of your application.

Note how GMyList is declared underneath implementation and MyList is actually a global function to access GMyList. This is to avoid accidental assignments and such. From any other unit, you can access GMyList by using the MyList function, but won't be able to access GMyList directly (which is what you want to avoid bugs).

Nabonidus answered 2/1, 2012 at 16:35 Comment(5)
Suggestion: move MyList to implementation and expose it through a function to protect it from accidental write access. (Adding/changing items would still possible, but maliciuous / buggy code could not simply re-assign it)Marrow
F prefix is for members, G would be more appropriateOld
@DavidHeffernan Never heard of that before... Any good source to see examples of prefixes?Nabonidus
Delphi source code. Personally I've never seen G prefix for a global. My point is that it you have to have a prefix G would be the obvious candidate. It can't be F since that is for field. I sometimes prefix my implementation section globals with a _Old
And G in this case stands for Global, whereas F stands for Field, which is not what I have in this case. That is David's point. I wouldn't doubt if _ is a more standard practice maybe, but I don't like how prefixing with _ looks, so I'll stick with G :)Nabonidus
V
3

You'll need a newer Delphi version if you want the real thing.

However, pascal has always had similar scoping, but for that you should (with a bit of fantasy) see a unit as a static final class.

Functions and variables that are public are defined in the interface section, and private stuff is defined in the implementation section. All of those are more or less the equivalent of class variables and class methods.

If you name your unit loader.pas, and you define a function "init" in the interface section, you can even call it as if it's a class function: loader.init().

The initialization and finalization sections are the equivalent of a class constructor and a class destructor.

What i describe above makes sense from turbo plascal until delphi 2007 (i think class variables were introduced in d2009). All in all i'd advice to just get a newer delphi.

Valletta answered 2/1, 2012 at 16:34 Comment(1)
Turbo Delphi has class vars, and it's based on delphi 2006.Inae

© 2022 - 2024 — McMap. All rights reserved.