
ABAP - Assign
In this article, we'll look at different variations of ASSIGN and how you can use them in ABAP in everyday life to make your development more effective.
Table of contents
In this article, we'll discuss working with field symbols and how you can use them in everyday life. We'll look at various processing examples.
Introduction
The ASSIGN statement has been around for a long time in ABAP development and is part of an ABAP developer's standard toolbox. We typically work with a field symbol that represents a reference to a real variable. Field symbols and references are both pointers that don't contain real values, but point to a memory address with a real value.
Preparation
For the following examples, we'll use two structures with the respective types in tabular form. A simple structure contains the fields A to E, and we create a mapping that we will need later when we process the structure dynamically.
TYPES: BEGIN OF simple_mapping,
field TYPE string,
value TYPE string,
END OF simple_mapping.
TYPES simple_mappings TYPE STANDARD TABLE OF simple_mapping WITH EMPTY KEY.
TYPES: BEGIN OF simple_structure,
a TYPE string,
b TYPE string,
c TYPE string,
d TYPE string,
e TYPE string,
END OF simple_structure.
TYPES simple_table TYPE STANDARD TABLE OF simple_structure WITH EMPTY KEY.
Processing
There is also an inline declaration for field symbols, such as those you can use with a LOOP or an ASSIGN, for example. In this example, we use a field symbol instead of a normal structure. The advantage of this version is also performance, since we don't have to copy the data from the table into the structure; only the pointer is changed.
LOOP AT examples ASSIGNING FIELD-SYMBOL(<line>).
out->write( <line> ).
ENDLOOP.
In this scenario, however, you need to be careful, as you now have a pointer. Using this pointer, you can directly adjust and change the data in the table. In this example, we set a new value for column C and overwrite the old one.
LOOP AT examples ASSIGNING FIELD-SYMBOL(<line>).
<line>-c = `New Value`.
ENDLOOP.
Basically, you can easily adjust a lot of data or add more information to the table without having to write the data back into the table.
Component
Let's take just one structure of our table, for example. If you want to process a structure dynamically, various methods are available. For example, you can analyze the structure using RTTI to process the various fields. In the following example, we use an ASSIGN COMPONENT, which allows us to assign a single field to a field symbol.
DO.
ASSIGN COMPONENT sy-index OF STRUCTURE example TO FIELD-SYMBOL(<field>).
IF sy-subrc <> 0.
EXIT.
ENDIF.
result &&= <field>.
ENDDO.
There are currently two rules for assignment:
- Numeric - If the value behind COMPONENT is numeric, then the x-th field of the structure is assigned to the field symbol.
- Character - If the value consists of characters, then a field with the same name is searched for in the structure and then assigned to the field symbol.
In the example above, we process the fields from the 1st to the last field. If we now try to assign a field that no longer exists, the SY-SUBRC is set. In this case, we exit the loop and complete processing.
Mapping
In the next example, we'll work with a mapping and want to point out the dangers of this method. The mapping contains a field that doesn't currently exist in the structure.
METHOD get_mappings.
RETURN VALUE #( ( field = `a` value = `101` )
( field = `b` value = `102` )
( field = `f` value = `103` )
( field = `d` value = `104` )
( field = `e` value = `105` ) ).
ENDMETHOD.
Error Case
In the following example, we create an error in processing that will go unnoticed. We get the mapping from the method and process it against our structure.
LOOP AT get_mappings( ) INTO mapping.
ASSIGN COMPONENT mapping-field OF STRUCTURE example TO <field>.
<field> = mapping-value.
ENDLOOP.
At the third position of the mapping, the field can no longer be mapped. The SUBRC is now set. However, the field symbol remains on the second field. We are thus overwriting the second field with an incorrect value and have unnoticed generated an error.
Solution
To avoid making such mistakes again, we should react when an error occurs. In classic development, we would now check the SUBRC to see if the assignment worked. In such a case, we can skip the current line and continue processing on the next one.
LOOP AT get_mappings( ) INTO mapping.
ASSIGN COMPONENT mapping-field OF STRUCTURE example TO <field>.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
<field> = mapping-value.
ENDLOOP.
A relatively new variant is the ELSE UNASSIGN addition. If an error occurs, the field symbol is initialized, preventing the incorrect value from being overwritten. In such a case, we can then check whether the element is set without the SUBRC. This means we are no longer dependent on the system field, but can reference the element directly.
LOOP AT get_mappings( ) INTO mapping.
ASSIGN COMPONENT mapping-field OF STRUCTURE example TO <field> ELSE UNASSIGN.
IF <field> IS NOT ASSIGNED.
CONTINUE.
ENDIF.
<field> = mapping-value.
ENDLOOP.
Result
Let's take a look at the results of the three variants. Column C always remains empty, and only in the first case does column B have an incorrect value. Therefore, you should always ensure proper error handling in such situations.
Assignment
Let's look at two more assignments in the context of references. In older releases, you usually have to assign a reference to a field symbol before you can process the table, for example. The field symbol must also be of type TABLE, otherwise the compiler will issue an error.
ASSIGN local_reference->* TO FIELD-SYMBOL(<table>).
LOOP AT <table> ASSIGNING <line>.
out->write( <line> ).
ENDLOOP.
In a current release, you can save yourself the trouble and go directly via the reference. Here, the system only checks at runtime whether the reference is a table.
LOOP AT local_reference->* ASSIGNING <line>.
out->write( <line> ).
ENDLOOP.
New Features
In this article, we've also incorporated three new features and special features that are possible in current releases and that didn't really work before.
- Upper and lowercase - With ASSIGN COMPONENT, we use lowercase fields as references. Previously, the field name always had to be specified in uppercase, otherwise the field wouldn't be found. This no longer matters.
- Inline Declaration - When assigning the reference to the field symbol, we used an inline declaration. This would be of type ANY and therefore couldn't be used for the loop. This is also no longer a problem in a current release.
- Reference - We were also able to loop directly over de-referencing (->*) during assignment, without a field symbol or assignment. This makes direct use of references easier, as the type check only occurs at runtime.
Complete Example
If you would like to try out the example, you can find the complete executable class here. As described above in the special features, it may not be possible to activate it on your release.
CLASS zcl_bs_demo_assign DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PRIVATE SECTION.
TYPES: BEGIN OF simple_mapping,
field TYPE string,
value TYPE string,
END OF simple_mapping.
TYPES simple_mappings TYPE STANDARD TABLE OF simple_mapping WITH EMPTY KEY.
TYPES: BEGIN OF simple_structure,
a TYPE string,
b TYPE string,
c TYPE string,
d TYPE string,
e TYPE string,
END OF simple_structure.
TYPES simple_table TYPE STANDARD TABLE OF simple_structure WITH EMPTY KEY.
METHODS get_examples
RETURNING VALUE(result) TYPE simple_table.
METHODS get_example
RETURNING VALUE(result) TYPE simple_structure.
METHODS get_mappings
RETURNING VALUE(result) TYPE simple_mappings.
METHODS assign_in_loop
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS change_with_fieldsymbol
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS loop_structure
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS do_mapping
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS assign_reference
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.
CLASS zcl_bs_demo_assign IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
assign_in_loop( out ).
change_with_fieldsymbol( out ).
loop_structure( out ).
do_mapping( out ).
assign_reference( out ).
ENDMETHOD.
METHOD get_examples.
RETURN VALUE #( ( a = `1` b = `2` c = `3` d = `4` e = `5` )
( a = `6` b = `7` c = `8` d = `9` e = `10` )
( a = `11` b = `12` c = `13` d = `14` e = `15` )
( a = `16` b = `17` c = `18` d = `19` e = `20` ) ).
ENDMETHOD.
METHOD get_example.
RETURN VALUE #( a = `1`
b = `2`
c = `3`
d = `4`
e = `5` ).
ENDMETHOD.
METHOD get_mappings.
RETURN VALUE #( ( field = `a` value = `101` )
( field = `b` value = `102` )
( field = `f` value = `103` )
( field = `d` value = `104` )
( field = `e` value = `105` ) ).
ENDMETHOD.
METHOD assign_in_loop.
DATA(examples) = get_examples( ).
LOOP AT examples ASSIGNING FIELD-SYMBOL(<line>).
out->write( <line> ).
ENDLOOP.
ENDMETHOD.
METHOD change_with_fieldsymbol.
DATA(examples) = get_examples( ).
LOOP AT examples ASSIGNING FIELD-SYMBOL(<line>).
<line>-c = `New Value`.
ENDLOOP.
out->write( examples ).
ENDMETHOD.
METHOD loop_structure.
DATA(example) = get_example( ).
DATA(result) = ``.
DO.
ASSIGN COMPONENT sy-index OF STRUCTURE example TO FIELD-SYMBOL(<field>).
IF sy-subrc <> 0.
EXIT.
ENDIF.
result &&= <field>.
ENDDO.
out->write( result ).
ENDMETHOD.
METHOD do_mapping.
DATA mapping TYPE zcl_bs_demo_assign=>simple_mapping.
DATA example TYPE simple_structure.
FIELD-SYMBOLS <field> TYPE data.
LOOP AT get_mappings( ) INTO mapping.
ASSIGN COMPONENT mapping-field OF STRUCTURE example TO <field>.
<field> = mapping-value.
ENDLOOP.
out->write( example ).
CLEAR example.
LOOP AT get_mappings( ) INTO mapping.
ASSIGN COMPONENT mapping-field OF STRUCTURE example TO <field>.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
<field> = mapping-value.
ENDLOOP.
out->write( example ).
CLEAR example.
LOOP AT get_mappings( ) INTO mapping.
ASSIGN COMPONENT mapping-field OF STRUCTURE example TO <field> ELSE UNASSIGN.
IF <field> IS NOT ASSIGNED.
CONTINUE.
ENDIF.
<field> = mapping-value.
ENDLOOP.
out->write( example ).
ENDMETHOD.
METHOD assign_reference.
FIELD-SYMBOLS <line> TYPE zcl_bs_demo_assign=>simple_structure.
DATA(examples) = get_examples( ).
DATA(local_reference) = REF #( examples ).
ASSIGN local_reference->* TO FIELD-SYMBOL(<table>).
LOOP AT <table> ASSIGNING <line>.
out->write( <line> ).
ENDLOOP.
LOOP AT local_reference->* ASSIGNING <line>.
out->write( <line> ).
ENDLOOP.
ENDMETHOD.
ENDCLASS.
Conclusion
The ASSIGN still helps ensure reliable generic processing and adapt content quickly and reliably. You'll have to get used to it a bit at first, but the benefits are greater and will quickly become second nature.