Try OpenEdge Now
skip to main content
Object-oriented Programming
Getting Started with Classes, Interfaces, and Objects : Using the CLASS construct : Defining methods within a class : DEFINE METHOD statement
 
DEFINE METHOD statement
This is the syntax for defining a class-based method using the METHOD statement:

Syntax

METHOD {method-modifiers }{ VOID |return-type}method-name
       ( [parameter[ , parameter]...] ) { : | . }[method-body
END [ METHOD ] . ]
Element descriptions for this syntax diagram follow:
method-modifiers
A list of options that modify the behavior of the method. They can appear in any order as specified in the following syntax:
[ PRIVATE | PROTECTED | PUBLIC ][ STATIC | ABSTRACT ]
[ OVERRIDE ][ FINAL ]
[ PRIVATE | PROTECTED | PUBLIC ]
The access mode for the method. The default method access mode is PUBLIC. PRIVATE methods are accessible from within the class where they are defined. An instance can access a PRIVATE method of another instance if they are both instances of the same class. PROTECTED methods are accessible from within the class where they are defined and in any subclass of the defining class. An instance can access a PROTECTED method of a second instance of a class that is at the same level or in a super class in the class hierarchy. You can call a PUBLIC method from within the class that defines the method, from within any class that inherits the defining class, and from any class or procedure that references the defining class. For more information on calling methods, see Calling class-based methods.
An abstract method prototype cannot be defined as PRIVATE, and an interface method prototype can only be defined as PUBLIC.
[ STATIC ]
Specifies the scope of the method. By default, methods of a class are instance methods, meaning that a given method is defined and available for each instance of the class in which it is defined. However, methods can also be defined as static using this keyword. ABL defines a given static method on first reference to the class type in which it is defined, scopes that method to the class type, and makes it available through that class type for the duration of the ABL session. Unless specified otherwise, a reference to a method in this manual is assumed to be a reference to an instance method.
You cannot define a static method as abstract.
For more information on static methods, see Using static members of a class.
[ ABSTRACT ]
Declares the method as abstract using an abstract method prototype. Each method prototype is declared by a single METHOD statement, with a signature, but with no implementation and no END METHOD statement. Abstract methods can be defined as either PROTECTED or PUBLIC. These method prototypes cannot specify the STATIC option. An abstract method can only be an instance method. Abstract method prototypes can be overloaded and can overload implemented method definitions. Note that a constructor or destructor cannot be abstract.
An abstract method must be implemented in some class (abstract or non-abstract) that derives from the class that defines the abstract method. The class that implements this abstract method must fully define a corresponding method that matches this method prototype, but without the ABSTRACT option. In addition the implemented method can have a less restrictive access mode, if available (PUBLIC if the abstract method is PROTECTED).
You can only define an abstract method in an abstract class definition.
[ OVERRIDE ]
Specifies that this method overrides a method defined in a super class in the class hierarchy. The compiler verifies that this method has the same return type, the same or a less restrictive access mode, the same scope (instance or static), and the same number, modes, and data types of parameters as a method of the same name in a super class. If any of these tests fail, the compiler generates an error.
Note that to implement an inherited abstract method, a method definition overrides the abstract method. However, an abstract method prototype can also override an inherited method that is already implemented. In this case, the method is redefined as abstract and must be implemented, again, in a further derived class. This is different from the definitions of properties and events, which can never override an implemented (non-abstract) property or event, respectively.
[ FINAL ]
If specified, this method cannot be overridden. Any class that inherits from this class cannot define a method with the same method name as this method.
The FINAL option is permitted but irrelevant on a PRIVATE method, or on any method within a class that itself has been defined as FINAL. A subclass can define a method with the same definition as a PRIVATE method in its super class. However in this case, the subclass has simply defined its own method and is not overriding the super class's method.
VOID |return-type
The return-type is the data type of the value returned by the method. The data types that can be returned by a method are the same data types supported for return values by user-defined functions: CHARACTER, CLASS, COM-HANDLE, DATE, DATETIME, DATETIME-TZ, DECIMAL, HANDLE, INT64, INTEGER, LONGCHAR, LOGICAL, MEMPTR, RAW, RECID, ROWID; where CLASS specifies an object reference to a class defined as either a class or interface type. Like user-defined function return types, the return-type can also include the EXTENT option to define a one-dimensional array of a listed type. Unlike a user-defined function, a method can return VOID, which means the method does not return a value. (In ABL, you can ignore the data type of a user-defined function simply by invoking it as a statement.)
To set the return value for a method, you must use the RETURN statement with a value of the same data type as return-type. There is no implicit type conversion.
method-name
The name of the method. The method name must be unique among all non-overloaded methods within the class and cannot be the same as the class name. This method-name must also be unique among all non-overloaded methods within the class hierarchy according to its particular class member namespace. For more information, see Namespaces for naming class members.
If the method-name is the same as the name of a non-private method in a super class that also has the same signature, the method definition must also include the OVERRIDE option to override the method in the super class. If the method-name is the same as the name of any other non-private method in the class hierarchy or any other private method in the same class definition, and the other method has a different signature, the current method definition must not include the OVERRIDE option, as it overloads the other method with its different signature.
Methods defined within a class can be named the same as an ABL reserved keyword. In all contexts, a method whose name is a reserved keyword must be qualified when referenced, either by an object reference (which can be THIS-OBJECT) or if it is static, with a static type name. For more information on calling methods, see Calling class-based methods. For more information on using static type-name syntax to call static methods, see Accessing static members.
( [parameter[ , parameter]...] ) { : | . }
Any parameters that you define for the method. If this method overloads another method definition of the same name, ABL must be able to disambiguate the two methods by the number, data types, or modes of their parameter definitions (their signatures). For more information on the syntax of parameter and how to define overloaded method signatures, see the Parameter definition syntax reference entry in OpenEdge Development: ABL Reference.
You can terminate the METHOD statement with a colon (:) or period (.). You typically use a colon to introduce the method-body of an implemented method and use a period to terminate the definition of an abstract or interface method prototype.
[ method-body END [ METHOD ] . ]
The logic of an implemented method, which can be composed of any ABL statements currently allowed within an internal procedure, plus the syntax that is restricted to classes and their methods. An implemented method must include a method-body, followed by an END statement, even if it contains no statements (is empty). An abstract or interface method prototype cannot specify a method-body at all.
One statement specifically for use in the method-body of an instance is a call to an instance method defined in a super class using the SUPER system reference. Also, in the method-body of a static method, you can only access other static members defined within the current class hierarchy in addition to local method data; instance members defined within the current class hierarchy are inaccessible. However, if the method is defined as an instance member, method-body statements can access static members as well as other instance members.
If the method has a non-VOID return type, like a user-defined function, you must return the value for any defined return type using the RETURN statement.
Like a procedure or user-defined function, you can raise ERROR on the statement that invokes the method using an UNDO, THROW available in several ABL constructs to throw an error object that can be caught and accessed in the method or in its caller. Also like a procedure, but unlike a user-defined function, you can use a RETURN ERROR available in several ABL constructs to return ERROR to the caller. This RETURN ERROR can also include a string value for setting the RETURN-VALUE function in the caller or specify an error object that can be caught and accessed in the caller.
You cannot use any statements or ABL elements in the method-body that are only relevant in procedures, such as a reference to the THIS-PROCEDURE system handle.
Adding a method to the acme.myObjs.CustObj sample class definition results in this code:
USING acme.myObjs.*.
USING acme.myObjs.Common.*.

CLASS acme.myObjs.CustObj INHERITS CommonObj:

  DEFINE PUBLIC VARIABLE iNumCusts AS INTEGER NO-UNDO.

  DEFINE PROTECTED TEMP-TABLE ttCustomer NO-UNDO
    FIELD RecNum  AS INTEGER
    FIELD CustNum LIKE Customer.CustNum
    FIELD Name    LIKE Customer.Name
    FIELD State   AS CHARACTER.

  DEFINE PRIVATE VARIABLE rCreditObj AS CLASS CreditObj NO-UNDO.
  DEFINE PRIVATE VARIABLE rMsg       AS CLASS MsgObj    NO-UNDO.

  METHOD PUBLIC CHARACTER GetCustomerName (INPUT piRecNum AS INTEGER):
    FIND ttCustomer WHERE ttCustomer.RecNum = piRecNum NO-ERROR.
    IF AVAILABLE ttCustomer THEN
      RETURN ttCustomer.Name.
    ELSE DO:
      rMsg:Alert("Customer number" + STRING(ttCustomer.RecNum) +
"does not exist").
      RETURN ?.
    END.
  END METHOD.
END CLASS.
Adding an abstract method to the super class, acme.myObjs.Common.CommonObj, results in this code:
USING acme.myObjs.Common.*.

CLASS acme.myObjs.Common.CommonObj ABSTRACT:

  METHOD PROTECTED ABSTRACT CLASS MsgObj MessageHandler
    (INPUT iObjType AS CHARACTER).

END CLASS.
Implementing the abstract MessageHandler( ) method in the CustObj class results in this code:
USING acme.myObjs.*.
USING acme.myObjs.Common.*.

CLASS acme.myObjs.CustObj INHERITS CommonObj:

  DEFINE PUBLIC VARIABLE iNumCusts AS INTEGER NO-UNDO.

  DEFINE PROTECTED TEMP-TABLE ttCustomer NO-UNDO
    FIELD RecNum  AS INTEGER
    FIELD CustNum LIKE Customer.CustNum
    FIELD Name    LIKE Customer.Name
    FIELD State   AS CHARACTER.

  DEFINE PRIVATE VARIABLE rCreditObj AS CLASS CreditObj NO-UNDO.
  DEFINE PRIVATE VARIABLE rMsg       AS CLASS MsgObj    NO-UNDO.

  METHOD PUBLIC CHARACTER GetCustomerName (INPUT piRecNum AS INTEGER):
    FIND ttCustomer WHERE ttCustomer.RecNum = piRecNum NO-ERROR.
    IF AVAILABLE ttCustomer THEN
      RETURN ttCustomer.Name.
    ELSE DO:
      rMsg:Alert("Customer number" + STRING(ttCustomer.RecNum) +
                 "does not exist").
      RETURN ?.
    END.
  END METHOD.

  METHOD PROTECTED OVERRIDE CLASS MsgObj MessageHandler
     (INPUT iObjType AS CHARACTER):
     RETURN NEW MsgObj (iObjType).
  END METHOD.

END CLASS.