Best practice for Table Expressions (NW 7.4)

Lilienthal picture Lilienthal · Oct 31, 2014 · Viewed 10.3k times · Source

An official SAP presentation discussing new ABAP programming features in NetWeaver 7.4 (CD261) makes a big deal about table expressions, replacing the old syntax to read from an internal table:

READ TABLE lt_aufk INTO ls_aufk WITH KEY aedat = sy-datum.
lv_order = ls_aufk-aufnr.

with a single-line lv_order = lt_aufk[ aedat = sy-datum ]-aufnr.

However, it fails to mention that if a table expression fails to find a line it will raise exception CX_SY_ITAB_LINE_NOT_FOUND, so really that notation should actually be:

TRY.
        lv_order = lt_aufk[ aedat = sy-datum ]-aufnr.
    CATCH cx_sy_itab_line_not_found.
ENDTRY.

Which is both longer and makes any simple read logic look incredibly complex and hard to read. Since every individual read might need to fail or succeed individually this quickly balloons out of proportion:

TRY.
        wa1 = lt_itab[ col1 = ... ].
    CATCH cx_sy_itab_line_not_found.
ENDTRY.
TRY.
        wa2 = lt_itab[ col2 = ... ].
    CATCH cx_sy_itab_line_not_found.
ENDTRY.
TRY.
        wa3 = lt_itab[ col3 = ... ].
    CATCH cx_sy_itab_line_not_found.
ENDTRY.
TRY.
        wa4 = lt_itab[ col4 = ... ].
    CATCH cx_sy_itab_line_not_found.
ENDTRY.
TRY.
        wa5 = lt_itab[ col5 = ... ].
    CATCH cx_sy_itab_line_not_found.
ENDTRY.

Is there any way to improve the readability of these table expressions? Am I using them improperly?

Answer

Jorg picture Jorg · Nov 3, 2014

I was typing a comment but it's getting to long...

Best practice

This is debatable I guess but my 2 cents: Sometimes ignoring an exception is OK, for instance if you just want to, in your case, display an empty cell. Technically, in the old scenario you should also be catching SUBRCs before moving into structures too. You have an additional issue - depending on your table definitions, I can't see those - that aedat might not be a primary key in which case you might be trying to cram another table type into a work area. The thing that matters most in the end is whether or not your program crashes, and whether or not you're displaying meaningful data.

As for design principles, over the whole I think I'd rather put some effort into the DRY principle if you do a lot of this in your program.

Having said that, the documentation mentions:

About the exception:

Source

There are ways around it.

If the specified row is not found, a handleable expression of the class CX_SY_ITAB_LINE_NOT_FOUND is raised in all operand positions, except when

  1. a default value is specified in the definition of the type of the result,
  2. a table expression is used in the statement ASSIGN, where sy-subrc is set to the value 4,
  3. when used in the predicate function line_exists, where the logical value "false" is returned,
  4. when used in the table function line_index, where the value 0 is returned.

Default values for table expressions

Source.

Neat if you're on SP08 or higher already:

Table expressions itab[ ...] cannot support sy-subrc. Up to now, an exception was raised anytime if a table line specified in the square brackets could not be found. Not everybody liked this behavior.

As a workaround, you can place a table expression inside a VALUE or REF expression, that contains a OPTIONAL or DEFAULT addition. If a line is not found, the OPTIONAL addition returns an initiial line while the DEFAULT addition returns a given value, that can be specified as an expression, especially another table expression.

TYPES:
  BEGIN OF line,
    id    TYPE i,
    value TYPE string,
  END OF line,
  itab TYPE SORTED TABLE OF line WITH UNIQUE KEY id.

DATA(def) = VALUE line( id = 0 value = `not found` ).


...

DATA(result) = VALUE #( itab[ id = ... ] DEFAULT def ).