ABAP Deep Dive - VALUE
In this article we want to look at the value statement again in all its forms and how you can use it in your daily work.
Table of contents
In another article we have already dealt with aspects of the value statement and how it simplifies your life as a new variant. In this article we will again go into the different variants and ways of use and how the VALUE can be easily integrated into your everyday life.
Introduction
The value statement is a constructor expression, which means new data types are created. As with CORRESPONDING, the expression can be used to initialize the target variable. Value is mainly used for structures and tables and can be used in various positions, such as in an inline declaration, an insert or in importing parameters.
Preparation
Before we start with the examples, here are the different types that we will use in our examples. At the end of the article you will find the complete executable class again so that you can understand all the examples:
TYPES:
td_field TYPE c LENGTH 20,
tt_r_field TYPE RANGE OF td_field,
BEGIN OF ts_structure,
ident TYPE i,
text TYPE string,
last_changed TYPE timestamp,
END OF ts_structure,
tt_structure TYPE SORTED TABLE OF ts_structure WITH UNIQUE KEY ident,
tt_unsorted TYPE STANDARD TABLE OF ts_structure WITH NON-UNIQUE KEY ident.
Definition
If you have already defined a variable in your source code, you can use Value to reinitialize the variable and fill it with new information. In the following example, the variable has already been defined in the header and is now being filled.
DATA:
ls_predefined TYPE ts_structure.
ls_predefined = VALUE #( ident = 1 text = `Test 1` ).
You can use the placeholder # after Value because the type is known during the assignment. In this case, the data type is derived from the target variable. It is of course also possible to specify the data type with the value statement and omit the placeholder. This allows the variable to be defined using an inline declaration:
DATA(ls_inline) = VALUE ts_structure( ident = 2 text = `Test 2` ).
In the previous examples we have created structures, it is also possible to create tables in the same way. To do this we specify a table type after Value and now it is important to delimit each record with a pair of brackets. For the sake of simplicity, we support readability by formatting the statement accordingly:
DATA(lt_inline) = VALUE tt_structure(
( ident = 3 text = `Test 3` )
( ident = 4 text = `Test 4` )
( ident = 5 text = `Test 5` )
).
Default values
In the last example, we filled a table with rows, giving all values in each row and thus completely structuring the table. But what about a range, for example? We can fill these in the same way:
DATA(lt_r_full) = VALUE tt_r_field(
( sign = 'I' option = 'EQ' low = 'ABC' )
( sign = 'I' option = 'EQ' low = 'DEF' )
( sign = 'I' option = 'EQ' low = 'GHI' )
).
But what is noticeable is that we have a lot of duplicate entries that we have to fill with each line. So that we don't have to fill "SIGN" and "OPTION" with every line, we can also define default values outside of the line:
DATA(lt_r_default) = VALUE tt_r_field(
sign = 'I' option = 'EQ'
( low = 'ABC' )
( low = 'DEF' )
( low = 'GHI' )
).
But what no longer works is addressing the element that has already been defined outside the brackets. So we can't enter any other option for a line. But what works is to "swap" the default value outside:
DATA(lt_r_switch) = VALUE tt_r_field(
sign = 'I' option = 'EQ'
( low = 'ABC' )
( low = 'DEF' )
option = 'BT'
( low = 'GHI' high = 'JKL' )
).
In the example shown, we only exchange the "OPTION", "SIGN" remains defined as "Included".
BASE
Now let's look at the use of the "BASE" suffix and what it means for the data. To better illustrate the example, let's build a base as a first step, a table with three records:
DATA(lt_base_table) = VALUE tt_structure(
( ident = 3 text = `Test 3` )
( ident = 4 text = `Test 4` )
( ident = 5 text = `Test 5` )
).
So far nothing special. In the next step we want to insert two data sets into the existing data. Here you have to note that this is a constructor expression, if we now assign two more data records to the table via Value, then this will be deleted and only the two data records will be in it. To do this, we use the addition "BASE" plus the specification of the table with the existing data records.
DATA(lt_base_extended) = VALUE tt_structure( BASE lt_base_table
( ident = 1 text = `Test 1` )
( ident = 2 text = `Test 2` )
).
ABAP copies the rows of the base table plus the new rows into the newly created table. This is a table with a sorted key, which means that the key is taken into account and no error occurs. The situation is different with the following statement:
TRY.
DATA(lt_duplicate) = VALUE tt_structure( BASE lt_base_table
( ident = 1 text = `Test 1` )
).
CATCH cx_sy_itab_duplicate_key.
ENDTRY.
We want to insert a duplicate record into the table that already has the first 5 records. In this case, the exception CX_SY_ITAB_DUPLICATE_KEY is thrown and should be caught.
LINES OF
The addition BASE ensured that the table was taken as the basis and the new data records were appended at the end. If the table is a sorted table, then the records are inserted according to their order. But how do we get the data records together in a "STANDARD" table? To do this, we create the following table, this time without a key:
DATA(lt_base_table) = VALUE tt_unsorted(
( ident = 3 text = `Test 3` )
( ident = 4 text = `Test 4` )
( ident = 5 text = `Test 5` )
).
In the next step, we want to create a new table and include the data records from the previous step, but this time in a very specific place. For this we can use the addition "LINES OF" directly in a row of the new table:
DATA(lt_append_tab) = VALUE tt_unsorted(
( ident = 9 text = `Test 9` )
( ident = 7 text = `Test 7` )
( LINES OF lt_base_table )
( ident = 6 text = `Test 6` )
).
The rows are inserted between the other rows and the new table is created:
Filling
The VALUE statement can not only be used to create local tables and structures, but it can also be combined with various expressions. For example, you can also use it directly with an INSERT without defining an intermediate variable:
INSERT VALUE #( ident = 10 text = `Test 10` ) INTO TABLE lt_append_tab.
If a method is called and the appropriate variable is not available, it can also be created using VALUE. This method also works great for function blocks that sometimes react a little more meticulously to the correct data types:
as_parameter(
is_structure = VALUE #( ident = 10 text = `Test 10` )
).
Data type
Since we were also on the subject of data types, we should look at simply defined tables that have no defined fields but require a special data type. In most cases, these will be tables of type CHAR or STRING:
DATA:
lt_char TYPE STANDARD TABLE OF char25 WITH EMPTY KEY,
lt_string TYPE STANDARD TABLE OF string WITH EMPTY KEY.
There are small things to consider when filling. If we now want to fill the table with CHAR, we enter the previous brackets, we can omit the field name since there is none:
lt_char = VALUE #( ( 'ABC' ) ( 'DEF' ) ).
If we now want to use the whole thing for the table of type STRING, we get a corresponding compiler error message:
The correct literals must be used when filling the table, only then will this method work:
lt_string = VALUE #( ( `ABC` ) ( `DEF` ) ).
Full example
To conclude the article, once again the complete example of the parts that we have shown in this article. Furthermore, there is also an output to the console for each example in order to be able to understand the results of the operations:
CLASS zcl_bs_demo_value DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
TYPES:
td_field TYPE c LENGTH 20,
tt_r_field TYPE RANGE OF td_field,
BEGIN OF ts_structure,
ident TYPE i,
text TYPE string,
last_changed TYPE timestamp,
END OF ts_structure,
tt_structure TYPE SORTED TABLE OF ts_structure WITH UNIQUE KEY ident,
tt_unsorted TYPE STANDARD TABLE OF ts_structure WITH NON-UNIQUE KEY ident.
PROTECTED SECTION.
PRIVATE SECTION.
METHODS:
create_variables
IMPORTING
io_out TYPE REF TO if_oo_adt_classrun_out,
default_values
IMPORTING
io_out TYPE REF TO if_oo_adt_classrun_out,
base_tables
IMPORTING
io_out TYPE REF TO if_oo_adt_classrun_out,
append_table
IMPORTING
io_out TYPE REF TO if_oo_adt_classrun_out,
correct_types
IMPORTING
io_out TYPE REF TO if_oo_adt_classrun_out,
as_parameter
IMPORTING
is_structure TYPE zcl_bs_demo_value=>ts_structure.
ENDCLASS.
CLASS zcl_bs_demo_value IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
create_variables( out ).
default_values( out ).
base_tables( out ).
append_table( out ).
correct_types( out ).
as_parameter(
is_structure = VALUE #( ident = 10 text = `Test 10` )
).
ENDMETHOD.
METHOD create_variables.
DATA:
ls_predefined TYPE ts_structure.
ls_predefined = VALUE #( ident = 1 text = `Test 1` ).
io_out->write( `Predefined variable:` ).
io_out->write( ls_predefined ).
DATA(ls_inline) = VALUE ts_structure( ident = 2 text = `Test 2` ).
io_out->write( `Inline declaration (structure):` ).
io_out->write( ls_inline ).
DATA(lt_inline) = VALUE tt_structure(
( ident = 3 text = `Test 3` )
( ident = 4 text = `Test 4` )
( ident = 5 text = `Test 5` )
).
io_out->write( `Inline declaration (table):` ).
io_out->write( lt_inline ).
ENDMETHOD.
METHOD default_values.
DATA(lt_r_full) = VALUE tt_r_field(
( sign = 'I' option = 'EQ' low = 'ABC' )
( sign = 'I' option = 'EQ' low = 'DEF' )
( sign = 'I' option = 'EQ' low = 'GHI' )
).
io_out->write( `Range with full values:` ).
io_out->write( lt_r_full ).
DATA(lt_r_default) = VALUE tt_r_field(
sign = 'I' option = 'EQ'
( low = 'ABC' )
( low = 'DEF' )
( low = 'GHI' )
).
io_out->write( `Range with default values:` ).
io_out->write( lt_r_default ).
DATA(lt_r_switch) = VALUE tt_r_field(
sign = 'I' option = 'EQ'
( low = 'ABC' )
( low = 'DEF' )
option = 'BT'
( low = 'GHI' high = 'JKL' )
).
io_out->write( `Range with default switch:` ).
io_out->write( lt_r_switch ).
ENDMETHOD.
METHOD base_tables.
DATA(lt_base_table) = VALUE tt_structure(
( ident = 3 text = `Test 3` )
( ident = 4 text = `Test 4` )
( ident = 5 text = `Test 5` )
).
DATA(lt_base_extended) = VALUE tt_structure( BASE lt_base_table
( ident = 1 text = `Test 1` )
( ident = 2 text = `Test 2` )
).
io_out->write( `Add with base into sorted:` ).
io_out->write( lt_base_extended ).
TRY.
DATA(lt_duplicate) = VALUE tt_structure( BASE lt_base_table
( ident = 1 text = `Test 1` )
).
CATCH cx_sy_itab_duplicate_key.
io_out->write( `Duplicate key inserted` ).
ENDTRY.
ENDMETHOD.
METHOD append_table.
DATA(lt_base_table) = VALUE tt_unsorted(
( ident = 3 text = `Test 3` )
( ident = 4 text = `Test 4` )
( ident = 5 text = `Test 5` )
).
DATA(lt_append_tab) = VALUE tt_unsorted(
( ident = 9 text = `Test 9` )
( ident = 7 text = `Test 7` )
( LINES OF lt_base_table )
( ident = 6 text = `Test 6` )
).
io_out->write( `Append table into base:` ).
io_out->write( lt_append_tab ).
INSERT VALUE #( ident = 10 text = `Test 10` ) INTO TABLE lt_append_tab.
io_out->write( `After insert into base:` ).
io_out->write( lt_append_tab ).
ENDMETHOD.
METHOD as_parameter.
ENDMETHOD.
METHOD correct_types.
DATA:
lt_char TYPE STANDARD TABLE OF char25 WITH EMPTY KEY,
lt_string TYPE STANDARD TABLE OF string WITH EMPTY KEY.
lt_char = VALUE #( ( 'ABC' ) ( 'DEF' ) ).
io_out->write( `Table with CHAR base:` ).
io_out->write( lt_char ).
lt_string = VALUE #( ( `ABC` ) ( `DEF` ) ).
io_out->write( `Table with CHAR base:` ).
io_out->write( lt_char ).
ENDMETHOD.
ENDCLASS.
Conclusion
The value statement is a lot more powerful than you might think in the first step. With today's tips you can use the full potential of this instruction and know the small and big pitfalls.