Instantiation and destruction

Instantiating and using a class

Instantiating a class means to create an object in memory that corresponds to the form of a previously defined class. Before you instantiate a class, you must already have declared or imported it (see Creating a class or IMPORT). You might also have generated a prototype file (.dbp) for it (see Prototyping).

1. Declare a local variable that is an object handle to an instance of the class for the class type whose functionality you want to access. For example,
record
    x, @SomeClass
2. Instantiate the class, assigning the variable to the new object. This causes the constructor that matches the method signature of the call to be run. For example,
x = new SomeClass(someparams)

See NEW keyword for more information about this syntax.

3. Using the local object handle to reference the object, call an accessible method, or access an accessible field value. The following example accesses the method someMethod in the object referenced by x:
val = x.someMethod(someparams)

The example below accesses the value for the myfield field in the object referenced by x:

val = x.myfield
4. Add code to assign an object reference to a variable. The object instance must be the same or be a derived class of the declared destination variable type. (Note that this does not create a copy of the object but adds an additional reference to the same object.)
y, @SomeClass
y = x
5. Add code to clear the object reference held by the variable when finished with the object. If this is the last reference for the object, the object is released and the destructor is run before the object is finally deleted. The following example clears the object reference assigned to the local variable x:
clear x

Alternatively, the object reference is implicitly cleared when the variable goes out of scope (see Destroying a class instance for more information about data going “out of scope”). Or if a variable holds an object reference (for example, A), an assignment of another object to that variable releases the reference to object A.

6. Compile the application and link to the object file or ELB that contains the class being used.

The instantiations of nested and outer classes are not connected. Therefore, if you instantiate an nested class, its outer class is not automatically instantiated, and vice versa.

NEW keyword

When you instantiate a class, you will use the NEW keyword in one of the forms shown below:

variable = new class[<generic_type>]([arguments])
variable = new array_element_type[<generic_type>] [#[,#...] ]
variable = new type [<type_param_list>]([param_list]) [object_initializer_list]
variable = new array_element_type[<generic_type>] [#[,#...] ] [{initial_values}]     (.NET)
variable = new type [<type_param_list>]([param_list]) [collection_initializer_list]  (.NET)

variable

The variable name to assign to the new object.

class

The full name of the class to instantiate.

generic_type

(optional) A generic type parameter. See Generic types (.NET) for more information. (Synergy .NET only)

arguments

(optional) The argument values that you want to pass to parameterized constructors. Note that the parentheses are required even if no arguments are specified.

array_element_type

The type of the array.

#

The declared number of dimensions for each array element, or an actual pound sign (#) for automatically sized arrays. Note that the square brackets ([ ]) around the dimensions are required.

type

The name of the class to instantiate.

type_param_list

(optional) A list of types used to instantiate a generic class.

param_list

(optional) A list of parameters passed to the constructor when instantiating the class into an object. The parameter list can be omitted if the parameter-less constructor is to be called, although the parentheses are still required.

object_initializer_list

(optional) A comma-separated list of public property or field names and expressions that must be convertible to the type of the property or field to which they are being assigned. The list must be enclosed in braces. (See Object initializers below for more information.)

{object_member = expression [, object_member = expression,... ]}

initial_values

A comma-delimited list of initial values that autosizes the array if [#] is used instead of a declared number of dimensions. See Initial values for more information about initial_values. (Synergy .NET only)

collection_initializer_list

(optional) A comma-separated list of expressions that must be convertible to the member type of the collection being instantiated. The list must be enclosed in braces. (See Collection initializers (.NET only) for more information.)

{ expression[, expression] }

Here are some examples:

Myvar = new int [10]
Myvar = new int [#] {1,2,3}
Myvar = new list<T>[3]
Myvar = new class1()
Myvar = new myClass() {myfld = 2}
Myvar = new list<int>(){1,2,3,4,5}
data Myvar, [#]int, new int[#] {1,2,3,4}

The passed arguments determine which class constructor will be executed, because the arguments are compared against the method signatures of the declared constructors for the class. The constructors for inheriting classes are called in hierarchy order when the class is instantiated. For example, if classC extends classB which extends classA, and classC is instantiated, Synergy/DE will run the constructors in the following order: classA, classB, and then classC.

Object initializers

Object initializers enable you to instantiate an instance of a class and set public properties or fields without separate assignment statements. The properties and fields can be initialized within an expression or passed as a parameter, and they can be initialized to literals, existing objects or value types, or collection initializers.

In traditional Synergy, property and field initializers are only allowed on DATA statements (or assignments to DATA statement variables). Also, they cannot be nested. For example, if an object being instantiated contains an object handle property, that property cannot be set to a new instance that has a property initializer.

The following is an example of a property initializer:

public class myClass1
    private fld,                i4
    public property myfld,      i4
        public method get
        proc
            mreturn fld
        end
        public method set
        proc
            fld = value
        end
    endproperty
endclass
.
.
.
main
record
    hnd,        @myClass1
proc
    hnd = new myClass() {myfld = 2}
end

Collection initializers (.NET only)

A collection initializer enables you to create a collection object and populate it with members. This allows collection classes to be instantiated and filled within an expression or passed as a parameter. Members can be literals, existing objects or value types, other collection initializers, property initializers, or field initializers. Collection initializers are useful when you are creating a collection from a set of known values, such as a list of products or an initial set of numeric values.

The class being instantiated must implement the System.Collections.IEnumerable interface.

Destroying a class instance

After the last reference to the instantiated class has been released, the destructor method for the class and any of its parents are called in reverse hierarchy order. For example, if classC extends classB which extends classA, and an instance of classC is getting destroyed, Synergy/DE will run the destructors in the following order: classC, classB, and then classA.

Some of the events that cause references to be released, which could result in the destruction of the object, are the object variable going out of scope, being cleared, or being reassigned. Conditions under which data goes out of scope are shown in the table below.

When data goes out of scope

Data

Out-of-scope condition

A local stack variable defined by the DATA statement

The end of the block is reached

A caught exception

The end of the block is reached

Stack record data

The end of a local record or routine is reached

Class data

The class is destroyed

Common and static record data

The field is cleared

Important

Circular references can cause objects not to be released, and the majority of circular references are not found by the compiler. As an application developer, it is your responsibility to remove circular references from your code. If you do not, your program will experience memory leaks. (You can locate circular references in your code using the debugger SHOW CLASSES/WARNINGS command.)

In traditional Synergy, object handles declared via the DATA statement reduce the object reference count when the block is exited, and the destructor is automatically called if the reference count goes to zero. In .NET, the object lifetime is nondeterministic and depends only on the garbage collector. Reference counting does not occur. Destructors can be called in any order and may be called after the STOP statement.

In Synergy .NET, going out of scope “marks” the object for possible destruction by the garbage collector. It is important that classes implement the IDisposable.Dispose method if deterministic finalization is required. In .NET, destructors may be called on shutdown and may require that channels not be closed before the STOP statement. Be aware that when the garbage collector runs destructors, they run in a parallel thread, and you must avoid (or use a critical section to synchronize) any I/O statement in your destructor if that same channel may be in use on another thread (including the main thread). This is most important when using xfServer. For more information when using xfServer, see S_SERVER_THREAD_INIT. For information about the IDisposable.Dispose method, see the DISPOSABLE qualifier to DATA.