Defines a method of a class, declares a method prototype in an ABL interface, or overrides a method inherited from an ABL or .NET super class. A method is a class member that, when invoked by name, can execute code and return a value similar to a user-defined function. The description that follows begins with the general syntax for defining a method.
Note: This statement is applicable only when used in a class or interface definition (.cls) file.
Specifies the access mode for this method. A PRIVATE method can be called by the defining class. An instance can call the private method of another instance if they are both from the same class. A PROTECTED method can be called by the defining class and any of its derived classes. An instance can call the protected method of a second instance that is at the same level or higher in the class hierarchy. A PUBLIC method can be called by:
The defining class
Any of its derived classes
Any class or procedure that has access to a class instance that defines or inherits the method
Any piece of code can call a PUBLIC static method. The default access mode is PUBLIC.
When declaring an interface method prototype, the access mode for this method must be PUBLIC (the default).
When defining an abstract method, the access mode for the method cannot be PRIVATE.
If this method is defined with the OVERRIDE option, the access mode must not be more restrictive than the access mode defined for the overridden ABL or .NET super class method. ABL access modes correspond to inherited .NET access levels as follows:
PROTECTED matches either the .NET protected or protected internal access level
PUBLIC matches the .NET public access level
Note: The PRIVATE/PROTECTED/PUBLIC modifier and the STATIC/ABSTRACT modifier can appear in either order, e.g., METHOD STATIC PUBLIC VOID myMethod():... is valid syntax.
[ STATIC ]
Defines a method that is a static member of the class type for which it is defined and that is scoped to the ABL session where it is referenced. You can call an accessible static method in any piece of code.
Without this option, ABL defines an instance method that is scoped to a single instance of the class where it is defined. You can call any public instance method (abstract or non-abstract) in any procedure, or in any instance or static method defined inside or outside of the class where the instance property is defined. Any static method can call the public instance method only using an object reference to a class instance that defines the instance method as a member. If the referencing static method is defined in the same class as the public instance method, the class must instantiate itself in order to have access to an instance reference.
Note: In ABL, all PRIVATE and PROTECTED access modes are class based. An instance can access the PRIVATE member of another instance if both instances are from the same class. Likewise, a PROTECTED member can be accessed from any instance of the class or subclass that defines it. In other words, an instance can access a protected member of a second instance that is from the same level or higher in the class hierarchy..
For more information on the mechanism for calling methods of different access modes and scopes, see the reference entry for Class-based property access.
The STATIC option is not valid when you:
Define or implement an abstract method
Declare an interface method prototype
Implement an interface method
[ ABSTRACT ]
Defines the method as an abstract member of the class type for which it is defined. The defining class type must also be abstract. If you define an abstract method, it has the following requirements:
You must specify the OVERRIDE option if an inherited method (abstract or otherwise) has the same name and signature.
You can specify either a PROTECTED or a PUBLIC access mode, depending on any inherited method you might be overriding.
The abstract method must be overridden and implemented in a derived class.
Any class definition for an instance method that includes the OVERRIDE option and does not include the ABSTRACT option defines a method implementation. If it also includes the ABSTRACT option, the inherited method remains or is redefined as abstract.
This option is not valid either when you define a static method or you declare an interface method prototype.
[ OVERRIDE ]
Specifies one of the following:
This instance method overrides the behavior of another instance method inherited from an ABL or .NET class.
This instance method implements, or redefines as abstract, an abstract method inherited from an ABL or .NET abstract class.
This instance method redefines as abstract an implemented method inherited from an ABL or .NET class.
A .NET abstract class is defined in C# with the abstract keyword.
This static method redefines the behavior of another static method implemented in a super class.
When you specify OVERRIDE, the method signature must match the overridden method with respect to the name, return type, and the number, types, and modes of its parameters. In addition, the access mode cannot be more restrictive than the access mode of the super class method it overrides. When overriding a .NET method, the return type and parameters must also map appropriately to the inherited .NET method return type and parameters. For more information, see the description of the return-type and parameter options.
If you are overriding an inherited abstract method and you specify the ABSTRACT option, your overriding method is also defined as abstract, and it must be implemented in a class derived from the defining class. Note that you do not have to override an inherited abstract method that you want to remain abstract as long as the inheriting class is also abstract. However, doing so allows you to specify a less restrictive access mode for the abstract method.
If you do not specify the ABSTRACT option when overriding an inherited abstract method, your method definition implements the abstract method.
If you are overriding an inherited method that already has an implementation and you specify the ABSTRACT option, your overriding method redefines the inherited method as abstract, and it must, again, be implemented in a class derived from the defining class. Note that to redefine an inherited method as abstract that already has an implementation, the defining class must also be abstract.
Note that instance methods do not override static methods and static methods do not redefine instance methods. For more information about overriding and redefining methods, see OpenEdge Development: Object-oriented Programming.
You can only override methods of a .NET super class that, in C# terms, are:
Declared as virtual or abstract
Declared as public, protected or protected internal
Not declared as static or sealed (FINAL)
This option is not valid when you declare an interface method prototype.
[ FINAL ]
Indicates this method cannot be overridden or redefined by a method defined in an inheriting subclass.
This option is not valid either when you define an abstract method or when you declare an interface method prototype.
VOID
Indicates this method does not return a value.
return-type
Indicates the data type of the method return value. You can specify return-type as one of the following data types. For more information on each data type, see the Data types reference entry:
{ CHARACTER | COM-HANDLE | DATE | DATETIME | DATETIME-TZ
| DECIMAL | HANDLE | INT64 | INTEGER | LOGICAL | LONGCHAR
| MEMPTR | RAW | RECID | ROWID |AS-data-type |[ CLASS ]object-type-name}[ EXTENT [constant]]
AS-data-type
If you are defining the return type for a method that overrides a .NET super class method (abstract or otherwise) or implements a method defined in a .NET interface, return-type must specify the exact return type of the overridden or implemented .NET method. For a .NET mapped data type that is a default match for an ABL primitive type, you must use the default matching ABL data type, as shown in Table 24. (For example, INTEGER indicates a .NET System.Int32.) For a .NET mapped data type that is not a default match for one of the ABL primitive types, ABL provides a data type keyword (the AS-data-type) that you must use to explicitly indicate the required .NET data type, as shown in Table 25. (For example, UNSIGNED-BYTE indicates a .NET System.Byte.)
At run time, a method return type defined using an AS-data-type keyword behaves in ABL like the corresponding ABL primitive type shown in Table 25. (For example, an UNSIGNED-BYTE behaves like an INTEGER.)
Also note that when overriding or implementing a .NET array return value, you must specify the .NET array object type (for example, "System.Int32[]" or "System.Byte[]"); you cannot use an ABL array equivalent (for example, INTEGER EXTENT or UNSIGNED-BYTE EXTENT).
object-type-name
Specifies the type name of an ABL or .NET class or interface. Specify an object type name using the syntax described in the Type-name syntax reference entry. With an appropriate USING statement, you can also specify a class or interface name alone, without the qualifying package or namespace.
If you are defining the return type for a method that overrides a .NET super class method (abstract or otherwise), or that implements a method defined in a .NET interface, object-type-name must specify the exact return type of the overridden or implemented .NET method. However, for .NET inner (nested) type, note the difference in the ABL syntax, which replaces the corresponding period (.) in the .NET object type with a plus (+) (see the Type-name syntax reference entry).
Also note that when overriding or implementing a .NET array return value, you must specify the .NET array object type (for example, "System.Drawing.Point[]"); you cannot use an ABL array equivalent (such as System.Drawing.Point EXTENT).
[ CLASS ]
If the specified class or interface type name conflicts with an abbreviation of a built-in primitive type name, such as INT for INTEGER, you must specify the CLASS keyword.
For a class or interface return value, ABL returns an object reference associated with the class or interface, not a class instance itself. For more information on object references, see the Class-based object reference reference entry.
[ EXTENT [constant]]
Defines the return value as an array of data elements with a primitive or object data type. This option can specify an array return value as either determinate (has a defined number of elements) or indeterminate (has an undefined number of elements). To define a determinate array return value, specify the EXTENT option with the constant argument. This optional argument is an integer value that represents the number of elements in the array. To define an indeterminate array return value, specify the EXTENT option without the constant argument.
An indeterminate array return value can be in one of two states: fixed or unfixed, meaning it either has a fixed dimension or it does not. An indeterminate array return value has an unfixed dimension when first defined. You can fix the dimension of an indeterminate array return value by:
Setting the number of elements in the array return value using the EXTENT statement
Assigning a determinate array to the indeterminate array value, fixing it to the dimension of the determinate array
Passing array parameters to a procedure, user-defined function, or class-based method, so that the indeterminate array value is the target for the passing of a determinate array, fixing the indeterminate array to the dimension of the determinate array
Once fixed, ABL treats a fixed indeterminate array as a determinate array.
If you do not use the EXTENT option (or you specify constant as 0), the return value is not an array return value.
method-name
The method name. This name must be unique among all methods defined in the class hierarchy of the defining class, unless the method:
Includes the OVERRIDE option to override an inherited method.
Overloads a method in the defining class or in any super class within its inherited class hierarchy. In this case, the parameter list must differ from that of every other method with the same name in the defining class, and it must differ from that of every other method with the same name defined in every super class of the defining class.
Note: Members of a class are grouped into six namespaces, including buffers/temp-tables, methods, variables/properties/events, ProDataSets, queries, and data-sources. Methods defined as members of a class share the same namespace. There can be only one class member in this namespace with a given name. If the method is defined in a class that is derived from a .NET class, other restrictions on method-name apply. For more information, see the Notes in this reference entry.
( [parameter[ , parameter]...] )
Defines zero or more parameters of the method.
If this method is one of several overloaded methods, the parameter list must be unique among all public and protected methods defined in the class hierarchy of the defining class. This uniqueness can be established using a different combination of number, data types, or modes for the parameters. Note that both instance and static methods overload one another within the class hierarchy.
If this method implements an interface method prototype or overrides an inherited method (using the OVERRIDE option), the parameter list must match the parameter list of the interface method prototype or a public or protected method with the same name that is inherited from a super class.
If the method implements a .NET interface method prototype or overrides an inherited .NET method (abstract or otherwise), you must explicitly map any .NET mapped types specified for parameters of the .NET method (see Table 25). Note that at run time, any explicitly mapped parameter behaves like the corresponding ABL primitive type.
For more information on the syntax of parameter, establishing uniqueness for method overloading, and on mapping .NET parameter types, see the Parameter definition syntax reference entry.
method-body
The body for a method implementation. For an interface method prototype or an abstract method, you cannot specify method-body. For more information about declaring method prototypes in an interface, see the INTERFACE statement reference entry.
The logic of the method. This logic can contain the ABL statements that are allowed within a procedure block, including class-related statements.
If you define the method to return a value of the data type specified by return-type, you can execute the RETURN statement to set a value of that data type to return at run time. If return-type is defined as a .NET array of mapped types (for example, "System.Byte[]"), you must return an object reference of the specified .NET array of mapped types in the RETURN statement. You cannot return an ABL array of a type that maps to the .NET array type (for example, INTEGER EXTENT) or the AVM raises a run-time error. If you do not execute any RETURN statement for return-type in the method-logic, the method returns the Unknown value (?) as its return value.
If you are defining an instance method with the OVERRIDE option, you can also call the overridden implementation of this method in the class hierarchy using the SUPER system reference. You can also optionally call any instance method defined in the same class using the THIS-OBJECT system reference.
If you are defining a static method, you cannot access any instance members of a class (including the defining class) nor can you use the SUPER and THIS-OBJECT system references. From a static method, you can access only other static members of a class and the local variables or other local data elements of the method.
Each logic statement must end with a period.
catch-block
Specifies a CATCH statement that defines error handling code for one or more error types. A DO block does not have any default error handling. Therefore, a DO block must have error handling options specified such that it becomes an undo-able block. Otherwise, ABL generates a compiler warning. For more information on catch-block, see the CATCH statement reference entry.
finally-block
Specifies a FINALLY statement that defines the processing that must occur after all other processing in the block occurs. For more information on finally-block, see the FINALLY statement reference entry.
END [ METHOD ]
Specifies the end of the method body definition. You must end the method body definition with the END statement.
Examples
The following example shows the definition of an instance method in a class (which might implement a method prototype declared in an interface, as depicted in the second example):
METHOD PUBLIC CHARACTER GetCustomerName (INPUT inCustNum AS INTEGER):
FIND ttCust WHERE ttCust.CustNum = inCustNum NO-ERROR.
IF AVAILABLE ttCust THEN
RETURN ttCust.CustName.
ELSE
RETURN ?.
END METHOD.
The following example shows the definition of a method prototype declaration in an interface (which can be implemented by an instance method definition in a class, as depicted in the first example):
INTERFACE acme.myObjs.Interfaces.ICustObj:
METHOD PUBLIC CHARACTER GetCustomerName (INPUT inCustNum AS INTEGER).
END INTERFACE.
For more examples of method definitions, including static and abstract methods, see the descriptions of r-CustObj.cls, r-CustObjStatic.cls, and r-CustObjAbstract.cls in the CLASS statement reference entry.
Notes
You can terminate a METHOD statement with either a period (.) or a colon (:), but typically use a colon (:) for a method definition (in a class) and a period (.) for a method prototype (in an interface).
A complete method definition must begin with the METHOD statement and end with the END statement.
A method can access any data members and properties in its defining class including all PROTECTED and PUBLIC data members and properties defined anywhere in its inherited class hierarchy. For more information on referencing data members and properties, see the reference entries for a Class-based data member access and a Class-based property access.
A method of a class can invoke another method of a class (instance or static, as appropriate), as well as an internal or external procedure or a user-defined function. Similarly, a procedure or user-defined function can invoke a method of a class. Note that if method-name is an ABL reserved keyword, you might need to use the THIS-OBJECT system reference or Type-name syntax to call the method. For more information on referencing and invoking methods, see the reference entry for a Class-based method call.
Local variables and other data elements defined within a method are scoped to the end of the method definition. The values of local variables and data elements do not persist across method invocations; they are re-initialized each time you invoke the method. However, if you define a local variable within a method using the same name as a data member or property within the class hierarchy, the local variable takes precedence over the data member or property for the duration of the method.
When defining local variables and other data elements for any method, even one that overrides or implements a .NET method, you cannot define these elements using an AS data type (see Table 25). You must use an ABL data type like any other method definition. The ABL data that you assign to or from a given .NET method parameter must be assignment compatible with the .NET type, as in all other contexts.
You cannot specify the PRIVATE, PUBLIC, or PROTECTED access mode for variable definitions in a method.
You cannot define SHARED objects, work tables, temp-tables, or ProDataSet objects within the body of a method.
ABL implements primitive and array parameters of methods as NO-UNDO variables.
You can handle application errors in a method as in any ABL block. By executing a RETURN ERROR action at the block level or a THROW action at the block level with the presence of a ROUTINE-LEVEL ON ERROR UNDO, THROWstatement, the AVM returns the ERROR condition to the statement that invoked the method. If a RETURN ERROR also includes the option to return a character string value, or you set the ReturnValue property of a Progess.Lang.AppError object that you THROW, you can get this value using the RETURN-VALUE function following the statement that invoked the method or in a CATCH block that catches the Progress.Lang.AppError object. For more information, see OpenEdge Development: Object-oriented Programming.
You cannot override an inherited .NET generic method. However, you can create a non-generic ABL method of the same name (without a type parameter list).
You cannot override the following .NET methods:
DestroyHandle( )
Dispose( )
Finalize( )
GetHashCode( )
In .NET, these methods are overridable. However, OpenEdge defines these methods as FINAL for an ABL session. Instead of overriding .NET methods (such as Dispose( )) that destroy or otherwise clean-up .NET resources, always use a destructor in the ABL class to manage class clean-up using these methods, even when inheriting from a .NET class. Similarly, if you want to return an ABL-processed value generated by GetHashCode( ), create a separate ABL method that calls GetHashCode( ) to return the value.
When you define a method in an ABL class that inherits a .NET class, you cannot define method-name as any of the following reserved method names (case insensitive) or ABL raises a compile-time error:
Get_property-name( ) — Where property-name is the name of a property (including any default indexed property) defined by the .NET super class
For default indexed properties, property-name is usually Item.
Set_property-name( ) — Where property-name is the name of a property (including any default indexed property) defined by the .NET super class
Add_event-name( ) — Where event-name is the name of an event defined by the .NET super class
Remove_event-name( ) — Where event-name is the name of an event defined by the .NET super class
When you raise error from within an ABL method that overrides a .NET method or implements a .NET method defined in a .NET interface, if the method is called from .NET, and ABL error options raise the error out of the method block, ABL returns a .NET System.Exception to the caller. If the error is raised by executing a RETURN ERROR with the optional error string, the Message property of the System.Exception describes the operation where the error occurred, but the error string is available only to the ABL session, using the RETURN-VALUE function. If the error is raised by executing a RETURN ERROR with an optional ABL error object or by executing an UNDO, THROW, the System.Exception:Message property includes both a description of the operation where the error occurred and any messages from the ABL error object. If the error is fatal, the AVM responds as for any ABL class, generating a protrace file and exiting the session.