Jump to content

Converting Variant to Record and viceversa


Recommended Posts

Hi everyone!

 

I have read that variants and records are stored internally the same way (http://smartmobilestudio.com/2012/02/04/working-with-javascript-structures/).

 

I am using the variant type to decode some received JSON. Now I want to convert this variant to a record representation, in order to avoid typos when writing code (thanks to the compile-time checkings that records have).

 

Of course, the JSON and the record contains the same fields, so the asm direct conversion would work fine, but I don't know how to encapsulate this into a function, in order to avoid the use of asm ... end sections but in the actual function that does the conversion. Problem is that I am not able to pass a record of ANY kind to a function, so I thought of using the Variant, but now I am facing the problem of converting Variant to record.

 

There is a way to achieve this?

 

Attached is my sample code.

 

Best regards,

 

LoPiTaL

 

 

 

 
//This function is meant to avoid filling all the code with asm ... end sections 
function JSON2Variant(AResponse: string): Variant; 
begin 
  asm 
    @Result=JSON.parse(@AResponse); 
  end; 
end; 

procedure WhereIsUsedTheConversion; 
var 
  LResult: Variant; 
  LRecord: TMyRecord; 
begin 
    LResult:=JSON2Variant(AResponse); 
    //Is this possible???? 
    LRecord:=VariantToRecord(LResult); 
end; 

Link to post
Share on other sites
  • Administrators

Answer from Eric Grange:

 

You can't cast directly to a record, first because the fields names you have on the Pascal side and those you have in the compiled JS can be different (because of disambiguation, case sensitivity or obfuscation).

 

Also JS doesn't have records only classes, so the compiler actually turns records into classes with special methods that are invoked automatically to copy/clone, so that they behave like records.

 

To achieve what I think you're after, you could declare an external class, f.i.

 

 
   JCompassOptions = class external 'Object' 
      frequency : Float; 
      filter : Float; 
   end; 

 

this defines a JCompassOptions external class, with two fields "frequency" and "filter", that will be safe from all disambiguation and obfuscations by the compiler, and you can cast your variant directly to a JCompassOptions.

If in your code you then have a variable "v" of type JCompassOptions, then "v.hello" will trigger a syntax error, and "v.Filter" will be automatically compiled as "v.filter" (ie. case is enforced).

 

You can see http://delphitools.info/2012/10/03/re-rooting-object-pascal/ or n check the PhoneGapAPI or w3c.xxx for many exemples.

 

Link to post
Share on other sites

Hi Jørn, thanks for the answer.

 

I tried what you proposed, but I'm still getting the incompatible types error:

 

"Syntax Error: Incompatible types: Cannot assign "Variant" to "JMyObject" [line: 195, column: 15, file: ServerConnector]"

 

Now I have my code like this:

 

 
function JSON2Variant(AResponse: string): Variant; 
JMyObject=class external 'object' 
end; 

procedure WhereIUseIt; 
var 
  LObject: JMyObject; 
begin 
  LObject:=JSON2Variant(AString);  //Error appears here 
end; 

 

Can you explain a bit more or put some sample code?

Thanks in advance,

LoPiTaL

 

 

Link to post
Share on other sites
  • Administrators

Do you need the record as datatype?

 

You can access the variant members directly though the loose/late binding offered by the variant data type.

 

Create a new console project and add this to the PopulateConsole method:

 

 
procedure TApplication.PopulateConsole; 
var 
  mJSON: String; 
  mData: Variant; 
begin 
  { Assigning some JSON to a string (by using the heredoc multi line syntax: http://delphitools.info/2012/02/24/heredoc-multi-line-strings/ } 
  mJSON := " 
              { 
                  ""firstName"": ""John"", 
                  ""lastName"": ""Smith"", 
                  ""age"": 25 
              } 
           "; 


  { Just checking the string content } 
  ShowMessage(mJSON); 

  { Parsin the JSON into a variant } 
  asm 
    @mData = JSON.parse(@mJSON); 
  end; 

  { Accessing the elements of the JSON } 
  Console.WriteLn('mData.firstName = '   + mData.firstName); 
  Console.WriteLn('mData.lastName = '    + mData.lastName); 
  Console.WriteLn('mData.age = '         + mData.age); 
end; 

 

Will give you this output:

 

ConsoleOut.png

Link to post
Share on other sites

Hi! Thank you both for your answers:

 

> Do you need the record as datatype?

 

No, I don't need the record. I just don't want to use Variants, because they are prone to typos. Using the variants remembers too much to Javascript, that can compile always but not execute, and (from my point of view) using a higher level language like Pascal is to avoid things like that.

 

> LObject:=JMyObject(JSON2Variant(AString));

 

Ok, now your solution works really fine!

 

Just a thing now: I have inherited from my object, so I can have a base class with some variables and childs with different variables. If I declare a variable of a child (even without using it), when I execute the program (even without entering the function where the variable is declared) appears a black window.

 

Can inheritance be used in extern objects?? Code is attached:

 

 
JObject=class external 'object' 
var 
Common: integer; 
end; 

JChild= class (JObject) 
Concretion: string; 
end; 

procedure WhereIDeclareIt; 
var 
LChild: JChild; 
begin 
//I don't use LChild here, but the program shows a black window. 
//If I use JObject instead of JChild everything works fine. 
end; 

 

Thanks for the answers,

Best regards,

LoPiTaL

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...