The most important news for internal tables are the Table expressions that allow the same single line access as the READ TABLE statement. But soon after those were available, the question arised “What about the system fields?”.

We all use the well known patterns

READ TABLE … TRANSPORTING NO FIELDS.

IF sy-subrc = 0.

  …

ENDIF.

READ TABLE … TRANSPORTING NO FIELDS.

DATA(idx) = sy-tabix.

Since an expression should be free of side effects it especially should not influence any system field. So what about these patterns?

The answer comes in form of two new built-in functions.

Line existence

A new predicate function that returns true if a line exists:

IF line_exists( itab[ … ] ).

ENDIF.

Where itab[ … ] is a table expression that works here like READ TABLE … TRANSPORTING NO FIELDS.

(Note that we have already some other predicate functions in ABAP: matches and the contains-variants in the context of string processing).

Line index

A new table function that returns the number of the line in the index used (primary or secondary index):

DATA(idx)= line_index( itab[ … ] ).

Where itab[ … ] is a table expression that works here like READ TABLE … TRANSPORTING NO FIELDS. If no line is found, the value 0 is returned. For Hash-Tables or hashed secondary keys, always the value -1 is returned.

(Note that this is the second table function in ABAP. The other one is lines).

To report this post you need to login first.

27 Comments

You must be Logged on to comment or reply to a post.

  1. Uwe Fetzer

    A short question to the predicate functions, and I don’t know whether you are able / allowed to answer or not:

    The result of a predicate function is always a truth value, but

    A data type for Boolean data objects to take truth values is currently not supported.

    (see http://help.sap.com/abapdocu_702/en/abenlogical_value_glosry.htm )

     

    If we want to create our own predicate functions we need such a type. Is it planned in the (near) future?

    (0) 
    1. Horst Keller Post author

      This old question …

       

      A Boolean data type is in discussion, planned since I am in  the ABAP group – and this is quite a time. To be honest, I can’t fullly explain why it isn’t done yet. One reason can be that any introduction of a new built-in type is dangeroius for compatibility. If we introduce a type named “boole” or “boolean” you will have naming collisions with self defined types in ABAP programs or in the Dictionary of that name. We made that experience recently with int8. int8 could be introduced in the NGAP release (8.x) because this ABAP release is not downward compatible. But up to now int8 did not find its way into 7.40.

       

      For the time being you still have two work with type c length 1 aka abap_bool with values abap_true and abap_false as workaround. The Boolean functions boolc and boolx also support this access.

       

      But since you will participate in our TechEd session as a mentor this year, you will very probalbly have the chance to discuss that with us directly

      (0) 
      1. Uwe Fetzer

        Yes, indeed, this is an old question, and I’ll repeat this question for every new release. Promised

        Sure, we can handle it with a workaround, but in my opinion the kernel could do the same (is the returning parameter initial -> false else true). We don’t really need a new datatype.

         

        See you in Amsterdam (finally )

        (0) 
        1. Volker Wegert

          the kernel could do the same (is the returning parameter initial -> false else true)

           

                             

          This won’t work in all cases – take for example ISH_TRUE_FALSE which is a CHAR value with ‘0’ signifying false and ‘1’ signifying true. The initial value would be ‘ ‘…

          (0) 
          1. Horst Keller Post author

            Yep, only a real Boolean would really help. Problem is that too many and different workarounds can be found.

             

            B.T.W.,  price question, what is the result of

             

            IF boolc( 1 = 2 ) = abap_false.

             

            True or false and why?

             

            (0) 
            1. Uwe Fetzer

              I don’t think we need a workaround here. Every expression (let it be a variable or a returning parameter) which is not initial is true like in most of the other languages.

               

              boolc( 1 = 2 ) = abap_false

              is false because boolc is a string and abap_false is a char with length 1.

              (0) 
  2. Ankit Sharma

    Hi Horst,

     

    For moving data from one Internal Table to another, of same type,

    we are having a handy option,

     

    itab_1[] = itab_2[].

     

    But the we do not have any similar syntax, to move data from

    one Internal Table to another, of different type, as we have

    for work areas ,

     

    move-corresponding ls_tab_1 to ls_tab_2.

     

    Just wondering,

    why can not we have such function even for Internal Tables,

    or else if we do already have some similar syntax,

    please post.

     

    Thanking You All.

    (0) 
  3. Jacques Nomssi

    Hello Horst,

     

    which idiom would recommend for the ubiquitous SY-SUBRC check after a READ TABLE ?


    TRY.

           rv_msg = mt_return[ 1 ]message.

           CATCH cx_sy_itab_line_not_found.

             CLEAR rv_msg.

    ENDTRY.


    or


    IF line_exists( mt_return[ 1 ] ).

       rv_msg = mt_return[ 1 ]message.

    ELSE.

      CLEAR rv_msg.

    ENDIF.

     

    or anything else?

     

    regards,

     

    JNN

    (0) 
    1. Horst Keller Post author

      Before 7.40, SP08 you only have the above two and I would recommend line_exists.

       

      With 7.40, SP08 there will be

       

      VALUE #( mt_return[ 1 ]message DEFAULT def ) and

      VALUE #( mt_return[ 1 ]message OPTIONAL )

       

      For non-existing lines you can define your own default value and check the result for that one.

       

      rv_msg = VALUE #( mt_return[ 1 ]message DEFAULT def ).

      IF rv_msg = def.

         …

      ENDIF.

       

      Or in your case above, you simply denote the initial value a follows:

       

      rv_msg = VALUE #( mt_return[ 1 ]message OPTIONAL ).

       

      Best

       

      Horst

      (0) 
  4. Jacques Nomssi

    Hello Horst,

     

    what is the differene between a table function and a functional operand? e.g. error message Arithmetic calculation not permitted here is triggered for

     

         MESSAGE s542(>4) WITH lines( mt_data[] ).


    I can use

     

    DATA(lv_count) = lines( mt_data[] ).

         MESSAGE s542(>4) WITH lv_count


    but it is legal to write


    MESSAGE s035(mv) WITH lo_stream->get_filename( ).


    so why can’t I use a table function in an expression at a functional operand position? It seems to me it works in some contexts, but I could not find a reference yet.


    regards,


    JNN

    (0) 
    1. Horst Keller Post author

      Hi Jacques,

       

      Unfortunately, this is a little bit tricky because ABAP is growing very evolutionary and especially for operand positions it is not always clear what you can place there.

       

      But fortunately, you have (my) documentation which (at least) tries to describe it right for all these possibilities.

       

      In your case, you can look up  MESSAGE …WITH :

      If the data type is character-like, then dobj1 through dobj4 are character-like expression positions; if it is not character-like, they are functional operand positions.

       

      Well, in your first example “lines( mt_data[] ).” as a built-in function is neither character-like nor an operand for a functional operand position.

       

      For built-in functions you need a general expression position.

       

      But you can also make it easily character-like:

       

      … WITH |{ lines( mt_data[] ) }|.

      (0) 
  5. Amadeus Grabmayer

    Hi Horst,

     

    this might be a dumb question, but why is it not supported to return the value of “line_exists”?

     

    I get an error if I try the following:

    rv_assigned = line_exists( lt_roles[ table_line = iv_role ] ).

     

    The following works (obviously), but an IF is actually what I wanted to avoid due to the table function.

    IF line_exists( lt_roles[ table_line = iv_role ] ).

      rv_assigned = abap_true.

    ENDIF.

     

    (I am currently on a System with 7.40 SP7)

     

    Regards,

    Amadeus

    (0) 
    1. Horst Keller Post author

      Hello Amadeus,

       

      This touches the old question (discussed many times) of Boolean types in ABAP.

       

      ABAP does not support a real boolean type and I guess it will never do.

       

      Therefore, you cannot assign a relational expression (and that’s what the predicate function LINE_EXISTS is) to a variable but you can use it only where logical expressions are evaluated (behind IF and …).

       

      As a workaround, you can use

      flag = line_index( itab[ … ] ).

      A value 0 in flag means not assigned.

       

      Cheers!

       

      Horst

      (0) 
      1. Amadeus Grabmayer

        Hello Horst,

         

        thank you for your quick reply!

         

        So the one-liner (that I get a ABAP_BOOL value) would be the following?

        rv_bool = boolc( line_index( itab[…] ) GT 0 ).

         

        Regards,

        Amadeus

        (0) 
  6. Guyon Cumby

    Would it make sense to permit functions such as:

     

    IF ( line_exists( lt_serial_tc[ sernr <> 0 ] ) ).

    ENDIF.


    or is there a more obvious way than this?

    (0) 
    1. Horst Keller Post author

      Would it make sense

      Yes, but unfortunately not supported since table expressions work like READ TABLE and READ TABLE does not support arbitrary logical expressions.


      or is there a more obvious way than this?


      No …



      (0) 

Leave a Reply