You are not logged in.
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
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
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
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