Modern vs Classic ABAP Syntax

Why It Matters

ABAP has been evolving since its origins in the 1980s. With SAP NetWeaver 7.40 (SP08) and later S/4HANA, SAP introduced a sweeping wave of modern language features: inline declarations, string templates, table expressions, constructor operators, and more.

The classic style still works — and you'll encounter it in every legacy system — but modern ABAP is dramatically more readable, concise, and refactor-friendly. Understanding both is essential for every ABAP developer.

Compatibility Note Modern syntax features require ABAP 7.40 SP08 or higher. Always verify your system's release before adopting new constructs in production code.

Variable Declarations

Classic ABAP requires all variables to be declared upfront in a DATA block. Modern ABAP introduced inline declarations with DATA(...) and FINAL(...), placing the declaration exactly where the variable is first used.

// Classic

DATA: lv_name   TYPE string,
      lv_count  TYPE i,
      ls_flight TYPE sflight,
      lt_result TYPE TABLE OF sflight.

lv_name  = 'Lufthansa'.
lv_count = 42.

SELECT * INTO TABLE lt_result
  FROM sflight
  WHERE carrid = lv_name.

// Modern (7.40+)

DATA(lv_name)  = 'Lufthansa'.
DATA(lv_count) = 42.

SELECT *
  FROM sflight
  WHERE carrid = @lv_name
  INTO TABLE @DATA(lt_result).

" FINAL = immutable (7.56+)
FINAL(lc_max) = 100.

String Handling

String concatenation used to require the verbose CONCATENATE statement. Modern ABAP replaces it with string templates (pipe syntax) that embed expressions directly.

// Classic

DATA: lv_first TYPE string VALUE 'John',
      lv_last  TYPE string VALUE 'Doe',
      lv_msg   TYPE string.

CONCATENATE 'Hello, ' lv_first
            ' ' lv_last '!'
  INTO lv_msg.

WRITE: / lv_msg.

// Modern (7.40+)

DATA(lv_first) = 'John'.
DATA(lv_last)  = 'Doe'.

DATA(lv_msg) = |Hello, { lv_first } { lv_last }!|.

" Formatting options built-in
DATA(lv_price) = |Price: { lv_amount
  CURRENCY = lv_curr }|.

Internal Table Operations

Working with internal tables is at the heart of ABAP programming. Modern syntax introduces table expressions, VALUE #( ), FOR loops, and REDUCE — transforming what used to take 15 lines into a single expression.

// Classic — Read Table

DATA: ls_flight TYPE sflight,
      lv_idx    TYPE sy-tabix.

READ TABLE lt_flights
  INTO ls_flight
  WITH KEY carrid = 'LH'
           connid = '0400'.

IF sy-subrc = 0.
  WRITE: / ls_flight-price.
ENDIF.

// Modern — Table Expression

TRY.
  DATA(ls_flight) = lt_flights[
    carrid = 'LH' connid = '0400' ].
  WRITE: / ls_flight-price.
CATCH cx_sy_itab_line_not_found.
  " handle missing entry
ENDTRY.

// Classic — Build Table

DATA: lt_nums TYPE TABLE OF i,
      lv_sum  TYPE i,
      lv_n    TYPE i.

DO 5 TIMES.
  lv_n = sy-index.
  APPEND lv_n TO lt_nums.
ENDDO.

LOOP AT lt_nums INTO lv_n.
  lv_sum = lv_sum + lv_n.
ENDLOOP.

// Modern — VALUE + REDUCE

DATA(lt_nums) = VALUE int_tab(
  FOR i = 1 THEN i + 1
  UNTIL i > 5 ( i ) ).

DATA(lv_sum) = REDUCE i(
  INIT s = 0
  FOR  n IN lt_nums
  NEXT s = s + n ).

Conditional Assignments

Classic ABAP relies on verbose IF/ELSE blocks for conditional value assignment. Modern ABAP adds the COND and SWITCH constructor operators — the equivalent of ternary expressions and switch statements.

// Classic

DATA lv_label TYPE string.

IF lv_score >= 90.
  lv_label = 'Excellent'.
ELSEIF lv_score >= 70.
  lv_label = 'Good'.
ELSE.
  lv_label = 'Needs Work'.
ENDIF.

DATA lv_text TYPE string.
CASE lv_status.
  WHEN 'A'. lv_text = 'Active'.
  WHEN 'I'. lv_text = 'Inactive'.
  WHEN OTHERS. lv_text = 'Unknown'.
ENDCASE.

// Modern — COND + SWITCH

DATA(lv_label) = COND string(
  WHEN lv_score >= 90 THEN 'Excellent'
  WHEN lv_score >= 70 THEN 'Good'
  ELSE                     'Needs Work' ).

DATA(lv_text) = SWITCH string(
  lv_status
  WHEN 'A' THEN 'Active'
  WHEN 'I' THEN 'Inactive'
  ELSE         'Unknown' ).

Object Creation

Object instantiation gained the NEW operator in modern ABAP, allowing objects to be created inline without a preceding DATA statement or a separate CREATE OBJECT call.

// Classic

DATA: lo_order   TYPE REF TO zcl_order,
      lo_handler TYPE REF TO zcl_handler.

CREATE OBJECT lo_order
  EXPORTING
    iv_id = 'ORD-001'.

CREATE OBJECT lo_handler.

lo_handler->process( lo_order ).

// Modern — NEW Operator

DATA(lo_order) = NEW zcl_order(
  iv_id = 'ORD-001' ).

" Inline — no variable needed
NEW zcl_handler( )->process(
  lo_order ).

Loops & Filtering

Modern ABAP enriched LOOP AT with WHERE clauses, GROUP BY, and the FILTER operator — removing the need for manual CHECK/CONTINUE boilerplate.

// Classic

DATA ls_line TYPE ty_item.

LOOP AT lt_items INTO ls_line.
  CHECK ls_line-active = abap_true.
  " process active lines only...
ENDLOOP.

// Modern — WHERE + FILTER

LOOP AT lt_items INTO DATA(ls_line)
  WHERE active = abap_true.
  " cleaner intent signalling
ENDLOOP.

" Or build a filtered copy:
DATA(lt_active) = FILTER #(
  lt_items WHERE active = abap_true ).

Exception Handling

Classic ABAP used return code checks (sy-subrc) for nearly everything. Modern ABAP embraces class-based exceptions with TRY...CATCH, enabling cleaner error propagation and a richer exception hierarchy.

Modern Exception Handling ABAP 7.40+
TRY.
  DATA(lo_conn) = NEW zcl_db_connection( iv_dsn = lv_dsn ).

  DATA(lt_results) = lo_conn->query(
    iv_sql = |SELECT * FROM { lv_table } WHERE id = { lv_id }| ).

CATCH cx_sql_exception INTO DATA(lx_sql).
  RAISE EXCEPTION NEW zcx_data_error(
    iv_message  = lx_sql->get_text( )
    ix_previous = lx_sql ).

CATCH cx_parameter_invalid INTO DATA(lx_param).
  log_error( lx_param ).
ENDTRY.

Feature Reference

Feature Classic ABAP Modern ABAP
Variable declaration DATA block upfront DATA(...) inline
Immutable variables CONSTANTS only FINAL(...)
String building CONCATENATE |template { expr }|
Object creation CREATE OBJECT NEW class( )
Conditional value IF / ELSEIF blocks COND / SWITCH
Table read READ TABLE … INTO table[ key = val ]
Table build APPEND in DO loop VALUE #( FOR … )
Aggregation LOOP + manual sum REDUCE operator
Filtering tables LOOP + CHECK FILTER #( WHERE … )
Error handling sy-subrc checks TRY / CATCH classes
Open SQL host vars no prefix needed @ prefix required
Casting / conversion MOVE … TO + CAST CAST / CONV operators

Migration Tips

  • Start with new code, not rewrites. Apply modern syntax to new developments first. Legacy rewrites carry risk without immediate business value.
  • Use the ABAP Cleaner tool. SAP's open-source ABAP Cleaner (available on GitHub) automates many classic-to-modern transformations safely.
  • Enable extended program check. Modern ABAP constructs are checked more strictly — turn on extended syntax checks to catch issues early.
  • Learn the constructor operator pattern. VALUE, NEW, COND, SWITCH, REDUCE, FILTER, CONV, CAST — all follow the same OPERATOR type( … ) shape.
  • Check release notes for your stack. ABAP 7.50, 7.54, 7.56, and 7.57 each added further constructs. Features like FINAL require relatively recent releases.
  • Code reviews accelerate adoption. Pair experienced developers with those learning modern syntax. Review diffs to reinforce patterns.