The reason why your code works with a field symbol but not a data object is because of how those two deal with data in memory in a different way. There are similar concepts in C++, even though naming in ABAP is a bit confusing when you are used to C++:
In ABAP a field symbol is a bit like a reference in C++ (or like a dereferenced C++ pointer, as SAP calls it). It does not allocate memory for its own data, but rather refers to some existing field / data object. After assigning a data object to the field symbol, if you access that data object via the field symbol, then you don't ever talk to the field symbol itself, but always to the data object directly! (This is the crucial part in your case, as we see in a bit.)
Now in your first example you create the field symbol, which does nothing yet:
FIELD-SYMBOLS: <lfs_struct> TYPE REF TO DATA.
Only after creating the new line for your internal table and assigning that newly allocated memory to your field symbol <lfs_struct>
, the field symbol points to some data (the table line). Then you allocate some more memory dynamically:
CREATE DATA <lfs_struct> TYPE (<lfs_field>-segnam).
Now your internal table ei_lines
points to the newly appended table line (memory address), as does your field symbol. That memory address in turn points to the newly created data from CREATE DATA
. Important to note is that, as said, you don't access the field symbol itself, but the memory where it refers to!
In the second example however you first allocate memory for a new data object:
DATA: lo_struct TYPE REF TO data.
Then again you allocate new memory for a new table line (APPEND
) and put a reference to that memory address into your data object lo_struct
. Now the interesting part: You dynamically create another data (object) and save the pointer to that new data into lo_struct
. Thus now lo_struct
doesn't refer to the new table line any longer, but to the newly created data from CREATE DATA
.
TL;DR In the first example you CREATE DATA
and save the reference to that data into the object where your field symbol <lfs_struct>
refers to, which is the new table line in ei_lines
. In the second example, however, you also create a new table line and refer to it via lo_struct
, but when you CREATE DATA
afterwards, you store the reference to that new data again into lo_struct
, thus overwriting the original reference to the new table line.