Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2007-11

RTTI's GetPropValue returns corrupt Boolean value

8 messages · 3 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Graeme Geldenhuys

Hi,

I've included a program that shows the problem. I'm using FPC 2.2.0 under Linux on a Intel P4.
I've got a function PropertyMatch() which returns true or false if a given property matches a specified value. All very simple. But for some strange reason TypInfo.GetPropValue returns a boolean which seems to test ok using VarIsType(), but if I cast it as a boolean variant using VarIsType() just to be sure, the application throws the error show below.

Any ideas how to resolve this issue? Is it a FPC bug? This same code works perfectly with Delphi 7-2007.

./project1
Test 1 passed. Integer property matched.
Test 2 passed. String property matched.
An unhandled exception occurred at $0807F54D :
EVariantTypeCastError : Could not convert variant of type (Int64) into type (Boolean)
$0807F54D
$0807C5EB
$0807D139
$08048467 main, line 85 of project1.lpr

----[ Backtrace ]------------------------------
(gdb) break fpc_raiseexception
Breakpoint 1 at 0x8054886
(gdb) run
Starting program: /home/graemeg/programming/tests/rtti_bug/project1 Test 1 passed. Integer property matched.
Test 2 passed. String property matched.

Breakpoint 1, 0x08054886 in fpc_raiseexception ()
(gdb) bt
#0 0x08054886 in fpc_raiseexception ()
#1 0x0807f539 in VARIANTS_VARCASTERROR$WORD$WORD () #2 0x0807c5cb in VARIANTS_SYSVARCAST$VARIANT$VARIANT$LONGINT () #3 0x0807d119 in VARIANTS_VARASTYPE$VARIANT$WORD$$VARIANT () #4 0xbfa82934 in ?? ()
#5 0xbfa828d4 in ?? ()
#6 0x08048189 in PROPERTYMATCH (AOBJECT=0xb7f4a100, PROPNAME=0x80a1ab4, PROPVALUE=void)
at project1.lpr:41
#7 0x08048467 in main () at project1.lpr:82
------------- end ----------------

-----[  the program code  ]------------------------------
program project1;
{$mode objfpc}{$H+}
uses
  Classes, typinfo, variants;
type
  {$M+}
  TMyObject = class(TObject)
  private
    FBoolProp: Boolean;
    FIntProp: Integer;
    FStrProp: string;
  published
    property IntProp: Integer read FIntProp write FIntProp;
    property BoolProp: Boolean read FBoolProp write FBoolProp;
    property StrProp: string read FStrProp write FStrProp;
  end;
  {$M-}
  // This does a test to see if the property PropName's value
  // matches PropValue.
  function PropertyMatch(AObject: TObject; PropName: string;
        PropValue: variant): boolean;
  var
    lSearch, lItem: variant;
    lVarType: TVarType;
    lPropInfo: PPropInfo;
  begin
    lSearch := PropValue;
    lItem := TypInfo.GetPropValue(AObject, PropName);
    lVarType := VarType(lItem);
    // Just to be sure that I'm comparing the SAME kind of values
    if VarIsType(PropValue, varBoolean) then
    begin
      lItem := VarAsType(lItem, varBoolean);  // <<=== EVariantTypeCastError
//      lItem := VarAsType(True, varBoolean);  // this passes if we
force boolean
    end
    else
    begin
      lSearch := VarAsType(lSearch, lVarType);
      lItem := VarAsType(lItem, lVarType);
    end;
    result := (lSearch = lItem);
  end;
var
  obj: TMyObject;
  lBool: Boolean;
begin
  obj := TMyObject.Create;
  try
    obj.IntProp   := 123;
    obj.BoolProp  := True;
    obj.StrProp   := 'abcd';
    // Testing a Integer property
    if PropertyMatch(obj, 'IntProp', 123) then
      writeln('Test 1 passed. Integer property matched.')
    else
      writeln('Test 1 failed');
    // Testing a String property
    if PropertyMatch(obj, 'StrProp', 'abcd') then
      writeln('Test 2 passed. String property matched.')
    else
      writeln('Test 2 failed');
    // Testing a Boolean property
    // We can also try it with a typed variable
//    lBool := True;
//    if PropertyMatch(obj, 'BoolProp', lBool) then
    if PropertyMatch(obj, 'BoolProp', True) then
      writeln('Test 3 passed. Boolean property matched.')
    else
      writeln('Test 3 failed');
  finally
    obj.Free;
  end;
end.

------------- end ----------------

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

Michael Van Canneyt
to Graeme Geldenhuys
Graeme Geldenhuys wrote 13 lines
Hi, I've included a program that shows the problem. I'm using FPC 2.2.0 under Linux on a Intel P4. I've got a function PropertyMatch() which returns true or false if a given property matches a specified value. All very simple. But for some strange reason TypInfo.GetPropValue returns a boolean which seems to test ok using VarIsType(), but if I cast it as a boolean variant using VarIsType() just to be sure, the application throws the error show below. Any ideas how to resolve this issue? Is it a FPC bug? This same code works perfectly with Delphi 7-2007.

It depends on the choices made when converting variants to native types or vice versa (even more difficult when it occurs in an expression). It's hard to say whether this is an actual error or an incompatibility. Looking at the code and the error, I'd say that somewhere along the line fpc converted a variant to int64 instead of to an integer as delphi seems to do.

It's just one of these reasons why it is IMHO better not to use Variants: things happen behind the scenes that are not very clear (and that are not documented )

Michael.

Reply by email

Graeme Geldenhuys
to Michael Van Canneyt
Michael Van Canneyt wrote
It's hard to say whether this is an actual error or an incompatibility.

Well this 'error' has been around in tiOPF since I ported it to FPC (about 3 years) and now it's really bugging me. :)

Looking at the code and the error, I'd say that somewhere along the line fpc converted a variant to int64 instead of to an integer as delphi seems to do.

No idea, I may not look at the Delphi code remember! ;-)

It's just one of these reasons why it is IMHO better not to use Variants: things happen behind the scenes that are not very clear (and that are not documented )

Fair enough. I'm not a fan of Variants either, but how else would I write the PropertyMatch() function then? Yes I could do some extra tests and use GetStrProp, GetIntProp, GetFloatProp etc. but there isn't a GetBooleanProp(). I would imagine I need to use the GetOrdProp for Boolean, but looking at the function definition for GetOrdProp, it outputs a Int64 which is probably what gave me the error in the first place (casting Bool to Int64 or vice-versa).

Note that the PropertyMatch() function I have in the example is a scaled down version (just to highlight the issue) of the full one in tiOPF. I need to handle all property types.

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

Michael Van Canneyt
to Graeme Geldenhuys
Graeme Geldenhuys wrote 11 lines
On 20/11/2007, Michael Van Canneyt wrote: > It's hard to say whether this is an actual error or an incompatibility. Well this 'error' has been around in tiOPF since I ported it to FPC (about 3 years) and now it's really bugging me. :) > Looking at the code and the error, I'd say that somewhere along the line > fpc converted a variant to int64 instead of to an integer as delphi seems > to do. No idea, I may not look at the Delphi code remember! ;-)

Point scored :-)

Show quoted text 9 lines
> It's just one of these reasons why it is IMHO better not to use Variants: > things happen behind the scenes that are not very clear (and that are > not documented ) Fair enough. I'm not a fan of Variants either, but how else would I write the PropertyMatch() function then? Yes I could do some extra tests and use GetStrProp, GetIntProp, GetFloatProp etc.

This is IMHO the only correct way.

Show quoted text 5 lines
but there isn't a GetBooleanProp(). I would imagine I need to use the GetOrdProp for Boolean, but looking at the function definition for GetOrdProp, it outputs a Int64 which is probably what gave me the error in the first place (casting Bool to Int64 or vice-versa).

It probably retuns an int(64), and when it's converted to variant
- I don't know. I'd have to look at the code.

Note that the PropertyMatch() function I have in the example is a scaled down version (just to highlight the issue) of the full one in tiOPF. I need to handle all property types.

This is exactly where the easy access to RTTI would come in handy, and which is why I would like to have it. If you want we can always discuss in private the design of such an easy-acces method.

Michael.

Reply by email

Graeme Geldenhuys
to Michael Van Canneyt
Michael Van Canneyt wrote 5 lines
> Fair enough. I'm not a fan of Variants either, but how else would I > write the PropertyMatch() function then? Yes I could do some extra > tests and use GetStrProp, GetIntProp, GetFloatProp etc. This is IMHO the only correct way.

I've extended the PropertyMatch() function to test for tkBool types (no variants) and do a writeln when it finds it. That parts seems to work fine.

It probably retuns an int(64), and when it's converted to variant - I don't know. I'd have to look at the code.

That would be great. I'm on my way home now, but will continue looking at the code tomorrow. More eyeballs on the code is always better.

This is exactly where the easy access to RTTI would come in handy, and which is why I would like to have it. If you want we can always discuss in private the design of such an easy-acces method.

I've created a tiRTTI.pas unit in tiOPF, but it's simply wrappers for calling many other functions. It makes it a bit easier to use RTTI though. But yes I wouldn't mind discussion an 'easy-access' method for RTTI.

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

Michael Van Canneyt
to Graeme Geldenhuys: Here is the debug code I added to PropertyMatch() which successfully compare the results,…
Graeme Geldenhuys wrote 10 lines
On 20/11/2007, Graeme Geldenhuys wrote: > > I've extended the PropertyMatch() function to test for tkBool types > (no variants) and do a writeln when it finds it. That parts seems to > work fine. Here is the debug code I added to PropertyMatch() which successfully compare the results, but I have to explicitly cast GetOrdProp to a Boolean. Is that normal???

Yes.

Michael.

Reply by email

Graeme Geldenhuys
to Graeme Geldenhuys: I've extended the PropertyMatch() function to test for tkBool types (no variants) and do…
Graeme Geldenhuys wrote
I've extended the PropertyMatch() function to test for tkBool types (no variants) and do a writeln when it finds it. That parts seems to work fine.

Here is the debug code I added to PropertyMatch() which successfully compare the results, but I have to explicitly cast GetOrdProp to a Boolean. Is that normal???

    PropInfo := GetPropInfo(AObject.ClassType, PropName);
    if tiGetTypeInfo(PropInfo)^.Kind = tkBool then
    begin
      writeln('Found rtti bool type');
      lbool := Boolean(GetOrdProp(AObject, PropName));
      if lSearch = lbool then
        writeln('Comparison was a success');
    end;

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

Joao Morais
to Graeme Geldenhuys
Graeme Geldenhuys wrote 17 lines
On 20/11/2007, Graeme Geldenhuys wrote: > I've extended the PropertyMatch() function to test for tkBool types > (no variants) and do a writeln when it finds it. That parts seems to > work fine. Here is the debug code I added to PropertyMatch() which successfully compare the results, but I have to explicitly cast GetOrdProp to a Boolean. Is that normal??? PropInfo := GetPropInfo(AObject.ClassType, PropName); if tiGetTypeInfo(PropInfo)^.Kind = tkBool then begin writeln('Found rtti bool type'); lbool := Boolean(GetOrdProp(AObject, PropName)); if lSearch = lbool then writeln('Comparison was a success'); end;

Sounds familiar. Here I have:

   if UsePublishedGetter then
     Result := Boolean(GetOrdProp(Owner, Metadata.Name))
   else
     Result := Value;
Joao Morais

Reply by email