Skip to Content
Author's profile photo Horst Keller

ABAP News for Release 7.40 – New Internal Table Functions

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

Assigned Tags

      39 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Uwe Fetzer
      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?

      Author's profile photo Horst Keller
      Horst Keller
      Blog 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

      Author's profile photo Uwe Fetzer
      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 )

      Author's profile photo Former Member
      Former Member

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

      Author's profile photo Horst Keller
      Horst Keller
      Blog 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?

       

      Author's profile photo Uwe Fetzer
      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.

      Author's profile photo Uwe Fetzer
      Uwe Fetzer

      Hint for the others:

      boolc( 1 = 2 ) = ` ` is true

      boolc( 1 = 2 ) = ' ' is false

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author
      Author's profile photo Uwe Fetzer
      Uwe Fetzer

      ISH_TRUE_FALSE is always true because it is not initial.

      Author's profile photo Former Member
      Former Member

      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.

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Already posted: http://scn.sap.com/community/abap/blog/2013/05/29/abap-news-for-release-740--bye-bye-move-and-compute#comment-380325

       

      B.T.W., instead of itab_1[] = itab_2[] you can simply write itab_1 = itab_2 as long as the tables don't have header lines (as it is always the case in classes).

      Author's profile photo Former Member
      Former Member

      Thanks Horst.

       

      Thanking You All.

      Author's profile photo Jacques Nomssi Nzali
      Jacques Nomssi Nzali

      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

      Author's profile photo Horst Keller
      Horst Keller
      Blog 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

      Author's profile photo Jacques Nomssi Nzali
      Jacques Nomssi Nzali

      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

      Author's profile photo Horst Keller
      Horst Keller
      Blog 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[] ) }|.

      Author's profile photo Amadeus Grabmayer
      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

      Author's profile photo Horst Keller
      Horst Keller
      Blog 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

      Author's profile photo Amadeus Grabmayer
      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

      Author's profile photo Uwe Fetzer
      Uwe Fetzer

      .. or you can use

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


      to prevent the IF statement.

      Author's profile photo Amadeus Grabmayer
      Amadeus Grabmayer

      Now that I see it, it totally makes sense

       

      Thanks you for the hint/idea

      Author's profile photo Former Member
      Former Member

      Shouldn't that be xsd_boolc if rv_assigned is an abap_bool? Mr. Keller blogged about this recently.

      Author's profile photo Amadeus Grabmayer
      Amadeus Grabmayer

      Hi Jürgen,

       

      Technically that would be right (I read the mentioned blog), but as I stated I'm on a system with 7.40 SP7 and the referred function "xsdbool" is only available from SP8 onwards: http://help.sap.com/abapdocu_740/en/abennews-740_sp08-expressions.htm#!ABAP_MODIFICATION_2@2@

       

      Regards,

      Amadeus

      Author's profile photo Guyon Cumby
      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?

      Author's profile photo Horst Keller
      Horst Keller
      Blog 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 ...



      Author's profile photo Ramesh Raja R
      Ramesh Raja R

      Hello Horst,

       

      What is the difference between the above table expression and Read table? In which case we go for which one?

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author
      Author's profile photo Guru Anandh Ramakrishnan
      Guru Anandh Ramakrishnan

      Hi,

       

      Thanks for the informative blog. I  have a question..

       

      Is it possible to have dynamic string clause within line_index statement?

      For example something like

       

      FIELD-SYMBOLS:   <fs_t_data>   TYPE table.

      // Some logic to determine lv_string_key which is the row key

      line_index<fs_t_data>[ lv_string_key ] ).

       

      Also,

      How do we get the index/tabix for the ‘for loop’ in a statement below?

      Currently sy-index/sy-tabix does not return the correct row of wa.

      rt_selected_lines VALUE (BASE rt_selected_lines FOR wa IN <fs_t_data> WHERE (lv_string_keytabixsyindex )  ).

       

      Thanks & Best Regards,

      Guru

       

       

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      line_index<fs_t_data>[ lv_string_key ] ).

      https://help.sap.com/http.svc/rc/abapdocu_751_index_htm/7.51/en-US/index.htm?file=abentable_exp_itab_line.htm

      How do we get the index/tabix for the ‘for loop’ in a statement below?

      https://help.sap.com/http.svc/rc/abapdocu_751_index_htm/7.51/en-US/index.htm?file=abenfor_itab.htm

       

       

      Author's profile photo Guru Anandh Ramakrishnan
      Guru Anandh Ramakrishnan

      Hi Horst,

      Thanks a lot for the quick feedback.

       

      The second problem is now solved with INDEX INTO . Thanks a lot for the reference..  🙂

       

      However, I still get the error in first one. To elaborate, my code looks something like this

      FIELD-SYMBOLS:   <fs_t_data>   TYPE table.  // This is a dynamic table whose structure is known only at runtime

      // A dynamic runtime logic results in lv string_key values as below that uniquely identifies one row of <fs_t_data>

      lv_string_key = 'field1 = value1 field2 = value2'.

       

      line_index<fs_t_data>[ lv_string_key ] ).  // I get an error here..

      line_index( <fs_t_data>[ KEY lv_string_key ] ).  // I tried with prefix KEY as well.. I still get an error

       

      We are on NW750 SP 005. 

      Could you please help?

       

      Thanks & Regards,

      Guru

       

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Seems that you haven’t read the documentation I sent you.

      Is there a dynamic clause for table expressions? No. Is there a dynamic clause for READ TABLE? No. And now the sixty–four–dollar question: Where do we have a dynamic clause for reading internal tables?

      Author's profile photo Guru Anandh Ramakrishnan
      Guru Anandh Ramakrishnan

      Sixty-four-dollar answer.. 🙂

      I know READ TABLE does not support dynamic clause.

      However,  I was trying to understand whether the newer syntax supports a dynamic clause so that we can avoid a LOOP statement that supports dynamic where clause.

      Thanks a lot for your response Horst..

      Best Regards,

      Guru

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Yep, sometimes one really wonders  ...

      Author's profile photo Sunil Sankar
      Sunil Sankar

      Hi All,

      Do we have CONTINUE like statement which can be used in FOR loop to do nothing in a COND -> ELSE block?


      SPAN {
      font-family: "Courier New";
      font-size: 10pt;
      color: #000000;
      background: #FFFFFF;
      }
      .L0S32 {
      color: #3399FF;
      }
      .L0S52 {
      color: #0000FF;
      }
      .L0S55 {
      color: #800080;
      }
      .L0S70 {
      color: #808080;
      }
      lt_sect VALUE lty_sectBASE lt_sect  FOR ws IN results INDEX INTO l_cntr
      LET  l_nrec VALUE #results[ l_cntr + ]-line OPTIONAL )
      l_trow VALUE #p_gt_raw_data[ l_nrec ]-row OPTIONAL )
      l_crow p_gt_raw_data[ ws-line ]-row
      l_prow ws-line 39
      l_sect p_gt_raw_data[ l_prow ]-value+0(10)  IN
      COND #WHEN l_sect IS NOT INITIAL THEN
      VALUE #sec   l_sect
      frm   l_crow + 1
      to    l_trow )
      ELSE Continue???  )

      Cheers,

      Sunil

      Author's profile photo Sunil Sankar
      Sunil Sankar

      if no else part is declared an initial date type is inserted, trying to avoid it.

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Sorry, no, we havn't such a thing. For your use case we could also use a construct to insert no line into an internal table. But we don't have that either.

      Author's profile photo Amy King
      Amy King

      I notice we can write

      IF line_exists( itab[ ... ] ).
          ...
      ENDIF.

      but not

      CASE abap_true.
        WHEN line_exists( itab[ ... ] ).
          ...
      ENDCASE.

      Even though the predicate returns a Boolean. Is there a reason the latter isn't supported?

      The syntax for a method specification is "objref->method" or
      "class=>method". "objref->method" or "class=>method". "class=>method".

      Cheers,
      Amy

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

       

      Yes.

      The operands operand1, operand2, ... after WHEN are extended functional operand positions in which, however, table expressions cannot be specified. This property of operand positions is obsolete and should no longer be used.

      Don't ask. Normally, you should use constants behind WHEN while the expressions are behind CASE. But for whatsoever reasons, it was implemented wrongly, years ago, in the pre-real-expression era.

       

       

       

      Author's profile photo M. Ahmad
      M. Ahmad

      Hello Horst,

      Is there any performance difference between

      READ TABLE itab into wa

      WITH KEY F1 = X

      F2 = Y

      F3 = Z

      TRANSPORTING NO FIELDS

      BINARY SEARCH

      IF SY-SUBRC = 0.

      //bussness logic

      ENDIF.

      &

      IF line_exists(itab[ F1 = X   F2 = Y  F3 = Z]).

      //business logic

      ENDIF.

       

      if "itab" contains millions of records