11-24-2017 11:09 AM
Today I stumbled across an unexpected behaviour in a reduce table expression and couldn't find any hint in the documentation.
Consider these two reduce operations.
TYPES: BEGIN OF ty_output,
head TYPE string,
position TYPE string,
END OF ty_output.
SELECT FROM t100
FIELDS *
WHERE sprsl = @sy-langu
ORDER BY PRIMARY KEY
INTO TABLE @DATA(t100_tab)
UP TO 10 ROWS.
DATA(output) = REDUCE ty_output( INIT result = VALUE ty_output( )
FOR GROUPS group OF ls_t100 IN t100_tab
INDEX INTO index
GROUP BY ( arbgb = ls_t100-arbgb
msgnr = ls_t100-msgnr )
FOR <ls_t100> IN GROUP group
NEXT result = VALUE #( position = result-position && |\n{ <ls_t100>-text }| ) ). " <=== difference here
DATA(output2) = REDUCE ty_output( INIT result = VALUE ty_output( )
FOR GROUPS group OF ls_t100 IN t100_tab
INDEX INTO index
GROUP BY ( arbgb = ls_t100-arbgb
msgnr = ls_t100-msgnr )
FOR <ls_t100> IN GROUP group
NEXT result-position = result-position && |\n{ <ls_t100>-text }| ). " <=== difference here
" fails:
* ASSERT output = output2.
cl_demo_output=>write( output-position ).
cl_demo_output=>write( output2-position ).
cl_demo_output=>display( ).
I expected that both return the same value. They don't.
Can anybody explain that? Is that documented somewhere?
Maybe horst.keller is around 😉
Thanks.
Christian
P.s. You can also find the code in this abapGit repo.
11-24-2017 1:42 PM
Hi Christian
This is just a semi-educated guess but I think that OUTPUT only gets the last message in the internal table due to the VALUE #( ) operator in the last line of the first REDUCE statement.
NEXT result = VALUE #( position = result-position && |\n{ <ls_t100>-text }| ) )
My understanding of the VALUE operator is that it initialises the left hand side (in your case, the RESULT structure) *before* it constructs the right hand side. So RESULT-POSITION is always empty when it concatenates the next message.
The second REDUCE doesn not use the VALUE operator and so doesn't clear the RESULT structure in each iteration... resulting in a longer string.
Of course, I could be wrong. 🙂
Regards
Glen
11-24-2017 1:42 PM
Hi Christian
This is just a semi-educated guess but I think that OUTPUT only gets the last message in the internal table due to the VALUE #( ) operator in the last line of the first REDUCE statement.
NEXT result = VALUE #( position = result-position && |\n{ <ls_t100>-text }| ) )
My understanding of the VALUE operator is that it initialises the left hand side (in your case, the RESULT structure) *before* it constructs the right hand side. So RESULT-POSITION is always empty when it concatenates the next message.
The second REDUCE doesn not use the VALUE operator and so doesn't clear the RESULT structure in each iteration... resulting in a longer string.
Of course, I could be wrong. 🙂
Regards
Glen
11-24-2017 2:49 PM
Yes, that would be a reasonable explanation. But it came a bit as a surprise to me. Therefore I hoped to find something about in the documentation. But hadn't any luck yet.
11-24-2017 5:06 PM
11-24-2017 2:59 PM
11-24-2017 5:00 PM
Yep, that's it.
And we have the BASE or LET addition, to circumvent that.
There are examples in the documentation too.
11-27-2017 7:29 AM
Thanks to Glens and Horsts answers I was able to solve my issue with the base addition of the value constructor expression. I updated the repo if anybody is interested.
DATA(output) = REDUCE ty_output( INIT result = VALUE ty_output( )
FOR GROUPS group OF ls_t100 IN t100_tab
INDEX INTO index
GROUP BY ( arbgb = ls_t100-arbgb
msgnr = ls_t100-msgnr )
FOR <ls_t100> IN GROUP group
NEXT result = VALUE #( BASE result
position = result-position && |\n{ <ls_t100>-text }| ) ). " <=== solution with base
* NEXT result = VALUE #( position = result-position && |\n{ <ls_t100>-text }| ) ). " <=== difference here