Variant

Top  Previous  Next

Variants

 

Variant stores any Smart Pascal base or complex type, JavaScript object or array.

You can use variant to store object values, since you do not have to predefine the structure by hand. In SmartMS these kind of structures can be achieved automatically using "inline assembler" by grace of targeting Javascript directly.

 

Variants holding a JavaScript object cannot be directly casted from/to TObject. One of the reason for this is the obfuscation but even with obfuscation disabled, SmartMS compiler has to rename inherited methods, which are not supported in the JavaScript. Similar scoping issues happen in variety of other situations (nested procedures f.i.).

 

Variant is supported as a data-type, but can only be used as containers. The compiler has no operators that deals with them (so you cannot write: A := 1 + myVariant, because there is no way to predict the resulting type without considerable overhead and loss of performance).

 

When interacting with ordinary javascript libraries or a remote webservice you natually have to go native with your data structures.

Under SmartMS this can be handled in a variety of ways but the two most common approaches are to either use records or variants.

 

Using Records

 

Records in SmartMS work just like they do in other object pascal environments. And since Smart compiles to javascript rather than machine opcodes, a record will always compile to an ordinary javascript structure. You should note that javascript really does not distinguish between what we would call a record and objects. In javascript everything is an object.

 

So the following object pascal code:

 

Type 

  TMyInfo = Record

    miName: String;

    miAge: Integer;

    miGender: Integer;

  End;

 

 

will result in the following predictable javascript code:

 

 

 {

    miName: ""

    miAge: 0

    miGender: 0

 }

 

This means that when you want to interact with native javascript libraries that expects a structure of values, you can use records to match it directly.

 

Published record properties can be automatically assigned to a field of a variant object (and not directly to the variant object itself).

 

Example code: Using variant object to create javascript object

type

 TRec = record

   public

     A: integer;

   published

     B: integer;

     S: string;

 end;

 

procedure TForm1.W3Button7Click(Sender: TObject);

var

   r:  TRec;

   v:  Variant;

   s:  string;

begin

   r.A := 17;

   r.B := 42;

   r.S := 'Smart!';

     v :=  TVariant.CreateObject;

   v.field  :=  r;

   asm  @s  =  JSON.stringify(@v);  end;

   Writeln(s);

end;

 

will output:

 

 {

   "field" : {

      "B" : 42,

      "S" : "Smart!"

   }

 }

 

 

You can use TVariant object to create javascript object structure exactly the same as that produced by the record.

For instance, this example will result in a memory record structure like this:

 

Type

 TMyData = Record

    test = Record

      somevalue: Integer;

    end;

    text: String;

  End;

 

 

Under SmartMS, variants are used to transport information between raw JavaScript methods. You can however have variant parameters and function results, but these can only be accessed by methods using ASM section.

The resulting javascript structure will be exactly the same as that produced by the record. One difference to keep in mind though, is that the compiler will output the names "as is". There is no way for Smart to map the content of a native object so make sure you get the names right.

For instance, to create arbitrary inline JS object:

Note: Field types can be type-inferenced or provided explicitly. 

Initialization values can be constants of dynamic values. 

Field names can be specified as strings to provide for naming conventions, valid in JavaScript but not in Object Pascal.

 

 

JSON2Variant example

Creating reader/writer class for storage is very easy. Once you have populated your object's data, you can use JSON to serialize and make it portable. Take a look at this example:

 

Code Example using JSON to Variant

 

 

To force a variant cast explicitly, you can use TVariant object that contains basic variant functions.

 

TVariant = class

    public

      class function AsInteger(const aValue: Variant): Integer; static;

      class function AsString(const aValue: Variant): String; static;

      class function AsFloat(const aValue: Variant): Float; static;

      class function AsObject(const aValue: Variant): TObject; static;

      class function AsBool(const aValue: Variant): Boolean; static;

      class function IsNull(const aValue: Variant): Boolean; static;

      class function IsString(const aValue: Variant): Boolean; static;

      class function IsNumber(const aValue: Variant): Boolean; static;

      class function IsInteger(const aValue: Variant): Boolean; static;

      class function IsBool(const aValue: Variant): Boolean; static;

      class function IsNAN(const aValue: Variant): Boolean; static;

      class function Properties(const aValue: Variant): TStrArray; static;

      class function OwnProperties(const aValue: Variant): TStrArray; static;

      class function CreateObject: Variant; static;

      class function CreateArray: Variant; static;

  end;

 

// Variants support functions:

 

  VarIsValidRef(const aRef: Variant): Boolean;  

  ObjToVariant(value: TObject): Variant;

  VariantToObj(const Value: Variant): TObject;

  VariantExtend(const target, prop: Variant) : Variant; overload;

  VariantExtend(target: JObject; const prop: Variant): JObject; overload;

  VarIsClear(v: Variant) : Boolean;

  VarIsEmpty(v: Variant) : Boolean;

  VarIsNull(v: Variant) : Boolean; 

 

 

VarIsValidRef function: Indicates whether the specified variant is neither Null nor undefined.

 

VarIsNull function: It returns true if the given variant contains the value Null. If the variant contains any other value, the function result is false.

 

Note: Do not confuse a Null variant with an unassigned/undefined variant. A Null variant is still assigned, but has the value Null. Unlike unassigned variants, Null variants can be used in expressions and can be converted to other types of variants.

 

VarIsEmpty function: It returns true if the given variant contains the value Unassigned. If the variant contains any other value, the function result is false.

 

Note: Do not confuse an unassigned/undefined variant with a Null variant. A Null variant is still assigned, but has the value Null. Unlike unassigned variants, Null variants can be used in expressions and can be converted to other types of variants.

 

VarIsClear function: It returns true if the given variant’s value is undefined. The value can be undefined for any of several reasons:

 

- The Variant may have had its value set to Unassigned/undefined.

- The Variant’s value may be an interface type that has been set to nil (Delphi) or NULL (C++).

- The Variant may be a custom variant that returns true from its IsClear method.

 

In all other cases, the function result is false.

 

Note: Do not confuse an unassigned variant with a Null variant. A Null variant is still assigned, but has the value Null. Unlike unassigned variants, Null variants can be used in expressions and can be converted to other types of variants.

*VarIsClear is not implemented in the SmartMS 2.1.

 

Code Example using VarIsValidRef, VarIsEmpty and VarIsNull

 

Methods

 

ToString() : String