ABAP - FINAL
In this article, we'll take a look at the new FINAL language construct, how it works, and what you can do with it.
Table of contents
With the ABAP release for the cloud, a few new language constructs have appeared in ABAP. We want to take a look at one of these new constructs today.
Introduction
Now what is FINAL actually about, especially since the keyword already exists in the context of class definitions? Maybe the name isn't very well chosen, but FINAL is about defining variables, just like DATA. However, variables are created whose value can only be set once, after which all changing accesses are prohibited.
Variables
In the first examples, let's create a few variables and take a look at the general syntax. You'll notice that it can be used in the same places as DATA:
FINAL(ld_name) = `My name is John`.
FINAL(lt_partner) = VALUE tt_partner(
( partner = '1' name = 'Partner One' )
( partner = '2' name = 'Partner Two' )
).
In the example shown, we create a string and a table whose values we preassign.
Tables
In the next example we look at processing with tables. To do this, we fill our table with a SELECT and define it directly when reading with FINAL. This fills the table with data, but it cannot be changed afterwards. Then let's try different types of loops:
SELECT FROM zbs_dmo_partner
FIELDS *
INTO TABLE @FINAL(lt_partner).
LOOP AT lt_partner INTO DATA(ls_partner) FROM 1 TO 3.
ENDLOOP.
LOOP AT lt_partner REFERENCE INTO DATA(lr_partner) FROM 1 TO 3.
ENDLOOP.
Reading the data works without any problems, the loops also work without errors. As long as you don't try to change the data in the second loop, there will be no error.
Loop
In the next example, let's look at the loop and using FINAL in a loop. To do this, we fill the table once with dummy data, the table was declared with DATA and could therefore be changed. Then we implement two loops, one where the workspace is defined with FINAL and one where we make a copy with FINAL.
DATA(lt_partner) = VALUE tt_partner(
( partner = '1' name = 'Partner One' )
( partner = '2' name = 'Partner Two' )
( partner = '3' name = 'Partner Three' )
( partner = '4' name = 'Partner Four' )
).
LOOP AT lt_partner INTO FINAL(ls_final_partner).
ENDLOOP.
LOOP AT lt_partner INTO DATA(ls_partner).
FINAL(ls_copy) = ls_partner.
ENDLOOP.
Loops work without problems, running through the FINAL statement multiple times is no problem. It is important that the variable is only set at one point with FINAL. If this point is run through several times, the content of the variable changes.
CHANGING
The last example in this article deals with passing such defined variables to methods with changing parameters. The following example is not possible and cannot be activated even if the variable in the method is not changed:
FINAL(ls_partner) = VALUE ts_partner( partner = '3' name = 'Partner Three' ).
changing_final_variable(
CHANGING
cs_partner = ls_partner
).
Error
In some of the examples shown, activation of source code is already not possible because the system recognizes that the field is being changed and the compiler prevents activation:
In the case of the loop with reference, the compiler allows activation and does not show any errors. However, when you run the code, you get an uncatchable MOVE_TO_LIT_NOTALLOWED_NODATA exception:
SELECT FROM zbs_dmo_partner
FIELDS *
INTO TABLE @FINAL(lt_partner).
LOOP AT lt_partner REFERENCE INTO DATA(lr_partner) FROM 1 TO 3.
lr_partner->street = 'Dummy'.
ENDLOOP.
Complete example
As always, at the end of the article, once again the complete example of today's article. We took the table from the data model for the CDS views:
CLASS zcl_bs_demo_langu_final DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
TYPES:
BEGIN OF ts_partner,
partner TYPE zbs_dmo_partner-partner,
name TYPE zbs_dmo_partner-name,
country TYPE zbs_dmo_partner-country,
END OF ts_partner,
tt_partner TYPE SORTED TABLE OF ts_partner WITH UNIQUE KEY partner.
PROTECTED SECTION.
PRIVATE SECTION.
METHODS:
set_variables
IMPORTING
io_out TYPE REF TO if_oo_adt_classrun_out,
select_from_table
IMPORTING
io_out TYPE REF TO if_oo_adt_classrun_out,
final_in_loop
IMPORTING
io_out TYPE REF TO if_oo_adt_classrun_out,
call_method_with_changing
IMPORTING
io_out TYPE REF TO if_oo_adt_classrun_out,
changing_final_variable
CHANGING
cs_partner TYPE ts_partner.
ENDCLASS.
CLASS zcl_bs_demo_langu_final IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
set_variables( out ).
select_from_table( out ).
final_in_loop( out ).
call_method_with_changing( out ).
ENDMETHOD.
METHOD set_variables.
FINAL(ld_name) = `My name is John`.
io_out->write( ld_name ).
FINAL(lt_partner) = VALUE tt_partner(
( partner = '1' name = 'Partner One' )
( partner = '2' name = 'Partner Two' )
).
io_out->write( lt_partner ).
* INSERT VALUE #( partner = '3' name = 'Partner Three' ) INTO TABLE lt_partner.
ENDMETHOD.
METHOD select_from_table.
SELECT FROM zbs_dmo_partner
FIELDS *
INTO TABLE @FINAL(lt_partner).
LOOP AT lt_partner INTO DATA(ls_partner) FROM 1 TO 3.
io_out->write( ls_partner ).
ENDLOOP.
LOOP AT lt_partner REFERENCE INTO DATA(lr_partner) FROM 1 TO 3.
" Will dump
* lr_partner->street = 'Dummy'.
ENDLOOP.
ENDMETHOD.
METHOD final_in_loop.
DATA(lt_partner) = VALUE tt_partner(
( partner = '1' name = 'Partner One' )
( partner = '2' name = 'Partner Two' )
( partner = '3' name = 'Partner Three' )
( partner = '4' name = 'Partner Four' )
).
LOOP AT lt_partner INTO FINAL(ls_final_partner).
io_out->write( ls_final_partner ).
ENDLOOP.
LOOP AT lt_partner INTO DATA(ls_partner).
FINAL(ls_copy) = ls_partner.
io_out->write( ls_copy ).
ENDLOOP.
ENDMETHOD.
METHOD call_method_with_changing.
FINAL(ls_partner) = VALUE ts_partner( partner = '3' name = 'Partner Three' ).
* changing_final_variable(
* CHANGING
* cs_partner = ls_partner
* ).
ENDMETHOD.
METHOD changing_final_variable.
" No implementation
ENDMETHOD.
ENDCLASS.
Conclusion
Today's statement expands your knowledge of defining variables. The naming is a matter of taste and not necessarily consistent. In the end, you can use it to provide values and tables that also come with write protection and you don't have to worry about making adjustments in subroutines.
Source:
SAP Documentation - FINAL