diff --git a/04_ABAP_Object_Orientation.md b/04_ABAP_Object_Orientation.md index 51bdba1..12f7500 100644 --- a/04_ABAP_Object_Orientation.md +++ b/04_ABAP_Object_Orientation.md @@ -20,7 +20,6 @@ - [Defining Parameters as Optional](#defining-parameters-as-optional) - [Defining Input Parameters as Preferred](#defining-input-parameters-as-preferred) - [Constructors](#constructors) - - [Example for Method Definitions](#example-for-method-definitions) - [Working with Objects and Components](#working-with-objects-and-components) - [Declaring Object Reference Variables](#declaring-object-reference-variables) - [Creating Objects](#creating-objects) @@ -47,6 +46,7 @@ - [Events](#events) - [Examples for Design Patterns: Factory Methods and Singletons](#examples-for-design-patterns-factory-methods-and-singletons) - [Class-Based Exceptions](#class-based-exceptions) + - [ABAP Doc Comments](#abap-doc-comments) - [More Information](#more-information) - [Executable Example](#executable-example) @@ -525,6 +525,78 @@ ENDCLASS. section. Note that you must create an instance of a class first before using instance methods. - `CLASS-METHODS` and `METHODS` can be followed by a colon to list one or more methods, separated by commas, or without a colon to declare a single method. + +The following code snippet shows (which anticipates aspects described in the following sections, such as specifying the method signature, constructors etc.) multiple method definitions in the public section of a global class. Most of the formal +parameters of the demo methods below are defined by just using the +parameter name. This means passing by reference (returning parameters +require to be passed by value). +``` abap +CLASS zcl_some_class DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + METHODS: inst_meth1, "instance methods + + inst_meth2 IMPORTING a TYPE string, + + inst_meth3 IMPORTING b TYPE i + EXPORTING c TYPE i, + + inst_meth4 IMPORTING d TYPE string + RETURNING VALUE(e) TYPE string, + + "Note that method declarations should be done with care. An example + "as follows may not be advisable, e.g. specifying multiple output + "parameters (both exporting and returning parameters for a method). + "As is valid for all examples in the cheat sheet, the focus is on + "syntax options. + inst_meth5 IMPORTING f TYPE i + EXPORTING g TYPE i + CHANGING h TYPE string + RETURNING VALUE(i) TYPE i + RAISING cx_sy_zerodivide, + + constructor IMPORTING j TYPE i. "instance constructor with importing parameter + + CLASS-METHODS: stat_meth1, "static methods + + stat_meth2 IMPORTING k TYPE i + EXPORTING l TYPE i, + + class_constructor, "static constructor + + "Options of formal parameter definitions + stat_meth3 IMPORTING VALUE(m) TYPE i, "pass by value + stat_meth4 IMPORTING REFERENCE(n) TYPE i, "pass by reference + stat_meth5 IMPORTING o TYPE i, "same as n; the specification of REFERENCE(...) is optional + stat_meth6 RETURNING VALUE(p) TYPE i, "pass by value once more (note: it's the only option for returning parameters) + + "OPTIONAL/DEFAULT additions + stat_meth7 IMPORTING q TYPE i DEFAULT 123 + r TYPE i OPTIONAL, + + "The examples above use a complete type for + "the parameter specification. Generic types + "are possible. + stat_meth8 IMPORTING s TYPE any "Any data type + t TYPE any table "Any internal table type + u TYPE clike. "Character-like types (c, n, string, d, t and character-like flat structures) + +ENDCLASS. + +CLASS zcl_some_class IMPLEMENTATION. + METHOD inst_meth1. + ... + ENDMETHOD. + + ... "Further method implementations. Note that all declared methods must go here. +ENDCLASS. +``` + + +

⬆️ back to top

#### Parameter Interface @@ -955,6 +1027,100 @@ ENDCLASS. - [`DEFAULT`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapmethods_parameters.htm#!ABAP_ONE_ADD@1@): Also makes the passing of an actual parameter optional. However, when using this addition, as the name implies, a default value is set. - In the method implementations you may want to check whether an actual parameter was passed. You can use predicate expressions using `IS SUPPLIED`. See the example further down. + +The following example (which anticipates aspects described in the following sections, such as calling methods) includes three methods that specify optional parameters. The methods are called with and without providing actual parameters. The method implementations include the use of the predicate expression `IS SUPPLIED` with `IF` statements and the `COND` operator. The console output of the example, run with F9, is as follows: + +``` +meth1_result_a +The parameter is not supplied. Initial value: "0". +meth1_result_b +The parameter is supplied. Value: "2". +meth2_result_a +The parameter is not supplied. Default value: "1". +meth2_result_b +The parameter is supplied. Value: "3". +meth3_result_b +num1: "4" / num2 (is not supplied; initial value): "0" / num3 (is not supplied; default value): "1" +meth3_result_c +num1: "5" / num2 (is supplied): "6" / num3 (is not supplied; default value): "1" +meth3_result_d +num1: "7" / num2 (is not supplied; initial value): "0" / num3 (is supplied): "8" +``` + +```abap +CLASS zcl_some_class DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. + METHODS meth1 IMPORTING num TYPE i OPTIONAL + RETURNING VALUE(str) TYPE string. + METHODS meth2 IMPORTING num TYPE i DEFAULT 1 + RETURNING VALUE(str) TYPE string. + METHODS meth3 IMPORTING num1 TYPE i + num2 TYPE i OPTIONAL + num3 TYPE i DEFAULT 1 + RETURNING VALUE(str) TYPE string. + + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. + +CLASS zcl_some_class IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + + DATA(meth1_result_a) = meth1( ). + DATA(meth1_result_b) = meth1( 2 ). + + DATA(meth2_result_a) = meth2( ). + DATA(meth2_result_b) = meth2( 3 ). + + "The commented out statement is not possible as there is one + "non-optional parameter. + "DATA(meth3_result_a) = meth3( ). + DATA(meth3_result_b) = meth3( 4 ). + DATA(meth3_result_c) = meth3( num1 = 5 num2 = 6 ). + DATA(meth3_result_d) = meth3( num1 = 7 num3 = 8 ). + + out->write( data = meth1_result_a name = `meth1_result_a` ). + out->write( data = meth1_result_b name = `meth1_result_b` ). + out->write( data = meth2_result_a name = `meth2_result_a` ). + out->write( data = meth2_result_b name = `meth2_result_b` ). + out->write( data = meth3_result_b name = `meth3_result_b` ). + out->write( data = meth3_result_c name = `meth3_result_c` ). + out->write( data = meth3_result_d name = `meth3_result_d` ). + + ENDMETHOD. + + METHOD meth1. + IF num IS SUPPLIED. + str = |The parameter is supplied. Value: "{ num }".|. + ELSE. + str = |The parameter is not supplied. Initial value: "{ num }".|. + ENDIF. + ENDMETHOD. + + METHOD meth2. + str = COND #( WHEN num IS SUPPLIED THEN |The parameter is supplied. Value: "{ num }".| + ELSE |The parameter is not supplied. Default value: "{ num }".| ). + ENDMETHOD. + + METHOD meth3. + str = |num1: "{ num1 }" / |. + + str &&= |{ COND #( WHEN num2 IS SUPPLIED THEN |num2 (is supplied): "{ num2 }"| + ELSE |num2 (is not supplied; initial value): "{ num2 }"| ) } / |. + + str &&= |{ COND #( WHEN num3 IS SUPPLIED THEN |num3 (is supplied): "{ num3 }"| + ELSE |num3 (is not supplied; default value): "{ num3 }"| ) } |. + ENDMETHOD. + +ENDCLASS. +``` + +

⬆️ back to top

#### Defining Input Parameters as Preferred @@ -1142,75 +1308,6 @@ ENDCLASS. ``` -

⬆️ back to top

- -#### Example for Method Definitions - -The following snippet shows -multiple method definitions in the public section of a global class. Most of the formal -parameters of the demo methods below are defined by just using the -parameter name. This means passing by reference (returning parameters -require to be passed by value). -``` abap -CLASS zcl_some_class DEFINITION - PUBLIC - FINAL - CREATE PUBLIC. - - PUBLIC SECTION. - METHODS: inst_meth1, "instance methods - - inst_meth2 IMPORTING a TYPE string, - - inst_meth3 IMPORTING b TYPE i - EXPORTING c TYPE i, - - inst_meth4 IMPORTING d TYPE string - RETURNING VALUE(e) TYPE string, - - inst_meth5 IMPORTING f TYPE i - EXPORTING g TYPE i - CHANGING h TYPE string - RETURNING VALUE(i) TYPE i - RAISING cx_sy_zerodivide, - - constructor IMPORTING j TYPE i. "instance constructor with importing parameter - - CLASS-METHODS: stat_meth1, "static methods - - stat_meth2 IMPORTING k TYPE i - EXPORTING l TYPE i, - - class_constructor, "static constructor - - "Options of formal parameter definitions - stat_meth3 IMPORTING VALUE(m) TYPE i, "pass by value - stat_meth4 IMPORTING REFERENCE(n) TYPE i, "pass by reference - stat_meth5 IMPORTING o TYPE i, "same as n; the specification of REFERENCE(...) is optional - stat_meth6 RETURNING VALUE(p) TYPE i, "pass by value once more (note: it's the only option for returning parameters) - - "OPTIONAL/DEFAULT additions - stat_meth7 IMPORTING q TYPE i DEFAULT 123 - r TYPE i OPTIONAL, - - "The examples above use a complete type for - "the parameter specification. Generic types - "are possible. - stat_meth8 IMPORTING s TYPE any "Any data type - t TYPE any table "Any internal table type - u TYPE clike. "Character-like types (c, n, string, d, t and character-like flat structures) - -ENDCLASS. - -CLASS zcl_some_class IMPLEMENTATION. - METHOD inst_meth1. - ... - ENDMETHOD. - - ... "Further method implementations. Note that all declared methods must go here. -ENDCLASS. -``` -

⬆️ back to top

## Working with Objects and Components @@ -1267,15 +1364,17 @@ DATA(ref2) = NEW some_class( ). "Reference variable declared inline, explic "instance constructor. If a class has, actual parameters must be provided. DATA(ref_mand_param) = NEW another_class( ip1 = ... ip2 = ... ). -"Older syntax -"CREATE OBJECT ref3. "Type derived from already declared ref3 -"CREATE OBJECT ref4 TYPE some_class. "Corresponds to the result of the expression above +"Older syntax, replaced by NEW operator +"However, the CREATE OBJECT is required in dynamic object creation. +CREATE OBJECT ref3. "Type derived from already declared ref3 +CREATE OBJECT ref4 TYPE some_class. "Corresponds to the result of the expression above ```

⬆️ back to top

### Working with Reference Variables -Some examples for working with reference variables: + +This section covers some aspects of working with reference variables. **Assigning Reference Variables** @@ -1716,6 +1815,7 @@ CLASS zcl_some_class DEFINITION RETURNING VALUE(ref) TYPE REF TO zcl_some_class. METHODS add_space RETURNING VALUE(ref) TYPE REF TO zcl_some_class. METHODS add_period RETURNING VALUE(ref) TYPE REF TO zcl_some_class. + METHODS return_text RETURNING VALUE(str) TYPE string. METHODS display_text IMPORTING cl_run_ref TYPE REF TO if_oo_adt_classrun_out. DATA text TYPE string. PROTECTED SECTION. @@ -1727,13 +1827,10 @@ CLASS zcl_some_class IMPLEMENTATION. "---------------------------------------------------------------- "-------- Method chaining with a functional method call --------- - "---------------------------------------------------------------- - "This example chained method call includes a chained attribute access - "at the end so that the target variable contains the content of the - "attribute. - + "---------------------------------------------------------------- + "Hallo NAME. This is an example of method chaining. - DATA(some_text) = NEW zcl_some_class( + DATA(text1) = NEW zcl_some_class( )->add_text( `Hallo` )->add_space( )->add_text( xco_cp=>sy->user( )->name @@ -1753,16 +1850,50 @@ CLASS zcl_some_class IMPLEMENTATION. )->add_space( )->add_text( `chaining` )->add_period( + )->return_text( ). + + out->write( text1 ). + + "The following example chained method call includes a chained attribute + "access at the end so that the target variable contains the content of + "the attribute. + + "Example result: Today is 2025-03-05. It's 14:30:38. Have a nice day. + DATA(text2) = NEW zcl_some_class( + )->add_text( `Today` + )->add_space( + )->add_text( `is` + )->add_space( + )->add_text( xco_cp=>sy->date( )->as( xco_cp_time=>format->iso_8601_extended )->value + )->add_period( + )->add_space( + )->add_text( `It's` + )->add_space( + )->add_text( xco_cp=>sy->time( xco_cp_time=>time_zone->user + )->as( xco_cp_time=>format->iso_8601_extended + )->value + )->add_period( + )->add_space( + )->add_text( `Have` + )->add_space( + )->add_text( `a` + )->add_space( + )->add_text( `nice` + )->add_space( + )->add_text( `day` + )->add_period( )->text. - out->write( some_text ). + out->write( text2 ). "---------------------------------------------------------------- "-------- Method chaining with a standalone statement ----------- "---------------------------------------------------------------- - "In the example, the final method call in the chain receives the - "classrun instance available in the implementation of the - "if_oo_adt_classrun~main method. + + "In the example, the final method call in the chain receives + "the classrun instance available in the implementation of the + "if_oo_adt_classrun~main method. The method implementation + "includes the writing to the console. "Console output: Lorem ipsum dolor sit amet NEW zcl_some_class( )->add_text( `Lorem` @@ -1797,6 +1928,10 @@ CLASS zcl_some_class IMPLEMENTATION. ref = me. ENDMETHOD. + METHOD return_text. + str = me->text. + ENDMETHOD. + ENDCLASS. ``` @@ -4284,6 +4419,130 @@ obj_factory = class=>factory_method( par = ... ).

⬆️ back to top

+### ABAP Doc Comments + +- The ABAP Doc documentation tool allows you to add special ABAP Doc comments to ABAP source code for documentation. +- ABAP Doc comments consist of one or more lines starting with `"!`. +- You can place these comments before declarations (e.g., in classes and methods) to document functionality, add notes, and so on. +- In ADT, click, for example, on class names or methods to display ABAP Doc comments (if available) in the *ABAP Element Info*, or choose F2 to display the information. +- Find more information on ABAP Doc [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/ABENDOCCOMMENT.html). +- The following example demonstrates ABAP Doc comments, showing various commenting options, including: + - Using HTML tags for formatting. Only a selected set of HTML tags is supported. You can choose *CTRL + Space* in the ABAP Doc comment for input help. + - Special tagging and linking options. Refer to the [documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/ABENDOCCOMMENT.html) for more details. + - Special method signature specifications like `@parameter | ...` for parameters and `@raising | ...` for declared exceptions. + + +```abap +"!

Demo ABAP Doc comments

+"! +"!

This class serves as an example to illustrate comments for ABAP Doc. +"! The comments begin with the string "!, a special form of regular comments introduced by ".

+"! The {@link zcl_some_class.METH:calculate} method of the example class performs a calculation.

+"!

Notes

+"! +"!

Steps

+"!
    +"!
  1. Create a demo class named zcl_some_class
  2. +"!
  3. Copy and paste the code of this example and activate.
  4. +"!
  5. Click the class name to display the comments in the ABAP Element Info ADT tab.
  6. +"!
  7. You can also choose F2 for the class name to display the information.
  8. +"!
+"!

More examples

+"! Find more code examples in ABAP cheat sheet demo classes, such as {@link zcl_demo_abap_objects} and others.
+"!

Link examples

+"! +CLASS zcl_some_class DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. + + TYPES: basetype TYPE c LENGTH 1, + BEGIN OF ENUM t_enum_calc STRUCTURE en_calc BASE TYPE basetype, + init VALUE IS INITIAL, + plus VALUE '+', + minus VALUE '-', + multiply VALUE '*', + divide VALUE '/', + END OF ENUM t_enum_calc STRUCTURE en_calc. + + "!

This method performs a calculation.

+ "! @parameter num1 | First number for the calcation + "! @parameter num2 | Second number for the calcation + "! @parameter operator | Operator. Only one of the four operators +, -, *, / is allowed. + "! The value is represented by an enumerated type. Note that there is no handling if + "! the assigned value is initial. + "! @parameter result | Result of the calculation + "! @raising cx_sy_zerodivide | Zero division + "! @raising cx_sy_arithmetic_overflow | Arithmetic overflow + CLASS-METHODS calculate IMPORTING num1 TYPE i + num2 TYPE i + operator TYPE t_enum_calc + RETURNING VALUE(result) TYPE decfloat34 + RAISING cx_sy_zerodivide cx_sy_arithmetic_overflow. + + "! This is an ABAP Doc comment for a constant + CONSTANTS const TYPE i VALUE 123. + + "! This is an ABAP Doc comment for a static attribute of a class + CLASS-DATA dobj TYPE i. + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. + +CLASS zcl_some_class IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + + DATA(result_plus) = calculate( num1 = 1 num2 = 10 operator = en_calc-plus ). + DATA(result_minus) = calculate( num1 = 1 num2 = 10 operator = en_calc-minus ). + DATA(result_multiply) = calculate( num1 = 2 num2 = 5 operator = en_calc-multiply ). + DATA(result_divide) = calculate( num1 = 10 num2 = 5 operator = en_calc-divide ). + + out->write( data = result_plus name = `result_plus` ). + out->write( data = result_minus name = `result_minus` ). + out->write( data = result_multiply name = `result_multiply` ). + out->write( data = result_divide name = `result_divide` ). + + ENDMETHOD. + + METHOD calculate. + + result = SWITCH #( operator + WHEN en_calc-plus THEN num1 + num2 + WHEN en_calc-minus THEN num1 - num2 + WHEN en_calc-multiply THEN num1 * num2 + WHEN en_calc-divide THEN num1 / num2 + ELSE '0' ). + + ENDMETHOD. +ENDCLASS. +``` + +

⬆️ back to top

+ ## More Information You can check the subtopics of diff --git a/06_Dynamic_Programming.md b/06_Dynamic_Programming.md index bd5dae9..6e007ec 100644 --- a/06_Dynamic_Programming.md +++ b/06_Dynamic_Programming.md @@ -1026,6 +1026,9 @@ READ TABLE dref->* ASSIGNING FIELD-SYMBOL() WITH KEY ('CARRID') = 'AA'. DATA(line) = CONV zdemo_abap_carr( dref->*[ ('CARRID') = 'AA' ] ). dref->*[ ('CARRID') = 'AA' ] = VALUE zdemo_abap_carr( BASE dref->*[ ('CARRID') = 'AA' ] carrid = 'XY' ). dref->*[ ('CARRID') = 'XY' ]-('CARRID') = 'ZZ'. +"Note: As the example uses a fully generic type, explicit or implicit index +"operations are not allowed. +"dref->*[ 1 ]-('CARRID') = 'ZZ'. "Table functions DATA(num_tab_lines) = lines( dref->* ). @@ -1285,9 +1288,9 @@ ASSIGN ('ZDEMO_ABAP_OBJECTS_INTERFACE')=>('CONST_INTF') TO . ASSIGN NEW zcl_demo_abap_objects( )->('PUBLIC_STRING') TO . "ELSE UNASSIGN addition -"If ELSE UNASSIGN is specified in the context of dynamic assignments/accesses, -"no memory area is assigned to the field symbol. It is unassigned after -"the ASSIGN statement. +"If ELSE UNASSIGN is specified and assignment does not work in the context +"of dynamic assignments/accesses, no memory area is assigned to the field +"symbol. It is unassigned after the ASSIGN statement. "Note: For the static variant of the ASSIGN statement, i.e. if the memory area "to be assigned following the ASSIGN keyword is statically specified, the addition "ELSE UNASSIGN is implicitly set and cannot be used explicitly. @@ -1370,7 +1373,7 @@ ASSIGN dobj_c10 TO CASTING TYPE HANDLE tdo_elem. "1234 "CREATE DATA dref TYPE ... TABLE OF (typename) ... "CREATE DATA dref TYPE REF TO (typename). "CREATE DATA dref TYPE LINE OF (typename). -"CREATE DATA dref LIKE struc-(dobjname). +"CREATE DATA dref LIKE struc-(compname). "CREATE DATA dref TYPE (absolute_name). "CREATE DATA dref TYPE HANDLE type_description_object. @@ -1490,6 +1493,18 @@ CREATE OBJECT oref_dyn TYPE ('ZCL_DEMO_ABAP_OBJECTS'). DATA cl TYPE string VALUE `ZCL_DEMO_ABAP_OBJECTS`. CREATE OBJECT oref_dyn TYPE (cl). +"Specifying a wrong/non-existent type name +TRY. + CREATE OBJECT oref_dyn TYPE ('THIS_CLASS_DOES_NOT_EXIST'). + CATCH cx_sy_create_object_error. +ENDTRY. + +"Using an absolute name for the dynamic type specification +"Getting the absolute name using RTTI +DATA(abs_name_cl) = cl_abap_typedescr=>describe_by_name( 'ZCL_DEMO_ABAP_OBJECTS' )->absolute_name. +CREATE OBJECT oref_dyn TYPE (abs_name_cl). +CREATE OBJECT oref_dyn TYPE ('\CLASS=ZCL_DEMO_ABAP_OBJECTS'). + "Note: If the class has an instance constructor specified with importing "parameters, you can (or must in the case of non-optional parameters) pass "actual parameters. @@ -2288,16 +2303,24 @@ ENDCLASS.

⬆️ back to top

### Dynamic Invoke -The following code snippet shows dynamically specifying [procedures](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenprocedure_glosry.htm "Glossary Entry") calls. The snippet covers methods. Find an example of a dynamic function module call in the [Program Flow Logic](./13_Program_Flow_Logic.md#function-module-example) cheat sheet. + + +- The following code snippet shows dynamically specifying [procedures](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenprocedure_glosry.htm "Glossary Entry") calls. +- The snippet covers methods. Dynamic method calls require `CALL METHOD` statements. +- Find an example of a dynamic function module call in the [Program Flow Logic](./13_Program_Flow_Logic.md#function-module-example) cheat sheet. + + +Syntax patterns: ``` abap -"Note: Dynamic method calls require a CALL METHOD statement. "The following examples assume that there are no mandatory "parameters defined for the method. "Possible for methods of the same class, works like me->(meth) CALL METHOD (meth). + "Class specified statically CALL METHOD class=>(meth). + "Object reference variable specified statically; "also possible for interface reference variables CALL METHOD oref->(meth). @@ -2305,6 +2328,7 @@ CALL METHOD oref->(meth). "The following statements are possible for all visible static methods "Class dynamically specified CALL METHOD (class)=>meth. + "Class and method dynamically specified CALL METHOD (class)=>(meth). @@ -2328,38 +2352,10 @@ CALL METHOD class=>(meth) PARAMETER-TABLE ptab. " value -> pointer to appropriate actual parameter, " is of type REF TO data "The addition EXCEPTION-TABLE for exceptions is not dealt with here. - -"Example that uses the PARAMETER-TABLE addition -"Creating an instance by specifying the type statically -"An example class of the cheat sheet repository is used. -DATA(oref1) = NEW zcl_demo_abap_objects( ). -"Calling an instance method -"The method multiplies an integer by 3. -"The calculation result is returned. -DATA(result) = oref1->triple( i_op = 2 ). "6 - -"Dynamic equivalent -"Creating an instance of a class by specifying the type -"dynamically -DATA oref2 TYPE REF TO object. -CREATE OBJECT oref2 TYPE ('ZCL_DEMO_ABAP_OBJECTS'). - -"Creating parameter table -DATA(ptab) = VALUE abap_parmbind_tab( ( name = 'I_OP' - kind = cl_abap_objectdescr=>exporting - value = NEW i( 3 ) ) - ( name = 'R_TRIPLE' - kind = cl_abap_objectdescr=>returning - value = NEW i( ) ) ). - -"Dynamic method call and specifying a parameter table -CALL METHOD oref2->('TRIPLE') PARAMETER-TABLE ptab. -result = ptab[ name = 'R_TRIPLE' ]-('VALUE')->*. "9 ``` -**Example Class** - -The commented example class below explores dynamic method calls with a simple method. You can create a demo class called `zcl_some_class` and copy and paste the following code. Once activated, you can choose *F9* in ADT to run the class. The example is designed to display output in the console that shows the result of calling different methods. +**Example class 1** +The following example class explores dynamic method calls with simple methods. You can create a demo class called `zcl_some_class` and copy and paste the following code. Once activated, you can choose *F9* in ADT to run the class. The example is not designed to display output in the console. ```abap CLASS zcl_some_class DEFINITION @@ -2369,141 +2365,185 @@ CLASS zcl_some_class DEFINITION PUBLIC SECTION. INTERFACES if_oo_adt_classrun. - METHODS meth IMPORTING num1 TYPE i - num2 TYPE i - EXPORTING add TYPE i - subtr TYPE i - CHANGING abs_val TYPE i - RETURNING VALUE(ret) TYPE string. - + METHODS inst_meth1. + METHODS inst_meth2 IMPORTING text TYPE string + RETURNING VALUE(result) TYPE string. + CLASS-METHODS stat_meth1. + CLASS-METHODS stat_meth2 IMPORTING text TYPE string + EXPORTING result TYPE string. PROTECTED SECTION. PRIVATE SECTION. - ENDCLASS. CLASS zcl_some_class IMPLEMENTATION. METHOD if_oo_adt_classrun~main. - "-------------------- Static method call -------------------- + "The following examples use both named and unnamed data objects randomly, + "i.e. ...=>(meth_name) or ...=>(`SOME_METH`), for example. + DATA(cl_name) = `ZCL_SOME_CLASS`. + DATA(meth_name1) = `STAT_METH1`. - "Creating object reference - DATA(oref_stat) = NEW zcl_some_class( ). - DATA: calc_result_addition TYPE i, - calc_result_subtraction TYPE i, - some_number TYPE i VALUE -123. + "------------------------------------------------------------------------ + "---------------- Calling static methods dynamically -------------------- + "------------------------------------------------------------------------ - DATA(result_stat) = oref_stat->meth( EXPORTING num1 = 7 - num2 = 3 - IMPORTING add = calc_result_addition - subtr = calc_result_subtraction - CHANGING abs_val = some_number ). + "-------- Method without mandatory parameters defined -------- + "The syntax is possible for methods of the same class. + CALL METHOD (meth_name1). - out->write( data = calc_result_addition name = `calc_result_addition` ). - out->write( data = calc_result_subtraction name = `calc_result_subtraction` ). - out->write( data = some_number name = `some_number` ). - out->write( data = result_stat name = `result_stat` ). - out->write( repeat( val = `*` occ = 80 ) ). + "The previous example method call works like me->(meth). + CALL METHOD me->(meth_name1). - "-------------------- Dynamic method calls -------------------- - "The following method calls explore possible dynamic equivalents - "of the previous static method call. + "-------- Class specified statically, method specified dynamically -------- + CALL METHOD zcl_some_class=>(meth_name1). + + "-------- Class specified dynamically, method specified statically -------- + CALL METHOD (`ZCL_SOME_CLASS`)=>stat_meth1. + + "-------- Class and method specified dynamically -------- + CALL METHOD (`ZCL_SOME_CLASS`)=>(`STAT_METH1`). + + "-------- Specifying non-optional parameters -------- + CALL METHOD (`ZCL_SOME_CLASS`)=>stat_meth2 EXPORTING text = `hallo`. + + "Specifying the output parameter is optional + DATA res TYPE string. + CALL METHOD (`ZCL_SOME_CLASS`)=>stat_meth2 EXPORTING text = `hallo` IMPORTING result = res. + ASSERT res = `HALLO`. + + "-------- Some examples for handling errors when calling methods wrongly -------- + + "Instance method called using => + TRY. + CALL METHOD zcl_some_class=>(`INST_METH1`). + CATCH cx_sy_dyn_call_illegal_method. + ENDTRY. + + "The example method does not specify non-optional parameters. + TRY. + CALL METHOD (`ZCL_SOME_CLASS`)=>stat_meth2. + CATCH cx_sy_dyn_call_param_missing. + ENDTRY. + + "Specifying a wrong parameter name + TRY. + CALL METHOD (`ZCL_SOME_CLASS`)=>stat_meth2 EXPORTING hallo = `hallo`. + CATCH cx_sy_dyn_call_param_missing. + ENDTRY. + + "Assigning wrong, non-compatible type + TRY. + CALL METHOD (`ZCL_SOME_CLASS`)=>stat_meth2 EXPORTING text = VALUE string_table( ( `hi` ) ). + CATCH cx_sy_dyn_call_illegal_type. + ENDTRY. + + "Specifying wrong parameter kinds (the example method specifies importing + "and exporting parameters, and not a returning parameter) + TRY. + CALL METHOD (`ZCL_SOME_CLASS`)=>stat_meth2 EXPORTING text = `hallo` RECEIVING result = res. + CATCH cx_sy_dyn_call_illegal_type. + ENDTRY. + + "------------------------------------------------------------------------ + "---------------- Calling instance methods dynamically ------------------ + "------------------------------------------------------------------------ "Creating an instance of a class by specifying the type dynamically DATA oref TYPE REF TO object. CREATE OBJECT oref TYPE ('ZCL_SOME_CLASS'). - some_number = -99. - "Specifying parameters statically - DATA result_dyn TYPE string. - CALL METHOD oref->('METH') - EXPORTING - num1 = 10 - num2 = 4 - IMPORTING - add = calc_result_addition - subtr = calc_result_subtraction - CHANGING - abs_val = some_number - RECEIVING - ret = result_dyn. + "--- Object reference variable specified statically, method specified dynamically --- + "Note: This is a also possible for interface reference variables. + CALL METHOD oref->(`INST_METH1`). - out->write( data = calc_result_addition name = `calc_result_addition` ). - out->write( data = calc_result_subtraction name = `calc_result_subtraction` ). - out->write( data = some_number name = `some_number` ). - out->write( data = result_dyn name = `result_dyn` ). - out->write( repeat( val = `*` occ = 80 ) ). + "-------- Specifying non-optional parameters -------- + CALL METHOD oref->(`INST_METH2`) EXPORTING text = `abap`. - "The following examples show erroneous dynamic method calls - "Missing parameters - TRY. - CALL METHOD oref->('METH'). - CATCH cx_root INTO DATA(error). - DATA(cx_class) = cl_abap_typedescr=>describe_by_object_ref( error )->get_relative_name( ). - out->write( |{ cx_class } raised: { error->get_text( ) }| ). - out->write( repeat( val = `*` occ = 80 ) ). - ENDTRY. + CALL METHOD oref->(`INST_METH2`) EXPORTING text = `abap` RECEIVING result = res. + ASSERT res = `ABAP`. - "Illegal type of an actual parameter - TRY. - CALL METHOD oref->('METH') - EXPORTING - num1 = 'nope' - num2 = 1 - IMPORTING - add = calc_result_addition - subtr = calc_result_subtraction - CHANGING - abs_val = some_number - RECEIVING - ret = result_dyn. - CATCH cx_root INTO error. - cx_class = cl_abap_typedescr=>describe_by_object_ref( error )->get_relative_name( ). - out->write( |{ cx_class } raised: { error->get_text( ) }| ). - out->write( repeat( val = `*` occ = 80 ) ). - ENDTRY. + "Note that calling static methods using object reference variables is also possible. + CALL METHOD oref->(`STAT_METH1`). - "Dynamic method call using a parameter table - DATA(ptab) = VALUE abap_parmbind_tab( ( name = 'NUM1' + CALL METHOD oref->(`STAT_METH2`) EXPORTING text = `test` IMPORTING result = res. + ASSERT res = `TEST`. + + "------------------------------------------------------------------------ + "------------------- PARAMETER-TABLE addition --------------------------- + "------------------------------------------------------------------------ + + "------- Static equivalents to the dynamic statement below ------- + DATA(oref_stat) = NEW zcl_some_class( ). + res = oref_stat->inst_meth2( `abc` ). + ASSERT res = `ABC`. + "For demo purposes, including chained method call options: + "Functional method call + res = NEW zcl_some_class( )->inst_meth2( `def` ). + ASSERT res = `DEF`. + "Standalone statement) + NEW zcl_some_class( )->inst_meth2( EXPORTING text = `ghi` RECEIVING result = res ). + ASSERT res = `GHI`. + + "------- Dynamic CALL METHOD statements using the PARAMETER-TABLE addition ------- + + "Creating parameter table for an instance example method + DATA(ptab) = VALUE abap_parmbind_tab( ( name = 'TEXT' kind = cl_abap_objectdescr=>exporting - value = NEW i( 2 ) ) - ( name = 'NUM2' - kind = cl_abap_objectdescr=>exporting - value = NEW i( 10 ) ) - ( name = 'ADD' - kind = cl_abap_objectdescr=>importing - value = NEW i( ) ) - ( name = 'SUBTR' - kind = cl_abap_objectdescr=>importing - value = NEW i( ) ) - ( name = 'ABS_VAL' - kind = cl_abap_objectdescr=>changing - value = NEW i( -987 ) ) - ( name = 'RET' + value = NEW string( `jkl` ) ) + ( name = 'RESULT' kind = cl_abap_objectdescr=>returning - value = NEW string( ) ) ). + value = NEW string( ) ) + ). - CALL METHOD oref->('METH') PARAMETER-TABLE ptab. + CALL METHOD oref->(`INST_METH2`) PARAMETER-TABLE ptab. + "Excursion: Accessing structure components dynamically + res = ptab[ name = 'RESULT' ]-('VALUE')->*. + ASSERT res = `JKL`. + + "Creating parameter table for a static example method + ptab = VALUE abap_parmbind_tab( ( name = 'TEXT' + kind = cl_abap_objectdescr=>exporting + value = NEW string( `mno` ) ) + ( name = 'RESULT' + kind = cl_abap_objectdescr=>importing + value = NEW string( ) ) ). + + "Demonstrating static/dynamic specification variants + CALL METHOD (`ZCL_SOME_CLASS`)=>(`STAT_METH2`) PARAMETER-TABLE ptab. + res = ptab[ name = 'RESULT' ]-('VALUE')->*. + ASSERT res = `MNO`. + + CALL METHOD zcl_some_class=>(`STAT_METH2`) PARAMETER-TABLE ptab. + res = ptab[ name = 'RESULT' ]-('VALUE')->*. + ASSERT res = `MNO`. + + CALL METHOD (`ZCL_SOME_CLASS`)=>stat_meth2 PARAMETER-TABLE ptab. + res = ptab[ name = 'RESULT' ]-('VALUE')->*. + ASSERT res = `MNO`. - out->write( ptab ). ENDMETHOD. - METHOD meth. - add = num1 + num2. - subtr = num1 - num2. - DATA(abs_val_copy) = abs_val. - "Getting the absolute value - abs_val = abs( abs_val ). - ret = |Values of importing parameters: num1 = { num1 STYLE = SIMPLE }| && - |, num2 = { num2 STYLE = SIMPLE }\nValues of exporting parameters: | && - |add = { add STYLE = SIMPLE }, subtr = { subtr STYLE = SIMPLE }| && - |\nChanging parameter: abs_val (original) = { abs_val_copy STYLE = SIMPLE }, | && - |abs_val (modified) = { abs_val STYLE = SIMPLE }|. + + METHOD inst_meth1. + ... + ENDMETHOD. + + METHOD inst_meth2. + result = to_upper( text ). + ENDMETHOD. + + METHOD stat_meth1. + ... + ENDMETHOD. + + METHOD stat_meth2. + result = to_upper( text ). ENDMETHOD. ENDCLASS. ``` -**Excursion** +**Example class 2** The following simplified example highlights several things in the context of a dynamic invoke example: - Dynamic invoke and assigning actual parameters to formal parameters statically