7

I have some global string variables.

I have to create the function that I could pass & store them in some structure. Later I need to enumerate them and check their values.

how can this be easily achieved?

(I think I would need some kind of reflection, or store array of pointers). Anyway, any help will be appreciated.

Thanks!

Johan
  • 74,508
  • 24
  • 191
  • 319
John
  • 1,834
  • 5
  • 32
  • 60
  • 1
    Delphi has `RTTI`, `Java` and `.net` have `Reflection`. When talking about Delphi you should call it RTTI, not Reflection. – Cosmin Prund Jul 18 '11 at 08:52
  • @Cosmin Why? RTTI is a form of reflection. RTTI is only meaningful if you happen to know that acronym. OP is asking for reflection and doesn't care whether it's effected with RTTI or with some other mechanism. – David Heffernan Jul 18 '11 at 08:57
  • 7
    @David, because one might be a Delphinian who knows what RTTI is but has no idea what Reflection is. Because the documentation calls it RTTI. Because google's only helpful results for "Delphi reflection" are those that hint you should call it "RTTI". – Cosmin Prund Jul 18 '11 at 09:02
  • 1
    @Cosmin If people know what RTTI is but don't know what reflection is, then those people need to broaden their horizons. Reflection is a generic term and RTTI is a specific implementation of reflection. – David Heffernan Jul 18 '11 at 10:45

3 Answers3

7

First of all you can't use Delphi's RTTI for that purpose, because Delphi 7's RTTI only covers published members of classes. Even if you were on Delphi XE, there's still no RTTI for global variables (because RTTI is tied to Types, not to "units").

The only workable solution is to create your own variable registry and register your globals using a name and a pointer to the var itself.

Example:

unit Test;

interface

var SomeGlobal: Integer;
    SomeOtherGlobal: string;

implementation
begin
  RegisterGlobal('SomeGlobal', SomeGlobal);
  RegisterGlobal('SomeOtherGlobal', SomeOtherGlobal);
end.

were the RegisterXXX types would need to be defined somewhere, probably in there own unit, like this:

unit GlobalsRegistrar;

interface

procedure RegisterGlobal(const VarName: string; var V: Integer); overload;
procedure RegisterGlobal(const VarName: string; var V: String); overload;
// other RegisterXXX routines

procedure SetGlobal(const VarName: string; const Value: Integer); overload;
procedure SetGlobal(const VarName:string; const Value:string); overload;
// other SetGlobal variants

function GetGlobalInteger(const VarName: string): Integer;    
function GetGlobalString(const VarName:string): string;
// other GetGlobal variants

implementation

// ....

end.
Cosmin Prund
  • 25,498
  • 2
  • 60
  • 104
  • 1
    `var` parameters rather than pointers would make the interface more pleasant for the caller – David Heffernan Jul 18 '11 at 08:55
  • `var` parameters would allow for overloads as well. But that's only for `RegisterXXX` and `SetXXX`, the Getters would need to be plain functions. – Cosmin Prund Jul 18 '11 at 08:56
  • What a pity, it cannot be done easily. Yes registering the pointers of favriable is some kind of option but in case I have dozens of such variables I will have to do my task the other way. Thanks! – John Jul 18 '11 at 09:00
  • 1
    @John, consider not using global variables at all but published properties of a global class (that way you can use RTTI). Or don't use any variables at all, use name-value pairs as TOndrej suggests. – Cosmin Prund Jul 18 '11 at 09:05
  • I would probable do it, but in case i have already the file with the global vars, I wouldn't like to mess thigs up and rebuild the entire current 'solution' – John Jul 18 '11 at 09:18
  • @John, using global variables is not good design any way, consider this an opportunity to refactor your code. But make sure the class that's holding the published properties (or the named-value pairs) is passed as a parameter to your routines. – Cosmin Prund Jul 18 '11 at 09:30
  • I would personally prefer to encapsulate all the needed variables in a class with published properties. – TLama Feb 14 '13 at 19:08
7

You could also have a global TStringList variable holding a list of name-value pairs.

Ondrej Kelle
  • 36,941
  • 2
  • 65
  • 128
  • 1
    This was the *only* easy solution for Delphi 7, but it never was a good solution: Storing things as string just to use TString's key=value lookups is inefficient. There's also the option to use TStringList for indexing only and store actual values in an separate array. – Cosmin Prund Jul 18 '11 at 10:50
  • @Cosmin so you're basically saying that current TStringList implementation is inefficient. I agree, but still it's an easy solution and should be acceptable for a small list. If performance becomes an issue you can use `THashedStringList` from `IniFiles` or a similar descendant. – Ondrej Kelle Jul 18 '11 at 11:00
  • There's also the issue of storing everything as string, since `TStringList.Value[]` is a string. That's why I'd recommend a mixed implementation, where `TStringList` (or `TStringHash`) is only used for indexing, with a plain array of base type used for actual value storage. – Cosmin Prund Jul 18 '11 at 11:10
  • You could keep the variable contents in TStringList.Objects[], storing a pointer, an object containing the value or a (variant) record. – boileau Jul 18 '11 at 14:53
3

On Delphi 7, I would follow Cosmin's idea for the interface, and for the implementation, I would use a dictionary type based on Julian Bucknall's excellent data structures code for Delphi, ezDSL.

Later versions of delphi like XE not only have more advanced RTTI they also include a pretty great dictionary type, using generics, so the dictionary can contain any type you like. The esDSL dictionary is pretty easy to use but since it's pointer based, it isnt as type safe as the delphi generics dictionary.

Since what you need to do is look up string "variable names" in very fast time (O(1) we like to call it), what you need is a string-to-variable dictionary. You could have Strings for the keys, and Variants as the values in the dictionary, and just get rid of the original global variables, or you could attempt some rather complex pointers-to-globals logic, but I really think you'd be better off with a simple dictionary of <string,variant> key,value tuples.

Warren P
  • 65,725
  • 40
  • 181
  • 316