Dynamic Structure Component Expressions
In this blog post I will introduce dynamic structure component expressions. This blog post is a sequel to my previous blog post:
Everything in this section only works since CE 2108 or kernel 7.86. It is not yet contained in any on-premise release.
In the last blog post I introduced several new types of expressions used to dereference data references and dynamically accessing components of structured references.
But there is still a remainder left. What if you are not handling with references at all? What if you have a generic structure, for example a method parameter of TYPE DATA and want to access a specific component of this structure?
These new expressions provide new methods to do just that. Of course you should apply them only in situations when you do not know the exact type of the structure at compile-time, only the name of the component you want to access.
Here is an example of these new Dynamic Structure Component Expressions:
METHODS foo IMPORTING param TYPE data. ... METHOD foo. DATA comp_name TYPE string VALUE `comp`. DATA my_object TYPE REF TO my_class. ... my_object->method( foo-(comp_name) ). ENDMETHOD.
Of course you can do chaining with all other dynamic expressions introduced in my previous blog post:
my_object->method( foo-(comp_name)->(another_comp)-(yet_another_comp)->* ).
You can also use table selectors, like in the following example:
FIELD-SYMBOLS <fs> TYPE any. DATA dyn_key TYPE string VALUE `my_key`. ... <fs>->('comp_name')-('another_comp_name')->*[ (dyn_key) = 17 ] = 5.
It is also possible to use multiple table selectors in the chain, but not every combination is possible yet.
Of course you can also use the in more obscure places, for example to get a component of a class attribute after a CAST or NEW statement:
data(result) = cast my_class( obj )->attribute-(comp_name)
2. Using dynamic structure component expressions in ASSIGN
Everything in this section only works in kernel 787 or ABAP CE 2202.
These new expressions can also be used in the ASSIGN statement:
data struc type struc. field-symbols <fs> type any. assign struc-('comp') to <fs>.
This is a replacement for:
ASSIGN COMPONENT 'COMP' OF STRUCTURE struc TO <FS>.
This latter form is now deprecated. Do not use ASSIGN COMPONENT anymore!
The reason why ASSIGN COMPONENT is dangerous is a serious limitation. It cannot handle chains containing generic references correctly. Here is an example:
types: begin of test, comp type ref to data, end of test. data var type test. create data var-comp type i. assign component 'COMP->*' of structure var to field-symbol(<fs>). " oh: sy-subrc is 4! Why?
In the above example the sy-subrc is 4, because COMP is a generic reference at compile-time. This is very spooky, as we are at runtime when the ASSIGN statement is executed. If COMP would have had TYPE REF TO i, the sy-subrc would be 0!
In old ABAP you had to do the following:
types: begin of test, comp type ref to data, end of test. data var type test. create data var-comp type i. assign component 'COMP' of structure var to field-symbol(<fs>). assign <fs>->* to field-symbol(<fs2>).
For compatibility reasons this cannot be changed anymore.
The above example works correctly when using the new ASSIGN variant:
types: begin of test, comp type ref to data, end of test. data var type test. create data var-comp type i. assign var-('COMP->*') to field-symbol(<fs>). " sy-subrc is 0! Everything ok!
As the new syntax is shorter, more powerful, more consistent with other ASSIGN variants and always yields the correct result, you should abandon ASSIGN COMPONENT in newer ABAP coding in very recent releases.
Of course you can also chain these kinds of expressions inside ASSIGN:
types: begin of struc, comp type ref to i, end of struc. data var type struc. field-symbols <fs>. assign var-('comp')->* to <fs>.
Note however, that the sy-subrc is only set if the last dynamic access in the chain fails. If some access at the beginning or in the middle fails, a runtime error occurs.
The reason for this is to not obscure the errors from longer chains by simply setting a sy-subrc. It is defined that ASSIGN only “inspects” the last element of a chain by setting a sy-subrc. All other chain elements are assumed to be correct.
This is somehow similar to ASSIGN with table selectors, where the sy-subrc is only set when a table line is not contained in the internal table, but not if some other error occurs.