#1 2016-12-21 20:37:18

jbroussia
Member
From: France
Registered: 2011-04-09
Posts: 74

TDocVariant, problem (bug ?) assigning property from another object

Hi ab,

I'm encountering an annoying problem when trying to assign some properties from one object to another object. A few lines of code make it easier to describe it:

var
	a, o1, o2: Variant;
	s: string;
begin
	// THIS WORKS-------------------
	o1 := _Obj([]);
	o1.Val1 := 'blabla';
	o1.Val2 := 'bleble';
	
	o2 := _Obj([]);
	o2.Val1 := 'blibli';
	o2.Val2 := 'bloblo';

	o1.Val1 := o2.Val1;	// < --- OK
	o1.Val2 := o2.Val2;	// < --- OK

	Caption := o1;	// '{"Val1":"blibli","Val2":"bloblo"}'
	// -----------------------------


	// THIS WORKS-------------------
	s := '[{"Val1":"blabla","Val2":"bleble"},{"Val1":"blibli","Val2":"bloblo"}]';
	a := _Json(s);

	o1 := a._(0);
		
	o2 := _Obj([]);
	o2.Val1 := 'blublu';
	o2.Val2 := 'blybly';

	s := o2.Val1;
	o1.Val1 := s;	// < --- OK
	s := o2.Val2;
	o1.Val2 := s;	// < --- OK

	Caption := a;	// '[{"Val1":"blublu","Val2":"blybly"},{"Val1":"blibli","Val2":"bloblo"}]'
	// -----------------------------


	// THIS DOES NOT WORK-----------
	s := '[{"Val1":"blabla","Val2":"bleble"},{"Val1":"blibli","Val2":"bloblo"}]';
	a := _Json(s);

	o1 := a._(0);
		
	o2 := _Obj([]);
	o2.Val1 := 'blublu';
	o2.Val2 := 'blybly';

	o1.Val1 := o2.Val1;	// < --- NOT OK: raised exception class EVariantBadVarTypeError with message 'Invalid variant type'
	o1.Val2 := o2.Val2;	// < --- NOT OK

	Caption := a;	// Expecting '[{"Val1":"blublu","Val2":"blybly"},{"Val1":"blibli","Val2":"bloblo"}]'
	// -----------------------------

As you see, the first two examples work as expected but the third, which is a mix of the two others, raises an exception in SynCommons (function TSynInvokeableVariantType.SetProperty).
Is it normal behavior (meaning that my code is bad), or is it a bug ?

Thanks !

Offline

#2 2016-12-22 07:56:22

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,240
Website

Re: TDocVariant, problem (bug ?) assigning property from another object

I agree this is confusing, at most...

In fact, v._(0) returns a reference to the item [0] in v, for performance reasons.
So you are assigning some values to a not stand-alone instance.
Delphi RTL about late-binding does not like that...

What you should do is to store a true new value in o1:

  o1 := _Copy(a._(0));

or

  o1 := a._(0);
  _Unique(o1);

and then it works.

I've updated the documentation, and added the corresponding regression test.
See http://synopse.info/fossil/info/bac1983bed

Offline

#3 2016-12-22 10:56:29

jbroussia
Member
From: France
Registered: 2011-04-09
Posts: 74

Re: TDocVariant, problem (bug ?) assigning property from another object

Creating a copy of the object is not a solution because in the end I need to modify the properties of the object in the array.
And I can't put back the modified object in the array using:

a._(0) := o1;	// NOPE

And I still don't understand why this works (example 2):

s := o2.Val1;
o1.Val1 := s;

And this does as well:

o1.Val1 := string(o2.Val1);

But this does not (example 3):

o1.Val1 := o2.Val1;

Offline

#4 2016-12-22 12:41:46

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,240
Website

Re: TDocVariant, problem (bug ?) assigning property from another object

In such cases, go and work directly with the TDocVariantData, using e.g. _Safe(a).GetAsDocVariantByIndex(0).
Don't abuse on late-binding if you know you work with objects or documents.

It also will be slightly faster, and more compatible with FPC, which has some incompatibilities with Delphi when working with late-binding.

Offline

Board footer

Powered by FluxBB