Wednesday, 17 February 2021 06:46

Pass by value or pass by reference?

Written by Johan Wigert
Rate this item
(0 votes)
“© 2020. SAP SE or an SAP affiliate company. All rights reserved.” “Used with permission of SAP SE”

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 (or EXIT or CHECK).

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:

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

Read 44 times

Leave a comment

Make sure you enter all the required information, indicated by an asterisk (*). HTML code is not allowed.