Defining and Calling Methods

Objectives

After completing this lesson, you will be able to:

  • Define and call methods

Method Definition

In the definition part of a class you use METHODS to define an instance method and CLASS-METHODS to define a static method. The name of the method is followed by the method's signature; that is, the set of values that the method exchanges with its caller and the exceptions that may arise during the method.

The signature of a method consists of parameters and exceptions. Each parameter has a name and a type.

ABAP knows the following kinds of parameters:

Importing Parameters

Importing parameters are values that the method receives from the caller. A method can have any number of importing parameters.

By default, importing parameters are mandatory, but there are two ways to make them optional:

  • Using the OPTIONAL addition. The parameter is optional and its default value is the initial value appropriate to the type of the parameter
  • Using the DEFAULT <val> addition. The parameter is optional and its default value is the value that you specified as <val>.

Inside of a method, you may not change importing parameters. If you attempt to do so, you will cause a syntax error.

Exporting Parameters

Exporting parameters are results that are returned by the method. A method can have any number of exporting parameters. All exporting parameters are optional - a calling program only uses the values that it actually needs.

Changing Parameters

Changing parameters are values that the method receives from the caller. Unlike importing parameters, the method can change the values of these parameters. They are then returned to the caller under the same name. A method can have any number of changing parameters. Changing parameters are mandatory by default; you can make them optional in the same way as importing parameters.

Returning Parameters

A returning parameter is a method result that can be used directly in an expression. A method can only have one returning parameter. Returning parameters have to use a special form of parameter passing which is called pass-by-value. This form of parameter passing is defined by surrounding the parameter name in brackets (no blanks!) and preceding it with keyword VALUE.

Keyword RAISING is used to list the exceptions the method might raise to indicate an error situation. The calling program can then react to the error.

As an example, add two methods to our class lcl_connection.

A set_attributes( ) method to set the values for attribute i_carrier_id and i_connection_id and a get_attributes( ) method to return the values of these attributes. Where set_attributes( ) needs two importing parameters, one for each of attribute, the get_attributes( ) method needs two exporting parameters.

For every method that you define, you must also create an implementation in the implementation part of the class. Until you do so, you see syntax errors in your class; the syntax check tells you that the implementation of the method is missing.

Hint
ADT offers a quickfix to add the missing implementation. To use this quick fix, proceed as follows:
  1. Position the cursor in a METHODS statement with an error and press Ctrl + 1.
  2. From the list of possible quick fixes choose Add implementation for … and press Enter . If the implementation is missing for several methods, the quickfix title reads Add … unimplemented methods.

How to Define Methods

Method Implementation

You must implement every method that you define. You do this in the implementation part of the class, by adding a pair of statements METHOD <method_name> and ENDMETHOD.

The method implementation contains ABAP statements that can access the parameters of the method (you are not allowed to change importing parameters) and all types, attributes, and constants that you declared in the class, independent from their visibility. Instance methods may access both instance attributes and static attributes. Static methods may only access static components.

Inside the implementation part of a class, you can access the attributes of that class without a reference variable and '->' (or the class name and '=>' , in case of static attributes).

Only in the implementation of instance methods, ABAP offers built-in variable ME. ME is a reference variable, typed with the current class and filled at runtime with the address of the current instance. The use of ME is optional and should be avoided, unless the name of an attribute collides with the name of another data object, for example a parameter name.

In the example, the import parameters of method set_attributes( ) have the same names as the corresponding attributes. In such a situation, the name by itself denotes the parameter. Only by putting me-> in front it becomes clear that an attribute of the current instance is to be accessed.

If an error occurs during the execution of a method, the method can trigger an exception using statement RAISE EXCEPTION TYPE, followed by the name of the exception.

Note
Technically, exception names are the names of special ABAP classes and statement RAISE EXCEPTION TYPE creates an instance of the referenced class. The instance is referred to as exception object and the special kind of ABAP classes are called exception classes.

The moment an exception is raised, the method execution is terminated.

Control is returned to the calling program if all prerequisites are met. Otherwise the entire program terminates with a runtime error.

The prerequisites for continuing the program are as follows:

  • The raised exception is declared in the RAISING clause of the method signature
  • The method call is surrounded by a TRY … ENDTRY control structure
  • The TRY … ENDTRY control structure contains a CATCH block for the exception
Note
For some exceptions, the ABAP editor displays a syntax warning with a quick fix when you raise an exception that is not yet declared in the RAISING clause of the method.

How to Implement Methods

Method Calls

You call an instance method using a reference variable and the instance component selector (->). The component selector is followed by the name of the method you want to call. For static methods you use the class name and the static component selector (=>). On both cases, the parameter passing takes place in a pair of brackets. The brackets are needed in any case. They remain empty if no parameters are to be passed.

Note
No blank is allowed between the method name and the opening bracket. On the other hand you need at least one blank after the opening bracket and before the closing bracket.

Importing parameters are listed after keyword EXPORTING because the values that are imported by the called method are exported by the calling program. The parameter names are listed on the left-hand side of an equals sign (=) and an expression on the right-hand side.. This expression can be as simple as a literal, constant, or variable but any other expressions are also allowed as long as the type of the expression matches the type of the parameter.

Exporting parameters are listed after keyword IMPORTING. Note, that for exporting parameter the parameter name is also listed on the left-hand side of the equals sign. The variable on the right-hand side has to have the same type as the parameter.

Changing parameters are listed after keyword CHANGING. The type of the variable on the right-hand side has to match the type of the parameter on the left hand side.

The example illustrates the call of instance methods set_attributes( ) and get_attributes( ). The parameter names are always on the left-hand side of the equals sign (=).

Hint

You can use code completion in ADT to generate the method call including the parameter passing. To do so, proceed as follows:

  1. Type in the reference variable (or class name) and the component selector.
  2. Once you typed the component selector press Ctrl + Space to display a list of components you can address.
  3. If you choose a method, and press Shift + Enter to insert the name of the method and its full signature into your code. Optional parameters are listed in comment lines.

When calling a method, keyword IMPORTING is always needed to receive the value of exporting parameters. But keyword EXPORTING becomes optional, if you only want to supply importing parameters.

For methods with only one mandatory importing parameter, you can even omit the explicit parameter assignment. In the example, parameter i_carrier_id is optional with default value 'LH'. Therefore the value between the brackets is assigned to the remaining mandatory importing parameter i_connection_id.

How to Call Methods

Exception Raising

In a previous section of this class, you learned how to handle runtime errors with TRY … ENDTRY control structures.

Exceptions declared in the RAISING clause of a method definition are handled in exactly the same way:

  • Place the method call in the TRY-block of the TRY … ENDTRY control structure.
  • Define a CATCH block with the name of the exception you want to handle.
Note
If there is code that you want to skip in case the method call failed, you can place this code inside the try block, after the method call.

Try It Out: Method Calls and Exception Handling

  1. Like in the first exercise of this course, create a new global class that implements interface IF_OO_ADT_CLASSRUN.
  2. Copy the following code snippet to the implementation part of method if_oo_adt_classrun~main( ):
    Code snippet
    
        CONSTANTS c_carrier_id TYPE /dmo/carrier_id       VALUE 'LH'.
        CONSTANTS c_connection_id TYPE /dmo/connection_id VALUE '0400'.
    
        DATA connection  TYPE REF TO lcl_connection.
        DATA connections  TYPE TABLE OF REF TO lcl_connection.
    
    * Create Instance
    **********************************************************************
    
        connection = NEW #(  ).
    
    * Call Method and Handle Exception
    **********************************************************************
        out->write(  |i_carrier_id    = '{ c_carrier_id }' | ).
        out->write(  |i_connection_id = '{ c_connection_id }'| ).
    
        TRY.
            connection->set_attributes(
              EXPORTING
                i_carrier_id    = c_carrier_id
                i_connection_id = c_connection_id
            ).
    
            APPEND connection TO connections.
            out->write( `Method call successful` ).
          CATCH cx_abap_invalid_value.
            out->write( `Method call failed`     ).
        ENDTRY.  
    
    Expand
  3. Navigate to tab Local Typesand insert the following code snippet there:
    Code snippet
    
    CLASS lcl_connection DEFINITION.
      PUBLIC SECTION.
    
    * Attributes
        DATA carrier_id    TYPE /dmo/carrier_id.
        DATA connection_id TYPE /dmo/connection_id.
    
    * Methods
        METHODS set_attributes
          IMPORTING
            i_carrier_id    TYPE /dmo/carrier_id  DEFAULT 'LH'
            i_Connection_id TYPE /dmo/connection_id
          RAISING
            cx_abap_invalid_value.
    
    
    ENDCLASS.
    
    CLASS lcl_connection IMPLEMENTATION.
    
      METHOD set_attributes.
    
        IF i_carrier_id IS INITIAL OR i_connection_id IS INITIAL.
          RAISE EXCEPTION TYPE cx_abap_invalid_value.
        ENDIF.
    
        carrier_id    = i_carrier_id.
        connection_id = i_connection_id.
    
      ENDMETHOD.
    
    ENDCLASS.
    
    Expand
  4. Press CTRL + F3 to activate the class and F9 to execute it as a console app.
  5. Analyze the console output. Debug the program, play around with the source code to get familiar with the concepts. In particular, change the values of the two constants to debug the raising of the exception.

Functional Methods

Methods that have a returning parameter are called functional methods. It is not possible to define more than one returning parameter for the same method. It is mandatory that you define the returning parameter in the form VALUE(<parameter_name>). Besides the returning parameter a functional method can have any combination of other parameters. It is most common however, to add importing parameters only. The reason is, that with additional exporting or changing parameters you loose the biggest advantage of functional methods, namely, that you can use the result of a functional method directly in other ABAP expressions.

The figure shows two examples of how you can use functional methods in expressions; the first is a simple example in which the returning parameter is assigned directly to a variable. The second example shows how the call of the functional method is used as input for another method. The system executes the functional method, and then uses the value of the returning parameter as input for method write( ).

Try It Out: Functional Methods

  1. Like in the first exercise of this course, create a new global class that implements interface IF_OO_ADT_CLASSRUN.
  2. Copy the following code snippet to the implementation part of method if_oo_adt_classrun~main( ):
    Code snippet
    
       DATA connection  TYPE REF TO lcl_connection.
       DATA connections  TYPE TABLE OF REF TO lcl_connection.
    
    * Create Instance
    **********************************************************************
    
        connection = NEW #(  ).
    
        connection->set_attributes(
          EXPORTING
            i_carrier_id    = 'LH'
            i_connection_id = '0400'
        ).
    
        APPEND connection TO connections.
    
    * Calling Functional Method
    **********************************************************************
        " in a value assignment (with inline declaration for result)
        DATA(result) = connection->get_output( ).
    
        " in logical expression
        IF connection->get_output(  ) IS NOT INITIAL.
    
          " as operand in a statement
          LOOP AT connection->get_output(  ) INTO DATA(line).
    
          ENDLOOP.
    
          "  to supply input parameter of another method
          out->write( data = connection->get_output( )
                      name = `  ` ).
    
        ENDIF.
    
    Expand
  3. Navigate to tab Local Typesand insert the following code snippet there:
    Code snippet
    
    CLASS lcl_connection DEFINITION.
      PUBLIC SECTION.
    
    * Attributes
        DATA carrier_id    TYPE /dmo/carrier_id.
        DATA connection_id TYPE /dmo/connection_id.
    
    * Methods
        METHODS set_attributes
          IMPORTING
            i_carrier_id    TYPE /dmo/carrier_id  DEFAULT 'LH'
            i_Connection_id TYPE /dmo/connection_id.
    
        " Functional Method
        METHODS get_output
          RETURNING VALUE(r_output) TYPE string_table.
    
    *  PROTECTED SECTION.
    
    *  PRIVATE SECTION.
    
    ENDCLASS.
    
    CLASS lcl_connection IMPLEMENTATION.
    
      METHOD set_attributes.
    
        carrier_id    = i_carrier_id.
        connection_id = i_connection_id.
    
      ENDMETHOD.
    
      METHOD get_output.
    
        APPEND |------------------------------| TO r_output.
        APPEND |Carrier:     { carrier_id    }| TO r_output.
        APPEND |Connection:  { connection_id }| TO r_output.
    
      ENDMETHOD.
    
    ENDCLASS.
    
    Expand
  4. Press CTRL + F3 to activate the class and F9 to execute it as a console app.
  5. Analyze the console output. Debug the program, play around with the source code to get familiar with the concepts. In particular, debug the different calls of functional method get_output( )..

Define and Call Methods

In this exercise, you create and manage instances of your local class.

Template:

  • /LRN/CL_S4D400_CLS_INSTANCES (global Class)

Solution:

  • /LRN/CL_S4D400_CLS_METHODS (global Class)

Task 1: Copy Template (Optional)

Copy the template class. If you finished the previous exercise, you can skip this task and continue editing your class ZCL_##_LOCAL_CLASS or your class ZCL_##_INSTANCES.

Steps

  1. Open the source code of global class/LRN/CL_S4D400_CLS_INSTANCES in the ABAP editor.

    1. In the Eclipse toolbar, choose Open ABAP Development Object. Alternatively, press Ctrl + Shift + A.

    2. Enter /LRN/CL_S4D400_CLS as search string.

    3. From the list of development objects choose /LRN/CL_S4D400_CLS_INSTANCES, then choose OK.

  2. Link the Project Explorer view with the editor.

    1. In the Project Explorer toolbar, find the Link with Editor button. If it is not yet pressed, choose it. As a result, the development object, that is open in the editor, should be highlighted in the Project Explorer.

  3. Copy class /LRN/CL_S4D400_CLS_INSTANCES to a class in your own package (suggested name: ZCL_##_METHODS, where ## stands for your group number).

    1. In the Project Explorer view, right-click class /LRN/CL_S4D400_CLS_INSTANCES to open the content menu.

    2. From the context menu, choose Duplicate ....

    3. Enter the name of your package in the Package field. In the Name field, enter the name ZCL_##_METHODS, where ## stands for your group number.

    4. Adjust the description and choose Next.

    5. Confirm the transport request and choose Finish.

Task 2: Define Methods

In your local class lcl_connection, define instance methods get_output and set_attributes.

Steps

  1. Navigate to the definition of the local class lcl_connection.

    1. In the global class, choose Local Types.

  2. Add a method get_output to the public section of the class. It should have one returning parameter r_outputof global table typeSTRING_TABLE.

    Note
    Remember to surround the name of the returning parameter with VALUE( ).
    1. Add the highlighted code:

      Code snippet
      
       PUBLIC SECTION.
      
          DATA carrier_id    TYPE /dmo/carrier_id.
          DATA connection_id TYPE /DMO/Connection_id.
      
          CLASS-DATA conn_counter TYPE i.
      
        PROTECTED SECTION.
      
      Expand
      Note
      For the moment, ignore the syntax error Implementation missing for method "GET_OUTPUT".
  3. Add a method set_attributes to the public section of the class. It should have one importing parameter for each instance attribute of the class. Use the same types for the parameters that you used to type the attributes. To distinguish the parameters from the attributes, add prefix i_ to the parameter names. In addition, the method should raise exception CX_ABAP_INVALID_VALUE.

    1. Add the highlighted code:

      Code snippet
      
      PUBLIC SECTION.
      
          DATA carrier_id    TYPE /dmo/carrier_id.
          DATA connection_id TYPE /DMO/Connection_id.
      
          CLASS-DATA conn_counter TYPE i.
      
          METHODS get_output
            returning
              value(r_output) type string_table.
      
        PROTECTED SECTION.
      
      Expand
      Note
      For the moment, ignore the syntax error Implementation missing for method "SET_ATTRIBUTES".

Task 3: Implement Methods

Steps

  1. Use a quick fix to add the method implementations to the class.

    1. Position the cursor on the name of one of the methods in the editor and press Ctrl + 1.

    2. Double-click the suggestion Add 2 unimplemented methods.

  2. Implement the method get_output. Append some string templates to returning parameter r_output. In the string templates, use embedded expressions to add the values of attributes carrier_id and connection_id.

    1. In the local class add the following code between the statements METHOD get_output. and ENDMETHOD.

      Code snippet
      
        METHOD get_output.
      
        ENDMETHOD.
      
      Expand
  3. Implement the method set_attributes. If either of the two importing parameters is empty (IS INITIAL), raise exception CX_ABAP_INVALID_VALUE. Otherwise, fill the two instance attributes with the values of the importing parameters.

    1. Add the highlighted code:

      Code snippet
      
      METHOD set_attributes.
      
      ENDMETHOD. 
      
      Expand
  4. Activate your class.

    1. Choose Ctrl + F3 to activate the class.

Task 4: Call a Functional Method

In the main method of your global class, call the functional method get_output.

Steps

  1. Switch to the implementation of method if_oo_adt_classrun~main in the global class.

    1. In the global class, choose Global Class scroll down to the implementation of method if_oo_adt_classrun~main.

  2. At the end of the method, add a loop over the internal table connections with reference variable connection as a work area.

    1. Add the following code before ENDMETHOD..

      Code snippet
      
         LOOP AT connections INTO connection.
      
         ENDLOOP.
      
      Expand
  3. In the loop, call functional method get_output for each instance in turn and write the result to the console.

    Hint
    You can use the call of method get_output directly as input for out->write( ).
    1. Add the highlighted code:

      Code snippet
      
        LOOP AT connections INTO connection.
      
         ENDLOOP.
      
      Expand
  4. Activate the class. Execute it as a console app and analyze the console output.

    1. Press Ctrl + F3 to activate the class.

    2. Press F9 to run the class.

    3. Analyze the output on the Console window.

Task 5: Use Code Completion and Handle Exceptions

Use code completion to call the method set_attributes and handle the exception the method raises.

Steps

  1. For the first instance of class lcl_connection, replace the direct access to attributes carrier_id and connection_id with a call of the instance method set_attributes( ). Use code completion to insert the full signature of the method.

    Hint
    Press Ctrl + Space after you typed the component select (->) to display a list of available attributes and methods. Choose the method and then press Shift + Enter to insert the full signature of the method.
    1. Place the cursor in the next line after the first connection = NEW #( )..

    2. Type connection-> and press Ctrl + Space.

    3. Choose set_attributes and press Shift + Enter.

    4. Pass values to the importing parameters. Use the same literals that you used previously to set the attributes of this instance.

    5. Remove or comment the direct access to the instance attributes for this instance.

  2. Handle the exception. Surround the method call with TRY. and ENDTRY.. Add a CATCH-Block to handle exception CX_ABAP_INVALID_VALUE. Make sure the new instance is only added to internal table connections if the method call was successful.

    1. Uncomment the generated code line CATCH cx_abap_invalid_value. .

    2. Add TRY. before the method call .

    3. Add ENDTRY. after the CATCH statement.

    4. Between the CATCH statement and the ENDTRY statement add out->write( `Method call failed` ).

    5. Move the APPEND statement up to between the method call and CATCH statement.

    6. The complete method call should now look like this:

      Code snippet
      
          TRY.
              connection->set_attributes(
                EXPORTING
                  i_carrier_id    = 'LH'
                  i_connection_id = '0400'
              ).
      
      *       connection->carrier_id    = 'LH'.
      *       connection->connection_id = '0400'. 
      
              APPEND connection TO connections.
      
            CATCH cx_abap_invalid_value.
              out->write( `Method call failed` ).
          ENDTRY.
      
      Expand
  3. Repeat the previous step for the other two instances of class lcl_connection.

    1. After this step, the implementation of method if_oo_adt_classrun~main should look similar to this:

      Code snippet
      
      METHOD if_oo_adt_classrun~main.
      
          DATA connection TYPE REF TO lcl_connection.
          DATA connections TYPE TABLE OF REF TO lcl_connection.
      
      * First Instance
      **********************************************************************
          connection = NEW #(  ).
      
          TRY.
              connection->set_attributes(
                EXPORTING
                  i_carrier_id    = 'LH'
                  i_connection_id = '0400'
              ).
      
      *        connection->carrier_id    = 'LH'.
      *        connection->connection_id = '0400'.
      
              APPEND connection TO connections.
      
            CATCH cx_abap_invalid_value.
              out->write( `Method call failed` ).
          ENDTRY.
      
      * Second instance
      **********************************************************************
      
          connection = NEW #(  ).
      
          TRY.
              connection->set_attributes(
                EXPORTING
                  i_carrier_id    = 'AA'
                  i_connection_id = '0017'
              ).
      
      *        connection->carrier_id    = 'AA'.
      *        connection->connection_id = '0017'.
      
              APPEND connection TO connections.
      
            CATCH cx_abap_invalid_value.
              out->write( `Method call failed` ).
          ENDTRY.
      
      * Third instance
      **********************************************************************
          connection = NEW #(  ).
      
          TRY.
              connection->set_attributes(
                EXPORTING
                  i_carrier_id    = 'SQ'
                  i_connection_id = '0001'
              ).
      
      *        connection->carrier_id    = 'SQ'.
      *        connection->connection_id = '0001'.
      
              APPEND connection TO connections.
      
            CATCH cx_abap_invalid_value.
              out->write( `Method call failed` ).
          ENDTRY.
      
      
      * Output
      **********************************************************************
      
          LOOP AT connections INTO connection.
      
            out->write( connection->get_output( ) ).
      
          ENDLOOP.
      
        ENDMETHOD.
      
      Expand
  4. Activate the class. Execute it and debug the method calls.

    1. Press Ctrl + F3 to activate the class.

    2. Press F9 to run the class.

Log in to track your progress & complete quizzes