Boxing

Boxing and unboxing are the built-in capabilities of the compiler and runtime to convert value types and descriptor types to or from objects. Note that id is used to define a boxed implied-decimal data type (d.), and ip is used to define a boxed implied-packed data type (p.).

The variable used to hold a boxed value can be declared as either explicitly typed (@a, @d, @i4, etc.) or untyped (@*). Keep in mind that a typed boxed variable is processed and validated at compile-time. To box a value, you must cast it using either the boxing cast syntax (@type) or (object). When you box using the (@type) cast, the value is explicitly boxed as the specified type.

obj = (@d)dvar
Note

When boxing a numeric literal, the expression type defaults to d. Therefore, in order to box an integer or implied-decimal, you need to explicitly cast the literal as (@i4) or (@id).

When you box using the (object) cast, the type of the expression determines the type inside the box. The runtime creates an object and then puts a copy of the value type into the object. For example,

obj = (object)mystructvar

Boxing occurs automatically in the following circumstances:

When an item is boxed, it is of type @System.Object, so only System.Object’s members are accessible (for example ToString()). Boxing is very important when using the ArrayList classes (System.Collections.ArrayList and Synergex.SynergyDE.Collections.ArrayList), because the ArrayList can only deal with entities derived from System.Object.

Note

If @System.Object=@d, you can only unbox the object to a d, and you must do it explicitly. The object cannot be automatically unboxed because the compiler can’t detect its type.

In .NET, boxing occurs automatically only when a value type is assigned to a variable or parameter of type object.

An error will occur if you do any of the following:

Unboxing

Before you can access (or compare) members of a boxed type, the boxed type must first be unboxed. Unboxing allows access to the value type inside the boxed object.

In most cases, you will need to explicitly cast the result to unbox it. However, the boxed type is automatically unboxed under the following circumstances:

Automatic unboxing requires the boxed variable to be explicitly typed.

The following example does an automatic unbox on a field access of a boxed structure:

record
    shnd        ,@mystruct
    svar        ,mystruct
            shnd = (@mystruct)svar
    x = shnd.fld                ;Automatic unbox

However, for an unknown boxed type, such as

obj     ,@*

you cannot use automatic unboxing. Instead, you must explicitly cast the variable to unbox it:

obj = shnd
x = ((mystruct)obj).fld         ;Unbox

In the example below, the automatic box of the variable field creates a new object of type @i4 (the type of variable field) and copies in the value of the variable field:

record
    ifield,     int
    field,      i4
    sfield,     structure
    ooi4,       @i4
    oosfield,   @structure
    oifield,    @int
    .
    .
    .
    ooi4 = (@i4)field
    oosfield = (object)sfield
    oifield = (object)ifield
    field = (i4)ooi4
    sfield = (structure)oosfield
    ifield = (int)oifield

To unbox, the runtime extracts the i4 from the object in the example above and stores it in the variable field. For example,

field = (i4)ooi4
sfield = (structure)oosfield

The reason that we specify @i4 and i4 when we box field and unbox ooi4 is that integer fields (which are usually descriptor types) are often converted to native .NET data types (value types) for optimization: i1 becomes System.Sbyte, i2 becomes System.Int16, i4 and int (which are synonymous in traditional Synergy) become System.Int32, and i8 becomes System.Int64. For the most part, these conversions are seamless; you don’t need to consider them as you code. They can, however, cause problems if you rely on automatic boxing or unboxing. For example, the following code (which works with traditional Synergy) won’t work with .NET because casting ivar as (object) results in an @int, which can’t be unboxed to an (@i4), as shown below. (You can’t unbox one type to another.)

record
    num,        @object
    ivar,       i4
proc
    num=(object)ivar            ;Results in an @int
    ivar=(i4)num                ;Attempts to unbox the @int to an (@i4)

To prevent this, force the data type as you box and/or unbox to ensure you use the same type. For example, the above would work for both traditional Synergy and Synergy .NET if ivar was explicitly boxed using (@i4):

num=(@i4)ivar

or unboxed using (int):

ivar=(int)num