styleguides icon indicating copy to clipboard operation
styleguides copied to clipboard

Passing value type importing parameters

Open gbrfarkas opened this issue 6 years ago • 4 comments

First of all, thank you for this awesome guide, really appreciate the work that has been put into it.

I didn't find a recommendation on when to use pass by value/reference in case of importing parameters. This is probably a minor point but maybe worth mentioning because in other programming languages, the default behavior is that value types (int, struct, double etc.) are passed to methods by value (ie. they are copied). I think many developers expect this behavior subconsciously in ABAP too, however everything is passed by reference unless VALUE( ) is explicitly specified.

This can create some weird unexpected side effects for example when you pass sy-tabix to a method as an importing parameter (might be an anti-pattern itself...?) and there is a LOOP or READ TABLE inside the method too. There are probably other similar examples.

gbrfarkas avatar May 08 '19 14:05 gbrfarkas

The weird side effect scenario is not really valid. Firstly, ABAP won't let you change anything IMPORTed by reference. Secondly, if you pass sy-tabix, it will be addressed by the importing parameter's name and the method keeps it's own sy-tabix. Otherwise we'd be in trouble with any method that is called from a loop and performs a loop.

Or perhaps I misunderstood something; in that case could you provide a code example of what you mean?

pokrakam avatar May 10 '19 10:05 pokrakam

@pokrakam

Firstly, ABAP won't let you change anything IMPORTed by reference.

That is true for the access using the import parameter. If you have any other non read-only reference to the data object you can of course change it. Which is what happens with global fields like syst.

Secondly, if you pass sy-tabix, it will be addressed by the importing parameter's name and the method keeps it's own sy-tabix.

Yes, but the import parameter's value will change in that loop as well if you pass by value. Which is something you might not expect.

CLASS lcl_test_parameter DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS:
      pass_by_value IMPORTING VALUE(iv_tabix) TYPE syst_tabix,
      pass_by_reference IMPORTING iv_tabix TYPE syst_tabix.
  PROTECTED SECTION.
  PRIVATE SECTION.
    CLASS-METHODS:
      do_something_with_table.
ENDCLASS.

CLASS lcl_test_parameter IMPLEMENTATION.
  METHOD pass_by_value.
    WRITE: / 'Pass by value'.
    WRITE: / |Before: { iv_tabix }|.
    do_something_with_table( ).
    WRITE: / |After: { iv_tabix }|.
  ENDMETHOD.

  METHOD pass_by_reference.
    WRITE: / 'Pass by reference'.
    WRITE: / |Before: { iv_tabix }|.
    do_something_with_table( ).
    WRITE: / |After: { iv_tabix }|.
  ENDMETHOD.

  METHOD do_something_with_table.
    DATA(lt_tab) = VALUE stringtab( ( `1`) ( `2`) ( `3` ) ).
    READ TABLE lt_tab WITH KEY table_line = `2` TRANSPORTING NO FIELDS.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  sy-tabix = 200.
  lcl_test_parameter=>pass_by_value( sy-tabix ).
  sy-tabix = 200.
  lcl_test_parameter=>pass_by_reference( sy-tabix ).
Pass by value
Before: 200
After: 200
Pass by reference
Before: 200
After: 2

fabianlupa avatar May 10 '19 10:05 fabianlupa

Exactly. The following example also demonstrates the same thing:

CLASS test DEFINITION FINAL.
  PUBLIC SECTION.
    CLASS-METHODS display_time
      IMPORTING time TYPE syuzeit.
ENDCLASS.

CLASS test IMPLEMENTATION.
  METHOD display_time.
    WAIT UP TO 5 SECONDS.
    GET TIME.
    WRITE: / time.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  test=>display_time( sy-uzeit ).

One might expect this to display the time I passed originally but this is not the case - it will display the current time at the WRITE statement which is 5 seconds later.

gbrfarkas avatar May 10 '19 11:05 gbrfarkas

Ah, OK I get it! I thought you meant it could interfere with the loop itself, which remains consitent regardless of what you throw at it. Even the following will loop correctly:

CLASS lcl_test DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS foo CHANGING tabix TYPE i.
ENDCLASS.

CLASS lcl_test IMPLEMENTATION.
  METHOD change_tabix.
    tabix = 999.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  DATA(itab) = VALUE stringtab( ( `1`) ( `2`) ( `3` ) ).

  LOOP AT itab INTO DATA(val).
    WRITE / |Before call: { val } / { sy-tabix }|.
    lcl_test=>change_tabix( CHANGING tabix = sy-tabix ).
    WRITE |After call: { val } / { sy-tabix }|.
  ENDLOOP.

pokrakam avatar May 10 '19 11:05 pokrakam