Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

Is there any elegant way to rewrite below code snippet in 740/750?

aasim_khan
Participant
0 Kudos

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.
1 ACCEPTED SOLUTION

SuhaSaha
Advisor
Advisor
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 🙂

16 REPLIES 16

Armin_Beil
Product and Topic Expert
Product and Topic Expert

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

0 Kudos

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.

raghug
Active Contributor

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?

0 Kudos

Well, it's a matter of taste and also adherence to client naming conventions!

raghug
Active Contributor

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!

SuhaSaha
Advisor
Advisor
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 🙂

raghug
Active Contributor
0 Kudos

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!

0 Kudos

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:

  1. Define the instance as an auxiliary variable of the FOR operator,
  2. Define the instance as an auxiliary variable of the COND operator,

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!

raghug
Active Contributor
0 Kudos

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 🙂

Jelena
Active Contributor

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". 🙂

raghug
Active Contributor
0 Kudos

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!

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:

  • Why is the new ABAP construct branded as "hip"?
  • Why can't people embrace the fact that there is a paradigm shift towards functional programming in ABAP and accept it?
  • Why should i stop learning the new ABAP because my teammates don't want to invest their time in it?

Best,

Suhas

Jelena
Active Contributor

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?

pokrakam
Active Contributor
0 Kudos
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.

pokrakam
Active Contributor
0 Kudos

...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.

aasim_khan
Participant
0 Kudos

Thanks, Suhas! I didn't know 'bout BASE CORRESPONDING yet.