Skip to content

Clean ABAP Quick Reference

Modern ABAP syntax and best practices — before/after comparisons on one page.

Introduction

Modern ABAP (7.40+) introduced a set of inline and constructor expressions that make code shorter, safer, and easier to read. This cheat sheet shows the old approach and the clean alternative side by side. Each section fits on a few lines — scan the whole page in under two minutes.

Minimum release: ABAP 7.40 SP08

All features on this page require at least ABAP 7.40 SP08. Most are available in ECC with the correct support package and in all S/4HANA releases. Check your system release with sy-saprl if unsure.


1 — Inline declarations

Declare variables exactly where they are first used. No upfront DATA block needed.

" Old style
DATA lv_result TYPE string.
lv_result = 'Hello'.

" Modern
DATA(lv_result) = 'Hello'.

Also works in method calls and loops — the variable is typed automatically from the right-hand side context.


2 — String templates

Build strings with | | template literals. No CONCATENATE required; expressions are evaluated inline.

" Old style
DATA lv_msg TYPE string.
CONCATENATE 'Hello ' lv_name '!' INTO lv_msg.

" Modern
DATA(lv_msg) = |Hello { lv_name }!|.

Supports formatting options: { lv_date DATE = ISO }, { lv_amount CURRENCY = lv_curr }, { lv_num NUMBER = USER }.


3 — Table initialisation

Fill internal tables inline with VALUE #( ). No APPEND loop needed.

" Old style
DATA lt_tab TYPE STANDARD TABLE OF ty_item.
DATA ls_row TYPE ty_item.
ls_row-id = 1. ls_row-name = 'Alpha'. APPEND ls_row TO lt_tab.
ls_row-id = 2. ls_row-name = 'Beta'.  APPEND ls_row TO lt_tab.

" Modern
DATA(lt_tab) = VALUE ty_item_tab(
  ( id = 1  name = 'Alpha' )
  ( id = 2  name = 'Beta'  ) ).

Works for structures too: DATA(ls_row) = VALUE ty_item( id = 1 name = 'Alpha' ).


4 — Table expressions

Read a single row by key using lt_tab[ ]. Raises CX_SY_ITAB_LINE_NOT_FOUND if the key is not found — catch it, or use VALUE #( lt_tab[ key = 'X' ] OPTIONAL ) to get an empty result instead.

" Old style
READ TABLE lt_tab INTO ls_row WITH KEY id = 42.
IF sy-subrc = 0.
  WRITE ls_row-name.
ENDIF.

" Modern
DATA(ls_row) = lt_tab[ id = 42 ].           " raises exception if not found
DATA(ls_safe) = VALUE #( lt_tab[ id = 42 ] OPTIONAL ).  " empty if not found

Table expressions raise exceptions on missing entries

lt_tab[ key = 'X' ] raises CX_SY_ITAB_LINE_NOT_FOUND when the key does not exist. Either wrap in TRY/CATCH or use the OPTIONAL addition. Never rely on sy-subrc — table expressions do not set it.


5 — Constructor expressions: COND and SWITCH

Replace IF/ELSE chains with inline conditional expressions.

" Old style
DATA lv_label TYPE string.
IF lv_amount > 0.
  lv_label = 'positive'.
ELSE.
  lv_label = 'non-positive'.
ENDIF.

" Modern — COND for conditions
DATA(lv_label) = COND string(
  WHEN lv_amount > 0 THEN 'positive'
  ELSE                    'non-positive' ).

" Modern — SWITCH for discrete values
DATA(lv_color) = SWITCH string( lv_status
  WHEN 'A' THEN 'Green'
  WHEN 'I' THEN 'Red'
  ELSE          'Grey' ).

6 — FOR expressions

Project a source table into a new table in one expression. Replaces a LOOP/APPEND pattern.

" Old style
DATA lt_names TYPE STANDARD TABLE OF string.
LOOP AT lt_employees INTO DATA(ls_emp).
  APPEND ls_emp-name TO lt_names.
ENDLOOP.

" Modern
DATA(lt_names) = VALUE string_table(
  FOR ls_emp IN lt_employees
  ( ls_emp-name ) ).

Add a WHERE filter inline: FOR ls_emp IN lt_employees WHERE ( active = abap_true ).


7 — Modern SELECT

Use @DATA( ) inline declarations in SELECT. No separate DATA statement required.

" Old style
DATA lt_result TYPE STANDARD TABLE OF mara.
SELECT * FROM mara INTO TABLE lt_result
  WHERE mtart = 'FERT'.

" Modern
SELECT * FROM mara
  INTO TABLE @DATA(lt_result)
  WHERE mtart = 'FERT'.

Also use @lv_var to pass host variables into WHERE clauses — the @ prefix is mandatory in open SQL with inline declarations.


8 — FOR ALL ENTRIES — always check the driver table first

FOR ALL ENTRIES IN (FAE) is a classic trap: if the driver table is empty, the WHERE clause is dropped entirely and the SELECT returns all rows from the database table.

" Dangerous — never do this
SELECT * FROM vbap INTO TABLE @DATA(lt_items)
  FOR ALL ENTRIES IN @lt_orders
  WHERE vbeln = @lt_orders-vbeln.

" Safe — always guard with an IS NOT INITIAL check
IF lt_orders IS NOT INITIAL.
  SELECT * FROM vbap INTO TABLE @DATA(lt_items)
    FOR ALL ENTRIES IN @lt_orders
    WHERE vbeln = @lt_orders-vbeln.
ENDIF.

Empty driver table = full table scan with no WHERE filter

This is one of the most common SAP performance incidents. Always add IF lt_driver IS NOT INITIAL. before any FOR ALL ENTRIES IN @lt_driver SELECT. No exceptions.


9 — TRY/CATCH instead of SY-SUBRC

Use class-based exceptions for new code. They carry structured error information and cannot be silently ignored.

" Old style — sy-subrc is easy to forget to check
CALL FUNCTION 'SOME_FM'
  EXCEPTIONS error = 1 OTHERS = 2.
IF sy-subrc <> 0.
  " handle
ENDIF.

" Modern — exception carries text and can be rethrown
TRY.
    DATA(lv_result) = my_object->calculate( lv_input ).
  CATCH cx_calculation_error INTO DATA(lx).
    WRITE: / lx->get_text( ).
ENDTRY.

When calling legacy FMs that use sy-subrc, wrap them in a thin method that raises a class-based exception on failure.


10 — Method calls: named parameters and chaining

Omit EXPORTING (it is implicit). Use named parameters for clarity. Chain method calls to avoid temporary variables.

" Old style
CALL METHOD lo_obj->process
  EXPORTING
    iv_input = lv_data
  IMPORTING
    ev_result = lv_result.

" Modern — no EXPORTING keyword, functional style
DATA(lv_result) = lo_obj->process( iv_input = lv_data ).

" Chaining: no temp variable needed
DATA(lv_upper) = to_upper( substring( val = lv_text off = 0 len = 10 ) ).

Omit the parameter name when there is only one IMPORTING parameter

lo_obj->process( lv_data ) is valid when iv_input is the only importing parameter. Use the short form for trivial calls (to_upper( lv_str )), named form for anything with more than one parameter.


See also

  • SAP Help: ABAP Language Reference — Constructor Expressions
  • SAP Help: Clean ABAP Style Guide — the official SAP clean code guidelines on GitHub
  • Transaction SE38 — write and test ABAP programs
  • Transaction SAAB — debugger for verifying modern expressions at runtime

Comments