Open topic with navigation
A class member is any item that can be declared within a class declaration, such as a method, a field, a property, another nested class, and so on. This topic discusses the following class members:
A method is a routine within a class declaration that performs an operation using the fields of that class. When you declare a method, you can specify the following:
If you give a class method the same name as a Synergy statement (for example, close), to get the method call, you may have to further qualify the call to such a method with either the this initializer (for example, this.close) or, if it’s static, with the qualified name (for example, myns.myclass.close). We recommend that you don’t redefine statements, to avoid having to fully qualify method calls.
See the Synergex YouTube video Object-Oriented Methods and Properties for more information about methods.
A method signature is the fully qualified name of a method, which includes the namespace name(s), class name(s), method name, argument types, and return type, in the form
namespace[.namespace_n].class[.class_n].method(type[, type, ...])rettype
where namespace is the namespace or nested namespace names and class is the class or nested class names containing the method method. Type can be one of the following:
Rettype is the method’s return type, which in addition to the above types, includes VOID.
Overriding a method
Overriding a method means providing a method declaration in an inherited class that supersedes the method declaration with the same signature in the parent class. For every parent class method that you want to override, you must add a method declaration and implementation to the derived class and specify the OVERRIDE modifier in the METHOD statement. The signature for the derived class method must match the signature for the parent class method that’s being overridden. In addition, the parent class method must be marked as VIRTUAL, ABSTRACT, or OVERRIDE.
On OpenVMS, if the class is in a shared image, you must do an OPENELB of the shared image so that the virtual method can be found.
Overloading a method
A method is overloaded when another method in the same class has the same name but different arguments. Overloading enables you to perform analogous operations on different types of data. Calls to methods are resolved based on the types of the arguments passed in the call, and the best match is selected from overloaded methods.
In Synergy .NET, overloading by calling convention (that is, a BYVAL parameter and a BYREF parameter of the same type) is not supported.
You can add a subroutine or function to a class by enclosing the existing subroutine or function inside a class declaration.
The following rules apply to subroutines and functions within a class:
A class can optionally contain one or more field declarations, which may or may not be encapsulated in a record declaration. For example,
public class myclass private myfield ,i4 public record myrecord myfield2 ,i4 myfield3 ,i4 endrecord endclass
A class record can either be named or unnamed. If a record identifier is declared, it represents an instance variable of that record type within the class and can be used to access fields in that record. Field identifiers are optional in a named record. However, if the record is unnamed, fields in that record must have identifiers.
A field declared in a class outside of a record is called a loose field (for example, myfield in the example above). Only loose fields of .NET-compliant types are accessible from other languages. (Optimally all .NET class fields are defined this way.)
You can also declare a named group within a class record. A named group and its members inherit the accessibility of the record, if specified; otherwise, they default to private.
You can optionally declare any field modifier or access modifier on a record within a class. The specified modifiers apply to all groups and fields in that record unless overridden at the fieldlevel. (See Defining a field for the syntax of a field definition and for more information about field modifiers and access modifiers.)
Neither a common record nor a global data section may be declared within a class.
The ENDRECORD delimiter within a class or routine is optional. If you don’t specify it, the next nonfield member of the class delimits the record.
Upon instantiation of a class that contains fields, all of the fields in that class are initialized. You can get or set an accessible field value from an instantiated class as follows:
value = var1.myfield var1.myfield = value
The lifetime of a class field, class record, or class group is determined by the lifetime of the class instance. This is called instance data. There is one copy of instance data in each object instance of a given class.
When a data field is designated as STATIC, its value can be accessed (both read and write) even if the class that contains the field hasn’t been instantiated. Only one copy of static data exists, while many copies of instance data may exist. To access a static field for a class, append the class name to the beginning of the field name. For example,
MyClass.myfield = value
Classes can also contain traditional Synergy and Synergy .NET structures, which can have accessibility modifiers to determine when they can be used. The ENDSTRUCTURE delimiter within a class or routine is optional.
A property is usually used to provide controlled access to data within a class. In referencing routines, properties can be treated as if they were class fields, with certain restrictions. These restrictions include the following:
A field name and a property in the same class can have the same name as long as the case is different. In this situation, the compiler becomes case sensitive when resolving paths within that class. If the calling path doesn’t exactly match the case of either member, an “Ambiguous symbol” error (AMBSYM) occurs.
To add a property to a class and then use it in a program,
|1.||Create a new class or edit an existing class.|
|2.||Use the PROPERTY statement to add a property to the class defining a get accessor method
and/or a set modifier method that accesses a field value. For example,
public class myclass private myfield, i4 public property myproperty, i4 method get proc mreturn myfield endmethod method set proc myfield = value endmethod endproperty endclass
|3.||Save the file containing the class declaration and compile it.|
|4.||Add code to use the property. For example,|
c1, @myclass var1, i4 c1 = new myclass c1.myproperty = 5 var1 = c1.myproperty
An indexer allows methods on an object to be called as though the object is an array. An indexer has the same requirements as a property, with a few additional requirements:
m, @myclass i, i4 m = new myclass()
m = 23 would run the set accessor, and i = m would run the get accessor.
See Indexer properties for an example.
See the Synergex YouTube video Object-Oriented Methods and Properties for more information about properties.
A delegate is a type-safe function pointer used by the .NET Framework that enables you to pass a method as a parameter value. See DELEGATE-ENDDELEGATE for more information.
An event is an action that occurs as a result of another action (for example, a mouse click). See EVENT for more information.
An interface is a contract for a class that defines the properties, methods, and events that the class must use. See INTERFACE-ENDINTERFACE for more information.
An enumeration is a data type that consists of a set of named values. See ENUM for more information.
A nested class is a class declared within another class declaration. There is no limit to the number of nesting levels you can have.
You must use the name of the outer class as well as the nested class when referencing a nested class. In other words, the outer class name acts as if it were a namespace. For example, to create an instance of a nested class named class3, you would do the following:
p1, @class2.class3 p1 = new class2.class3( )
A nested class has access to any of the other members of an outer class, regardless of accessibility.
Instance data would be accessed via an instance of the containing class, while static data would be available using the class itself. For example,
class c1 static x ,i4 y ,i4 class c2 method m1 ,void record h1 ,@c1 proc h1 = new c1() c1.x = 5 h1.y = 10 end endclass endclass
For a list and explanation of the operators that can be declared within a class, see Object operators.
A constructor is a class member method that is called whenever an instance of the class is created. It has the same name as the class. It is common to put initialization code in a constructor.
Constructors can have parameters, and a class can have multiple constructors as long as the method signatures are different.
public class class2 public method class2 ;Default constructor endmethod public method class2 ;Constructor that takes an i4 p1, i4 endparams endmethod
A constructor cannot have a return type. Only access modifiers (PUBLIC, PROTECTED, and PRIVATE, INTERNAL, and PROTECTED INTERNAL) and STATIC are allowed on a constructor. If you don’t declare a constructor, the compiler automatically generates a default constructor that has public accessibility. A static constructor is called on the first reference to the type, which could be when an instance constructor is called or when a static member is accessed directly. The debug name of the constructor is !MyClass. (MyClass is the name of the class containing the static constructor.)
You can also declare a constructor initializer to run in conjunction with a constructor. The initializer can be specified as parent, to run a parent class constructor, or this, to run a current class constructor, followed by zero or more argument values.
To call the sibling constructor (using the specified optional arguments), use this syntax:
To call the base constructor (using the specified optional arguments), use this syntax:
If you don’t specify an initializer, the default constructor, parent(), is assumed.
For example, if the mychild class extended another class and you wanted to run its constructor that took an i4 value, your code might look like this:
method mychild p1, i4 endparams parent(p1) proc endmethod
If this constructor called another constructor within mychild, it might look like this:
method mychild p1, i4 endparams this() proc endmethod
The initializer method signature must resolve to a constructor method in the parent class (if parent is used) or in the current class (if this is used). In traditional Synergy, you must not create a circular reference; otherwise, you will create an object that is never destroyed. (See Accessing members of the current instance or base class for more information about this and parent.)
A destructor is a class member function that is called before an instance of the class is destroyed. You can use it to perform any class-specific cleanup operations before the last reference to the class instance is cleared.
You can optionally declare a single destructor for a class by giving the method the same name as the class with a tilde (~) at the beginning. For example,
public class class2 method ~class2
By default, a destructor is a virtual method that has protected accessibility.
Only one destructor is allowed for each class. A destructor declares no parameters and cannot return any values.
A destructor must never throw an exception, because it is called as part of the runtime cleanup. If errors in a destructor are not trapped, they can cause the runtime to enter an infinite loop. Therefore, you should always use the ONERROR or TRY-CATCH statement in a destructor to ensure the destructor exits.
In Synergy .NET, destructors are nondeterministic. Order and timing are at the discretion of garbage collection, and they may even execute after a STOP statement.
The Synergex YouTube video Constructors and Destructors contains additional information.
Also see Instantiation and destruction.