Skip to Content

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

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.
Add comment
10|10000 characters needed characters exceeded

  • Get RSS Feed

6 Answers

  • Best Answer
    Feb 01, 2017 at 04: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 :-)

    Add comment
    10|10000 characters needed characters exceeded

    • 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?

  • Jan 31, 2017 at 08: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

    Add comment
    10|10000 characters needed characters exceeded

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

  • Jan 31, 2017 at 03: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?

    Add comment
    10|10000 characters needed characters exceeded

    • 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!

  • Feb 09, 2017 at 09: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.

    Add comment
    10|10000 characters needed characters exceeded

  • Feb 09, 2017 at 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.
    Add comment
    10|10000 characters needed characters exceeded

  • Feb 14, 2017 at 09:46 AM

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

    Add comment
    10|10000 characters needed characters exceeded