Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Accessing an entity of a record, using a string. 1

Status
Not open for further replies.

barrin

Technical User
Feb 6, 2006
25
CA
Let's say I have a record:

TRecord = record
variable1: Integer;
variable2: Integer;
end;

and a string:

aString: String = 'variable1';


Is it possible to access variable1 of TRecord using the string with its name, aString?

for example, something along these lines...

var
aRecord: TRecord;
begin
aRecord.aString := 10;
end;


Thanks, Pat.
 
hi!

im not really understanding why do you wanna do that, but i guess that your problem can be solved by using the
strtoint() function...

you ca do aRecord.aString := 10;
and then int=strtoint(arecord.astring);
 
No, it is not possible. PASCAL is a compiled language; variable names need to be defined at compile time.

The quick way is making an if... elseif... nest:

Code:
if UpperCase(aString) = 'VARIABLE1'
  then aRecord.Variable1 := 10
else if UpperCase(aString) = 'VARIABLE2'
  then aRecord.Variable2 := 10
else report_the_error;

buho (A).


 
Yes, I was looking for an alternative to the nested if statements. And no, in my case it won't be the quick way ;)

Thanks for the reply.
 
The only way you can do this sort of thing is with RTTI - which allows you to access published properties of objects by name.

Code:
type
  TMyObject = class
  private
    FStr : String;
  published
    property MyStr : String read FStr write FStr;
  end;

implementation

uses
  TypInfo;

var
  o : TMyObject;
  Prop : String;
begin
  ...
  Prop := 'MyStr';
  SetStrProp(o, Prop, 'new string value');
  ...
end;
 
Very interesting post Griffyn, I think you've solved my problem.

As a simple example, would you tell me if Int would equal 12 after this code is run?

Code:
type
  TMyObject = class
  private
    Int: Integer;
    procedure SetInt(Index: Integer; Value: Integer);
  published
    property One: Integer Index 1 read Int write SetInt;
    property Two: Integer Index 2 read Int write SetInt;
  end;

implementation

procedure SetInt(Index: Integer; Value: Integer);
begin
  Int := Value * Index;
end;

var
  MyObject: TMyObject;
  Property: String;
begin
  Property := 'Two';
  SetOrdProp(MyObject, Property, 6)
end;
 
hi barrin,

Presuming you created MyObject in the first place, then yes, Int=12 after that code.
 
Sorry for being negative, but using RTTI out of real and absolute need is a bad practice.

How many fields your record have? Are it so many as to pay the extra computational effort RTTI and published properties demand?

Sorry again for the criticism, Griffyn.

buho (A).
 
Hi buho,

I know that using RTTI is slow, but there are occasions when it is necessary.

This game I'm writing at the moment contains a database with scripts, and the scripts (plain strings) refer to procedures and functions within my Delphi code. The only way to make the link from parsing the script to the actual method is with RTTI. Unless you know of another way...?
 
Well... in your case I would start every script with an index and access the handler via an array.

Something like this:

Code:
[b]Script structure: [index_nr]script code[/b]

Lets say we have a function which receives the script structure and returns the index and the script code:

function CutIndex(var Script : AnsiString; var Ix : integer) : boolean;

// Entry: Script = script structure
// Exit : Script := script code (clean, without [index_nr])
//        Ix     := index_nr numerical value
//        True if index_nr ok, false otherwise (NAN, out of range, bad structure, etc).

At start we initialize an array with all the script handlers:

type
  TScriptHandler = procedure(Script : AnsiString) of object;
  THandlerTable  = array[n..m] of TScriptHandler;
var
  HandlerTable : THandlerTable;
begin
  HandlerTable[n] := method_n
  ...
  HandlerTable[m] := method_m
end;

When the program receives the script it can call the handler by way of:

var
  Script : AnsiString;
  Ix     : integer;
begin
  ...
  // Script contains a script structure
  if CutIndex(Script, Ix)
    then HandlerTable[Ix](Script)
    else handle_index_error.
   ...
end;

You need to work some more when the program starts, but the accessing mechanics is way faster than RTTI.

buho (A).



 
I can see that would work, the downside being that every function and event specified in the scripts would need to have an index number assigned.

However, it doesn't handle accessing properties, which can also be specified in the script.

For reference, so that you understand the particulars of my project, my scripts have fields like this:
Code:
[b]Event            xModifier[/b]
SetItemField     HP,GetItemField(HP)+1
...              ...
There's a procedure method (SetItemField) reference, a function method (GetItemField) reference, and a property reference (HP). This particular script line increments that value of the HP property.

For the methods, I use the MethodAddress function of TObject to map the address of the desired function or procedure to a variable of type TMethod, and then call that with parameters. And I use the the RTTI routines in TypInfo to reference the properties within those methods.

I have hundreds of properties and methods over different object classes that are handled in this way.

Speed is an issue, and something I'm interested in fixing. Do you have any details on how much slower using RTTI is?
 
Sorry, i missunderstood you. I thought you was talking about an event handler but it turned to be a full fledged script engine.

I have not idea about the "absolute slowiness" of RTTI and anyway this is not the point. The point is how much slow (or fast) is your RTTI-based implementation compared with another implementation.

A well crafted grammar and a well crafted parser (designed for interpretation) can make a difference speed wise, but the real magic here is moving from grammar source interpretation to pre-generated byte-code execution (like Java). Quite a challenge.

buho (A).

 
I have a task similar to yours, Griffyn.

The string value I read from an INI file has to determine which property the program must reference. Since there are many different properties, and all the values for this key in the INI file correspond exactly to one of the properies, this method reduces my code from 30+ lines to 2.

I'm curious to see if using RTTI greatly reduces performance, because I could implement it in quite a few other areas.
 
Using the MethodAddress function of TObject takes time the first time you use it for a method, but if you retain it's value in a variable (or some sort of array) then it will be as fast to use it as calling the method directly.

I've only used the first set of RTTI routines in TypInfo, but there are a second set of overloaded routines that work with a record structure. The first set do some work to assemble the record and then call the second set, so it may be possible to store these records in an array of some type to reduce access times.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top