01-30-2017 9:13 AM
My scenario is just to fill an internal table from another one within a LOOP with some method calls.
In conventional abap (within release 750), we could've written as follows: -
Source structure Targert structure
field1 field1
field2 field2
field3 field5
field4 field6
LOOP AT source_tab ASSIGNING FIELD-SYMBOL(<lfw_source>)
DATA(lo_instance) = zcl_someclass=>get_instance( <lfw_source>-field1 ).
IF lo_instance IS BOUND.
lv_somedata = lo_instance->meth_somemethod( <lfw_source>-field3 ).
ENDIF.
DATA(lw_target) = CORRESPONDING #( <lfw_source> MAPPING field5 = field4 ).
lw_target-field6 = lv_somedata.
APPEND lw_target TO target_tab.
ENDLOOP.
I tried using VALUE operator to to append moving content of lv_somedata to field6 in the target table, but it gives me an error.
LOOP AT source_tab ASSIGNING FIELD-SYMBOL(<lfw_source>)
DATA(lo_instance) = zcl_someclass=>get_instance( <lfw_source>-field1 ).
IF lo_instance IS BOUND.
lv_somedata = lo_instance->meth_somemethod( <lfw_source>-field3 ).
ENDIF.
target_tab = VALUE #( BASE target_tab
( CORRESPONDING #( <lfw_source> MAPPING field5 = field4 )
field6 = lv_somedata " <--- Doesn't work
)
).
ENDLOOP.
02-01-2017 4:13 PM
TYPES:
BEGIN OF ty_src,
f1 TYPE c LENGTH 4,
f2 TYPE c LENGTH 4,
f3 TYPE c LENGTH 4,
f4 TYPE c LENGTH 4,
END OF ty_src, " ty_src
tt_src TYPE STANDARD TABLE OF ty_src WITH EMPTY KEY.
TYPES:
BEGIN OF ty_trg,
f1 TYPE c LENGTH 4,
f2 TYPE c LENGTH 4,
f5 TYPE c LENGTH 4,
f6 TYPE c LENGTH 4,
END OF ty_trg, " ty_trg
tt_trg TYPE STANDARD TABLE OF ty_trg WITH EMPTY KEY.
DATA:
source_data TYPE tt_src.
START-OF-SELECTION.
" Why is the get_instance( ) inside LOOP?
DATA(processor) = lcl_processor=>get_instance( ).
DATA(target_data)
= VALUE tt_trg(
FOR <src> IN source_data " Iteration over the source data
LET foo = COND #( WHEN processor IS BOUND THEN processor->do_something( <src>-f3 ) ) IN
(
VALUE #(
BASE CORRESPONDING #( <src> MAPPING f5 = f4 )
f6 = foo
)
)
).
My 2 cents ... Now whether the code is elegant or human readable is up for debate 🙂
01-31-2017 8:21 AM
Hi Aasim,
as you most probably know the syntax is
l_itab = value #( base l_itab
( l_new_line )
).
or
l_itab = value #( base l_itab
( field1 = x field2 = y )
).
but cannot be
l_itab = value #( base l_itab
( l_new_line field2 = y )
).
The CORRESPONDING operator constructs a line value that can be used within the VALUE operator but I think that it is not possible to change a single field of this temporary line before it is inserted into the table. So I guess the answer is no - there is no way to achieve what you are trying.
I also tried to create a local line variable within the LET section and change a single field of it immediately afterwards but that also didn't work.
The only way that I currently see to use VALUE is probably not what you are looking for:
target_tab = VALUE #( BASE target_tab
( field1 = <lfw_source>-field1
field2 = <lfw_source>-field2
field5 = <lfw_source>-field4
field6 = lv_somedata )
).
But I also like your first source snippet because it's easy to read and I think there is nothing wrong with it.
Best regards,
Armin
02-01-2017 11:01 AM
Hi Armin,
Oh yes, I do know the syntax for VALUE constructor and tried using LET, too. But it doesn't work that way either.
But wouldn't be great if we had something like this? Just a thought 🙂
Thanks for the time.
01-31-2017 3:52 PM
How about using a mix of old and new...
LOOP AT source_tab ASSIGNING FIELD-SYMBOL(<lfw_source>)
DATA(lo_instance) = zcl_someclass=>get_instance( <lfw_source>-field1 ).
APPEND CORRESPONDING #( <lfw_source> MAPPING field5 = field4 ) TO target_tab
ASSIGNING FIELD-SYMBOL(<newline>).
<newline>-field6 = COND #( WHEN lo_instance IS BOUND
THEN lo_instance->meth_somemethod( <lfw_source>-field3 ) ).
ENDLOOP.
Like Armin, I agree that your first example is pretty elegant and readable to begin with.
Also, if you are trying out elegant coding practices, I suggest you read this https://blogs.sap.com/2014/12/29/abap-modern-code-conventions/. The whole <lfw_source> drives me nuts. As you will read in that blog...
l - yes I know it is local, 99% of your variables should be local
f - the <...> denote that it is a field symbol, why do I need the f to tell me so
w - what's that anyway?
02-01-2017 11:02 AM
Well, it's a matter of taste and also adherence to client naming conventions!
02-01-2017 12:59 PM
As far as client naming conventions - I agree the do, however - they get their information from somewhere. So, I would like to promote the idea that forcing those bad naming conventions on someone is just in bad taste!
02-01-2017 4:13 PM
TYPES:
BEGIN OF ty_src,
f1 TYPE c LENGTH 4,
f2 TYPE c LENGTH 4,
f3 TYPE c LENGTH 4,
f4 TYPE c LENGTH 4,
END OF ty_src, " ty_src
tt_src TYPE STANDARD TABLE OF ty_src WITH EMPTY KEY.
TYPES:
BEGIN OF ty_trg,
f1 TYPE c LENGTH 4,
f2 TYPE c LENGTH 4,
f5 TYPE c LENGTH 4,
f6 TYPE c LENGTH 4,
END OF ty_trg, " ty_trg
tt_trg TYPE STANDARD TABLE OF ty_trg WITH EMPTY KEY.
DATA:
source_data TYPE tt_src.
START-OF-SELECTION.
" Why is the get_instance( ) inside LOOP?
DATA(processor) = lcl_processor=>get_instance( ).
DATA(target_data)
= VALUE tt_trg(
FOR <src> IN source_data " Iteration over the source data
LET foo = COND #( WHEN processor IS BOUND THEN processor->do_something( <src>-f3 ) ) IN
(
VALUE #(
BASE CORRESPONDING #( <src> MAPPING f5 = f4 )
f6 = foo
)
)
).
My 2 cents ... Now whether the code is elegant or human readable is up for debate 🙂
02-01-2017 4:48 PM
I wondered about the the get_instance( ) in the loop too. If you notice the OP does pass the field 1 into the get_instance. Maybe the factory method returns something different based on the contents of field 1, or maybe even nothing if it doesn't like the contents of the field?
Other than that, now that I am getting used to the new ABAP, I find it reasonably readable. Nit-picking on style, personally I would indent the LET too, because it falls within the FOR. I also have not come up with a way of positioning the closing ')' that makes it evident what you are closing. On first look, the close on VALUE looks like it is meant to close the open '(' for the FOR statement right above it. Maybe...
DATA(target_data)
= VALUE tt_trg(
FOR <src> IN source_data " Iteration over the source data
LET foo = COND #( WHEN processor IS BOUND THEN processor->do_meth( <src>-f3 ) ) IN
(
VALUE #(
BASE CORRESPONDING #( <src> MAPPING f5 = f4 )
f6 = foo
)
)
).
Argh... syntax highlighting is not working on this comment for some reason, and the font is a tiny bit larger causing word wrap. Thus a couple of edits!
02-01-2017 6:39 PM
Maybe the factory method returns something different based on the contents of field 1, or maybe even nothing if it doesn't like the contents of the field?
True that, i missed it. OP has 2 choices:
depending on the algorithm.
I also have not come up with a way of positioning the closing ')' that makes it evident what you are closing.
In ADT the opening-closing brackets are highlighted, so it is easier to figure out the context of the functional operator you're in. In ol' SE80, god bless you!
02-01-2017 6:56 PM
In ADT the opening-closing brackets are highlighted
What I have noticed (maybe this is a bug I need to report) is that in more complex scenarios, ADT does not do the highlighting. I did copy your code into an ADT session and did not see the highlighting work. In simpler one off VALUE and COND statements in other code that I have written, it works fine.
In ol' SE80, god bless you!
... and in 'ol 'ol SE80 - I couldn't survive now 🙂
02-01-2017 7:50 PM
Elegance does not always mean the latest fashion. If it highlights your best features, is polished and looks good on you then it's elegant. I'd say that in programming "human readable" should be part of "elegant". So it's not elegant vs. readable. It's elegant and readable vs. blindly following new syntax just for the sake of being hip.
Personally, I dislike some new ABAP constructs for poor readability but maybe I'm just old-fashioned. 🙂 And I agree with others that there is really nothing wrong with OP's code. "Better is enemy of the good". 🙂
02-01-2017 9:11 PM
I just had a real-life example happen this morning. I posted https://answers.sap.com/articles/118824/new-vs-old-abap-elegance-vs-readability-etc.html to move this discussion on to the Coffee Corner. I am sure there will be plenty of opinions!
02-02-2017 2:12 PM
Hi Jelena,
I hate to disagree with you 😞
IMO if someone works with these expressions & operators daily, the construct is pretty straight forward to understand. Not all of them though, i'll give you that.
It's not about showing off, IMO expression based programming makes your code slimmer and compact. But it is addictive and sometimes i tend to overdo things.
But hey programming is an art and there's no "My way or the highway" approach ...
Everytime someone bashes the new programming style, i have the following question for him/her:
Best,
Suhas
02-02-2017 4:43 PM
I wasn't bashing "new programming style", I was just commenting on the subject of "elegance". Old code could be elegant, new code could be elegant, as well as combination of both. As you said, it's an art.
Besides, what even old/new is exactly? E.g. today I still work with a system that is on like 7.01. Even what is described in the old "Next Generation ABAP Development" book is not available there. We still don't have a system with 7.4.
I used "hip" not with regard to the ABAP constructs but to the person using them. In this context, specifically a person who would use them when there is no other practical reason. We've already had this discussion in OOP vs Procedural.
Why can't people embrace? Because most humans simply do not think like that on daily basis. We don't think about applying method "grind" to the object "coffee beans". 🙂 I'd say functional programming is probably easier to grasp than OOP (although I'm starting to get skeptical) but we also don't think like VALUE coffee_beans ( me->grind until ( human=likey) ) and such. That's why to embrace something different one needs to see real value.
And you should not stop learning under any circumstances. If learning is not a priority for the teammates then perhaps you could share with them your knowledge in more condensed format? E.g. I don't always have time to read 700 page design pattern book but I can appreciate someone posting a blog about it (so that I could pretend I read the book 🙂 ). And maybe your teammates could share something with you. Maybe they make great cookies, who knows?
02-09-2017 9:56 AM
target = corresponding #( source
mapping field5 = field4
field6 = cond #(
when zcl_someclass=>get_instance( field1 ) is bound
then zcl_someclass=>get_instance( field1 )->method( field3 ) ) ).
Slightly inelegant in that the instantiation takes place twice. Either wrap the functionality into a static method or leave it as is. If the instance is buffered it should not impact performance.
02-09-2017 10:15 AM
...another option: If not getting an instance invalidates the entire table, then you can ignore the instance bound condition and catch the exception instead:
try.
target = corresponding #( source
mapping field5 = field4
field6 = zcl_someclass=>get_instance( field1 )->method( field3 ) ).
catch cx_sy_ref_is_initial.
"Error handling
endtry.
02-14-2017 9:46 AM