Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
horst_keller
Product and Topic Expert
Product and Topic Expert
What an interesting chain of events: In the new SAP Community all my old blog posts from SDN - the predecessor of SCN (R.I.P.) - are visible again (they were buried in SCN). Now people start looking at those and also ask questions. One question is about handling of invalid references and - dang! - a gap in the documentation was unveiled.Let's fill the gap.

References in reference variables normally are either initial or point to objects.

 

  • For a valid reference, pointing to an object, the predicates IS NOT INITIAL and IS BOUND are both true.

  • An initial reference variable contains the null reference and the predicates IS INITIAL and IS NOT BOUND are true.


Besides those there can be also non initial invalid reference variables for which the predicates IS NOT INITIAL and IS NOT BOUND are true. How can you create invalid references?

Example 1, references pointing to deleted table lines:
DATA itab TYPE TABLE OF i WITH EMPTY KEY.
itab = VALUE #( ( 1 ) ( 2 ) ( 3 ) ).
DATA(dref) = REF #( itab[ 2 ] ).
DELETE itab INDEX 2.
BREAK-POINT.

The debugger says for dref: FREED ITAB:{A:1*\TYPE=I}.

Example 2, references pointing to deleted stack objects:
CLASS cls DEFINITION.
PUBLIC SECTION.
CLASS-DATA dref TYPE REF TO i.
CLASS-METHODS main.
ENDCLASS.

CLASS cls IMPLEMENTATION.
METHOD main.
DATA number TYPE i.
dref = REF #( number ).
ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
cls=>main( ).
BREAK-POINT.

The debugger says for cls=>dref: FREED STACK:{A:1*\TYPE=I}.

Unfortunately the behavior of such invalid references was not fully described until now. In fact it is quite similar to the behavior of initial null references:

 

  • For non initial invalid references as well as for initial references the predicate IS BOUND is false.

  • You cannot access objects via non initial invalid references or initial references (that's trivial).


Interestingly enough, you can assign non initial invalid references as well as initial references to any reference variable using down casts. The reason is, that those references don't have a dynamic type that can be checked.

But there is one difference. While the initial null reference can be compared to valid references (and is always smaller), non initial invalid references cannot be compared with any other references. There is no sort order defined for non initial invalid references. Any attempt to compare a non initial invalid reference leads to a runtime error SYSTEM_DATA_ALREADY_FREE.
DATA itab TYPE TABLE OF i WITH EMPTY KEY.
itab = VALUE #( ( 1 ) ( 2 ) ( 3 ) ).
DATA(dref) = REF #( itab[ 2 ] ).
DELETE itab INDEX 2.

DATA ref TYPE REF TO data.
IF dref = ref. "<- Crash!
ENDIF.

What you can use is:
IF dref IS NOT INITIAL AND
dref IS NOT BOUND.
ENDIF.

That you cannot compare non initial invalid references has an important impact on internal tables containing columns of references (and that was the question)! If an internal table contains non initial invalid references any table operation that involves comparisons of those will lead to the above runtime error. That concerns WHERE conditions, sortings, access via sorted keys, ...
DATA itab TYPE TABLE OF i WITH EMPTY KEY.
itab = VALUE #( ( 1 ) ( 2 ) ( 3 ) ).
DATA(dref) = REF #( itab[ 2 ] ).
DELETE itab INDEX 2.

DATA rtab TYPE TABLE OF REF TO i WITH EMPTY KEY.
APPEND dref TO rtab.
APPEND INITIAL LINE TO rtab.
SORT rtab BY table_line. "<- Crash!

Now the question arises, wouldn't it make sense to define a sort order for non initial invalid references? Currently, the answer is no (sorry slobodchikovius). Why? Because any time a reference variable becomes invalid, e.g. when leaving a procedure, each internal table that contains the reference variable as part of a sorted key must then be reorganized. Or with other words, the internal organization of internal tables must react on non internal table statements. And that is not wanted.

Seen from this angle, one can say that it is not the best idea to declare sorted keys that contain reference variables as key fields.
DATA itab TYPE SORTED TABLE OF REF TO data
WITH NON-UNIQUE KEY table_line.

DATA jtab TYPE STANDARD TABLE OF REF TO data
WITH NON-UNIQUE SORTED KEY ref COMPONENTS table_line.

Usage of those can lead to unexpected runtime errors if non initial invalid references are involved.

To prevent such runtime errors, you can use:
DELETE itab WHERE table_line IS NOT BOUND.

PS: Maybe it would be better, if there wasn't a sort order for references at all and reference variables wouldn't be alllowed as key fields of internal tables.
7 Comments