Class Variables.
I got asked today about having a global value that you can share between objects of specific types but was closed away to other objects, so they didn’t want to have a global variable.
Two nice language feature in Delphi allows you to do exactly what they were trying to do, and they are Class Variables and strict private declarations. In this quick blog post we will look at this in action.
A Class Variable simply means you have a value that is managed by the class type rather than an instance of a class. This means that each time you reference it from ANY object of that type, you get the same value back. Strict Private means that only this class can read and write the value, even if there are other classes in the same unit of code.
To demonstrate this in action I’m going to write some bonkers code, totally impractical, but feel free to copy it
It does however prove the point and give an understanding of it in action. I will then suggest some more practical examples of this in action.
So lets start with our demo class TFoo You can see this class has an ID (string) and this is read and set to the private value FID. We also have a strict private member FrIDCounter (Read Counter) that is increased everytime the property ID is read. This value is declared as a class var meaning it belongs to the class type and not the instance. (highlighted in blue below)
unit unitFoo;
interface uses System.SysUtils; type TFoo = class strict private class var FrIDCounter : Integer; private FID: string; function GetID: string; procedure SetID(const Value: string); public constructor Create; procedure SetIDCounter(NewValue : Integer); property ID : string read GetID write SetID; end; implementation constructor TFoo.Create(); begin inherited Create; ID := ''; end; function TFoo.GetID: string; begin Result := FID +':'+ IntToStr(FrIDCounter); Inc(FrIDCounter); end; procedure TFoo.SetID(const Value: string); begin FID := Value; end; procedure TFoo.SetIDCounter(NewValue: Integer); begin TFoo.FrIDCounter := NewValue; end; end.
OK, I did say it would be bonkers code! But lets see how this works in action. To try this code out, I’m going to create two instances of the object TFoo, to show that the updates really do happen across both objects. To show the output I’ve put a ListBox onto a form, added a button and run the application, The code in the image below will show what happens.
From the above we can see that Foo1 is created with an ID of MyFoo1ID and this is kept by the object as the ID, however the ID is appended with the counter for each read. When Foo 2 is created, its counter is the next value along form Foo1 and then when Foo1 is called again, it takes the next number again!
The code, then sets the ID to 1000 and the next two reads carry on from the same value.
OK. Totally bonkers code, but a very useful language feature. Imagine that you need to keep a lot of objects aware of a remote connection protocol, or you need to update the currency conversion value across your system. This gives one way to do it simply.
However following on from our theme, imagine you want to create a number of objects with a unique ID for each object the following code would do just that thanks to the Class Variable.
type TFoo = class strict private class var FrIDCounter : Integer; private FID: string; public constructor Create; property ID : string read FID; end;
implementation
constructor TFoo.Create(); begin inherited Create; FID := FrIDCounter; Inc(FrIDCounter); end;Posted by Stephen Ball on October 18th, 2012 under Delphi |




RSS Feed

October 18th, 2012 at 4:53 pm
Nice Post!
October 19th, 2012 at 4:09 am
Thanks for the article. To be honest I haven’t used Class Variables much, but I would state that guarded access is required to class variables in multi-threaded programs… TMonitor.Enter(classvar);
try;
DoSomething(classvar);
finally;
TMonitor.Exit(classvar);
end;
October 19th, 2012 at 8:21 am
I had never considered class variables in this way before - this is actually really useful and I can see that I could simplify some of my existing systems using this approach. The "remote connection protocol" variable particularly stood out to me.
October 19th, 2012 at 8:32 am
Great comments, thanks guys. Absolutely Darian, you would want to make this thread safe if using it in a multi-threaded application. There is more on TMonitor on docwiki.embarcadero.com
October 19th, 2012 at 3:38 pm
Bonkers code?