When calling a method of an ABAP class, data can be passed from actual parameters to formal parameters either by value or by reference. In this blog post I’ll discuss the difference and highlight some important scenarios.
Definitions
Pass by value
The ABAP Keyword Documentation provides the following definition of pass by value:
[…] In pass by value, a local data object is created as a copy of the actual parameter. Output parameters and return values are initialized when the procedure is called. Input parameters and input/output parameters are given the value of the actual parameter when they are called. Modified formal parameters are only passed to actual parameters if the procedure was concluded without errors, that is once the last statement is reached or if there is an exit using
RETURN
(orEXIT
orCHECK
).
Pass by reference
The ABAP Keyword Documentation provides the following definition of pass by reference:
[…] Pass by reference does not create a local data object for the actual parameter. Instead a reference to the actual parameter is passed to the procedure when it is called and the procedure works with the actual parameter itself. Input parameters passed by reference cannot be modified in the procedure.
Scenarios
To make the concepts easier to grasp, let us look at a few example scenarios.
The IMPORTING scenario
In the IMPORTING
section of the method signature, the keywords VALUE
and REFERENCE
are used to indicate how the data is passed. If none of these keywords are used, the parameter is passed by reference by default. It is not allowed to change an input parameter passed by reference in the method, whereas this is allowed in the pass by value scenario.
Example:
REPORTzre_test_pass_by_importing.DATAgv_timeTYPEt.CLASSlcl_time_utilityDEFINITIONFINAL.PUBLICSECTION.CLASS-METHODSdisplay_timeIMPORTINGiv_time_by_reference_implicitTYPEtREFERENCE(iv_time_by_reference_explicit)TYPEtVALUE(iv_time_by_value)TYPEt.PROTECTEDSECTION.PRIVATESECTION.ENDCLASS.CLASSlcl_time_utilityIMPLEMENTATION.METHODdisplay_time.WRITE:/`Pass by reference (implicit):`.WRITE:/iv_time_by_reference_implicit.WRITE:/`Pass by reference (explicit):`.WRITE:/iv_time_by_reference_explicit.WRITE:/`Pass by value:`.WRITE:/iv_time_by_value.WAITUPTO2SECONDS.gv_time=sy-uzeit.WRITE:/`Pass by reference (implicit) after 2 seconds wait:`.WRITE:/iv_time_by_reference_implicit.WRITE:/`Pass by reference (explicit) after 2 seconds wait:`.WRITE:/iv_time_by_reference_explicit.WRITE:/`Pass by value after 2 seconds wait:`.WRITE:/iv_time_by_value.iv_time_by_value=iv_time_by_value+10.WRITE:/`Pass by value after adding 10 seconds to the input parameter:`.WRITE:/iv_time_by_value.ENDMETHOD.ENDCLASS.START-OF-SELECTION.gv_time=sy-uzeit.lcl_time_utility=>display_time(iv_time_by_reference_implicit=gv_timeiv_time_by_reference_explicit=gv_timeiv_time_by_value=gv_time).
The report generates the following output to the screen:
Pass by reference (implicit): 132031 Pass by reference (explicit): 132031 Pass by value: 132031 Pass by reference (implicit) after 2 seconds wait: 132033 Pass by reference (explicit) after 2 seconds wait: 132033 Pass by value after 2 seconds wait: 132031 Pass by value after adding 10 seconds to the input parameter: 132041
The EXPORTING scenario
In the EXPORTING
section of the method signature, the keywords VALUE
and REFERENCE
are used to indicate how the data is passed. If none of these keywords are used, the parameter is passed by reference by default. When the parameter is passed by reference, the exporting parameter doesn’t necessarily have an initial value as illustrated by the do_nothing
method in the following example. When passing by value, the modified content of the parameter is assigned to the actual parameter only if the method is completed without errors. This is illustrated by the methods get_time_120000_successfully
and get_time_120000_with_exception
.
REPORTzre_test_pass_by_exporting.DATAgv_time_by_reference_implicitTYPEt.DATAgv_time_by_reference_explicitTYPEt.DATAgv_time_by_valueTYPEt.CLASSlcl_time_utilityDEFINITIONFINAL.PUBLICSECTION.CLASS-METHODSdo_nothingEXPORTINGev_time_by_reference_implicitTYPEtREFERENCE(ev_time_by_reference_explicit)TYPEtVALUE(ev_time_by_value)TYPEt.CLASS-METHODSget_time_120000_successfullyEXPORTINGev_time_by_reference_implicitTYPEtREFERENCE(ev_time_by_reference_explicit)TYPEtVALUE(ev_time_by_value)TYPEt.CLASS-METHODSget_time_120000_with_exceptionEXPORTINGev_time_by_reference_implicitTYPEtREFERENCE(ev_time_by_reference_explicit)TYPEtVALUE(ev_time_by_value)TYPEtRAISINGcx_abap_datfm_invalid_date.PROTECTEDSECTION.PRIVATESECTION.ENDCLASS.CLASSlcl_time_utilityIMPLEMENTATION.METHODdo_nothing.ENDMETHOD.METHODget_time_120000_successfully.ev_time_by_reference_implicit='120000'.ev_time_by_reference_explicit='120000'.ev_time_by_value='120000'.ENDMETHOD.METHODget_time_120000_with_exception.ev_time_by_reference_implicit='120000'.ev_time_by_reference_explicit='120000'.ev_time_by_value='120000'.RAISEEXCEPTIONTYPEcx_abap_datfm_invalid_date.ENDMETHOD.ENDCLASS.START-OF-SELECTION.gv_time_by_reference_implicit=sy-uzeit.gv_time_by_reference_explicit=sy-uzeit.gv_time_by_value=sy-uzeit.WRITE:/`Start time:`.WRITE:/gv_time_by_value.WRITE:/`Do nothing:`.lcl_time_utility=>do_nothing(IMPORTINGev_time_by_reference_implicit=gv_time_by_reference_implicitev_time_by_reference_explicit=gv_time_by_reference_explicitev_time_by_value=gv_time_by_value).WRITE:/`Pass by reference (implicit):`.WRITE:/gv_time_by_reference_implicit.WRITE:/`Pass by reference (explicit):`.WRITE:/gv_time_by_reference_explicit.WRITE:/`Pass by value:`.WRITE:/gv_time_by_value.WRITE:/`Method call successful:`.CLEAR:gv_time_by_reference_implicit,gv_time_by_reference_explicit,gv_time_by_value.lcl_time_utility=>get_time_120000_successfully(IMPORTINGev_time_by_reference_implicit=gv_time_by_reference_implicitev_time_by_reference_explicit=gv_time_by_reference_explicitev_time_by_value=gv_time_by_value).WRITE:/`Pass by reference (implicit):`.WRITE:/gv_time_by_reference_implicit.WRITE:/`Pass by reference (explicit):`.WRITE:/gv_time_by_reference_explicit.WRITE:/`Pass by value:`.WRITE:/gv_time_by_value.WRITE:/`Method call unsuccessful:`.CLEAR:gv_time_by_reference_implicit,gv_time_by_reference_explicit,gv_time_by_value.TRY.lcl_time_utility=>get_time_120000_with_exception(IMPORTINGev_time_by_reference_implicit=gv_time_by_reference_implicitev_time_by_reference_explicit=gv_time_by_reference_explicitev_time_by_value=gv_time_by_value).CATCHcx_abap_datfm_invalid_date." do nothingENDTRY.WRITE:/`Pass by reference (implicit):`.WRITE:/gv_time_by_reference_implicit.WRITE:/`Pass by reference (explicit):`.WRITE:/gv_time_by_reference_explicit.WRITE:/`Pass by value:`.WRITE:/gv_time_by_value.
The report generates the following output to the screen:
Start time: 144905 Do nothing: Pass by reference (implicit): 144905 Pass by reference (explicit): 144905 Pass by value: 000000 Method call successful: Pass by reference (implicit): 120000 Pass by reference (explicit): 120000 Pass by value: 120000 Method call unsuccessful: Pass by reference (implicit): 120000 Pass by reference (explicit): 120000 Pass by value: 000000
The CHANGING scenario
In the CHANGING
section of the method signature, the keywords VALUE
and REFERENCE
are used to indicate how the data is passed. If none of these keywords are used, the parameter is passed by reference by default. When passing by value, the modified content of the parameter is assigned to the actual parameter only if the method is completed without errors. This is illustrated in the following example:
REPORTzre_test_pass_by_changing.DATAgv_time_by_reference_implicitTYPEt.DATAgv_time_by_reference_explicitTYPEt.DATAgv_time_by_valueTYPEt.CLASSlcl_time_utilityDEFINITIONFINAL.PUBLICSECTION.CLASS-METHODSadd_10_seconds_successfullyCHANGINGcv_time_by_reference_implicitTYPEtREFERENCE(cv_time_by_reference_explicit)TYPEtVALUE(cv_time_by_value)TYPEt.CLASS-METHODSadd_10_seconds_with_exceptionCHANGINGcv_time_by_reference_implicitTYPEtREFERENCE(cv_time_by_reference_explicit)TYPEtVALUE(cv_time_by_value)TYPEtRAISINGcx_abap_datfm_invalid_date.PROTECTEDSECTION.PRIVATESECTION.ENDCLASS.CLASSlcl_time_utilityIMPLEMENTATION.METHODadd_10_seconds_successfully.cv_time_by_reference_implicit=cv_time_by_reference_implicit+10.cv_time_by_reference_explicit=cv_time_by_reference_explicit+10.cv_time_by_value=cv_time_by_value+10.ENDMETHOD.METHODadd_10_seconds_with_exception.cv_time_by_reference_implicit=cv_time_by_reference_implicit+10.cv_time_by_reference_explicit=cv_time_by_reference_explicit+10.cv_time_by_value=cv_time_by_value+10.RAISEEXCEPTIONTYPEcx_abap_datfm_invalid_date.ENDMETHOD.ENDCLASS.START-OF-SELECTION.gv_time_by_reference_implicit=sy-uzeit.gv_time_by_reference_explicit=sy-uzeit.gv_time_by_value=sy-uzeit.WRITE:/`Start time:`.WRITE:/gv_time_by_value.WRITE:/`Method call successful:`.lcl_time_utility=>add_10_seconds_successfully(CHANGINGcv_time_by_reference_implicit=gv_time_by_reference_implicitcv_time_by_reference_explicit=gv_time_by_reference_explicitcv_time_by_value=gv_time_by_value).WRITE:/`Pass by reference (implicit):`.WRITE:/gv_time_by_reference_implicit.WRITE:/`Pass by reference (explicit):`.WRITE:/gv_time_by_reference_explicit.WRITE:/`Pass by value:`.WRITE:/gv_time_by_value.WRITE:/`Method call unsuccessful:`.TRY.lcl_time_utility=>add_10_seconds_with_exception(CHANGINGcv_time_by_reference_implicit=gv_time_by_reference_implicitcv_time_by_reference_explicit=gv_time_by_reference_explicitcv_time_by_value=gv_time_by_value).CATCHcx_abap_datfm_invalid_date." do nothingENDTRY.WRITE:/`Pass by reference (implicit):`.WRITE:/gv_time_by_reference_implicit.WRITE:/`Pass by reference (explicit):`.WRITE:/gv_time_by_reference_explicit.WRITE:/`Pass by value:`.WRITE:/gv_time_by_value.
The report generates the following output to the screen:
Start time: 142101 Method call successful: Pass by reference (implicit): 142111 Pass by reference (explicit): 142111 Pass by value: 142111 Method call unsuccessful: Pass by reference (implicit): 142121 Pass by reference (explicit): 142121 Pass by value: 142111
The RETURNING scenario
In the RETURNING
section of the method signature, the keyword VALUE
must be used since pass by value is the only option. The modified content of the parameter is assigned to the actual parameter only if the method is completed without errors. This is illustrated in the following example:
REPORTzre_test_pass_by_returning.DATAgv_time_by_valueTYPEt.CLASSlcl_time_utilityDEFINITIONFINAL.PUBLICSECTION.CLASS-METHODSdo_nothingRETURNINGVALUE(result)TYPEt.CLASS-METHODSget_time_120000_successfullyRETURNINGVALUE(result)TYPEt.CLASS-METHODSget_time_120000_with_exceptionRETURNINGVALUE(result)TYPEtRAISINGcx_abap_datfm_invalid_date.PROTECTEDSECTION.PRIVATESECTION.ENDCLASS.CLASSlcl_time_utilityIMPLEMENTATION.METHODdo_nothing.ENDMETHOD.METHODget_time_120000_successfully.result='120000'.ENDMETHOD.METHODget_time_120000_with_exception.result='120000'.RAISEEXCEPTIONTYPEcx_abap_datfm_invalid_date.ENDMETHOD.ENDCLASS.START-OF-SELECTION.gv_time_by_value=sy-uzeit.WRITE:/`Start time:`.WRITE:/gv_time_by_value.WRITE:/`Do nothing:`.gv_time_by_value=lcl_time_utility=>do_nothing().WRITE:/`Pass by value:`.WRITE:/gv_time_by_value.WRITE:/`Method call successful:`.CLEARgv_time_by_value.gv_time_by_value=lcl_time_utility=>get_time_120000_successfully().WRITE:/`Pass by value:`.WRITE:/gv_time_by_value.WRITE:/`Method call unsuccessful:`.CLEARgv_time_by_value.TRY.gv_time_by_value=lcl_time_utility=>get_time_120000_with_exception().CATCHcx_abap_datfm_invalid_date." do nothingENDTRY.WRITE:/`Pass by value:`.WRITE:/gv_time_by_value.
The report generates the following output to the screen:
Start time: 145858 Do nothing: Pass by value: 000000 Method call successful: Pass by value: 120000 Method call unsuccessful: Pass by value: 000000
The escape character !
The escape character !
can be used in the method signature to distinguish a parameter name from an ABAP word with the same name. The escape character itself isn’t part of the name. Example:
REPORTzre_test_escape.DATAgv_timeTYPEt.CLASSlcl_time_utilityDEFINITIONFINAL.PUBLICSECTION.CLASS-METHODSdisplay_timeIMPORTING!importingTYPEt.PROTECTEDSECTION.PRIVATESECTION.ENDCLASS.CLASSlcl_time_utilityIMPLEMENTATION.METHODdisplay_time.WRITE:/`Pass by reference (implicit):`.WRITE:/importing.WAITUPTO2SECONDS.gv_time=sy-uzeit.WRITE:/`Pass by reference (implicit) after 2 seconds wait:`.WRITE:/importing.ENDMETHOD.ENDCLASS.START-OF-SELECTION.gv_time=sy-uzeit.lcl_time_utility=>display_time(gv_time).
The report generates the following output to the screen:
Pass by reference (implicit): 154728 Pass by reference (implicit) after 2 seconds wait: 154730
I can’t think of any example where I’ve felt the need to use the escape character, and it is probably a good idea to avoid it whenever possible.
Further reading
There have been some interesting discussions on pass by value and pass by reference in the following issues of the GitHub repository for SAP’s ABAP Styleguide:
- Issue #150: Prefer EXPORTING parameters passed by value?
- Issue #33: Passing value type importing parameters
I also recommend the ABAP Keyword Documentation.
Happy coding!
This blog post first appeared on the Developer Voyage blog at https://www.developervoyage.com/2021/02/18/pass-by-value-or-pass-by-reference.html