[ACCEPTED]-How to know what type is a var?-typeinfo

Accepted answer
Score: 32


First, there's no such thing as a "non-instantiated 74 variable." You instantiate it by the 73 mere act of typing its name and type into 72 your source file.

Second, you already know 71 all there is to know about a variable by 70 looking at it in your source code. The variable 69 ceases to exist once your program is compiled. After that, it's 68 all just bits.

A pointer only has a type 67 at compile time. At run time, everything 66 that can be done to that address has already 65 been determined. The compiler checks for 64 that, as you already noted. Checking the 63 type of a variable at run time is only useful 62 in languages where a variable's type could 61 change, as in dynamic languages. The closest 60 Delphi comes to that is with its Variant type. The 59 type of the variable is always Variant, but you 58 can store many types of values in it. To 57 find out what it holds, you can use the 56 VarType function.

Any time you could want to use 55 TypeInfo to get the type information of the type 54 associated with a variable, you can also 53 directly name the type you're interested 52 in; if the variable is in scope, then you 51 can go find its declaration and use the 50 declared type in your call to TypeInfo.

If you want 49 to pass an arbitrary address to a function 48 and have that function discover the type 47 information for itself, you're out of luck. You 46 will instead need to pass the PTypeInfo value as 45 an additional parameter. That's what all 44 the built-in Delphi functions do. For example, when 43 you call New on a pointer variable, the compiler 42 inserts an additional parameter that holds 41 the PTypeInfo value for the type you're allocating. When 40 you call SetLength on a dynamic array, the compiler 39 inserts a PTypeInfo value for the array type.

The answer that you gave suggests 38 that you're looking for something other 37 than what you asked for. Given your question, I 36 thought you were looking for a hypothetical 35 function that could satisfy this code:

  S: string;
  Instance: IObjectType;
  Obj: TDBGrid;
  Info: PTypeInfo;
  Info:= GetVariableTypeInfo(@S);
  Assert(Info = TypeInfo(string));

  Info:= GetVariableTypeInfo(@Instance);
  Assert(Info = TypeInfo(IObjectType));

  Info:= GetVariableTypeInfo(@Obj);
  Assert(Info = TypeInfo(TDBGrid));

Let's 34 use the IsClass and IsObject functions from the JCL to build that function:

function GetVariableTypeInfo(pvar: Pointer): PTypeInfo;
  if not Assigned(pvar) then
    Result := nil
  else if IsClass(PPointer(pvar)^) then
    Result := PClass(pvar).ClassInfo
  else if IsObject(PPointer(pvar)^) then
    Result := PObject(pvar).ClassInfo
    raise EUnknownResult.Create;

It obviously 33 won't work for S or Instance above, but let's see 32 what happens with Obj:

Info := GetVariableTypeInfo(@Obj);

That should give an access 31 violation. Obj has no value, so IsClass and IsObject both 30 will be reading an unspecified memory address, probably 29 not one that belongs to your process. You 28 asked for a routine that would use a variable's 27 address as its input, but the mere address 26 isn't enough.

Now let's take a closer look 25 at how IsClass and IsObject really behave. Those functions 24 take an arbitrary value and check whether 23 the value looks like it might be a value of the given 22 kind, either object (instance) or class. Use 21 it like this:

// This code will yield no assertion failures.
  p: Pointer;
  o: TObject;
  a: array of Integer;
  p := TDBGrid;

  p := TForm.Create(nil);

  // So far, so good. Works just as expected.
  // Now things get interesting:

  Pointer(a) := p;
  Pointer(a) := nil;
  // A dynamic array is an object? Hmm.

  o := nil;
    on e: TObject do
      Assert(e is EAccessViolation);
  // The variable is clearly a TObject, but since it
  // doesn't hold a reference to an object, IsObject
  // can't check whether its class field looks like
  // a valid class reference.

Notice that the functions tell 20 you nothing about the variables, only about the 19 values they hold. I wouldn't really consider those 18 functions, then, to answer the question 17 of how to get type information about a variable.

Furthermore, you 16 said that all you know about the variable 15 is its address. The functions you found 14 do not take the address of a variable. They 13 take the value of a variable. Here's a demonstration:

  c: TClass;
  c := TDBGrid;
  Assert(not IsClass(@c)); // Address of variable
  Assert(IsObject(@c)); // Address of variable is an object?

You 12 might object to how I'm abusing these functions 11 by passing what's obviously garbage into 10 them. But I think that's the only way it makes 9 sense to talk about this topic. If you know 8 you'll never have garbage values, then you 7 don't need the function you're asking for 6 anyway because you already know enough about 5 your program to use real types for your 4 variables.

Overall, you're asking the wrong 3 question. Instead of asking how you determine 2 the type of a variable or the type of a 1 value in memory, you should be asking how you got yourself into the position where you don't already know the types of your variables and your data.

Score: 4

With generics, it is now possible to get 5 the type info without specifying it. Certain 4 users indicated the following code doesn't 3 compile without errors. As of Delphi 10 2 Seattle, version 23.0.20618.2753, it compiles 1 without errors, as seen below in the screenshot.

program TypeInfos;
{$R *.res}

  System.SysUtils, System.TypInfo;

  TTypeInfo = class
    class procedure ShowTypeInfo<T>(const X: T);

{ TTypeInfo }

class procedure TTypeInfo.ShowTypeInfo<T>(const X: T);
  LTypeInfo: PTypeInfo;
  LTypeInfo := TypeInfo(T);

  L: Exception;
  B: Boolean;
                             // Console output
  TTypeInfo.ShowTypeInfo(L); // Exception
  TTypeInfo.ShowTypeInfo(B); // Boolean

enter image description here

Score: 2

Not that I know of. You can get RTTI (Run 10 Time Type Information) on published properties 9 of a class, but not for "normal" variables 8 like strings and integers and so forth. The 7 information is simply not there.

Besides, the 6 only way you could pass a var without passing 5 a type is to use either a generic TObject 4 parameter, a generic type (D2008, as in 3 ), or as an untyped parameter. I can't think 2 of another way of passing it that would 1 even compile.

More Related questions