Modern vs Classic ABAP Syntax

Author: Zheng Deding Updated: 2024-06-15 Tags: ABAP, SAP, S/4HANA

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.

Read Table

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

Build Table

// 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 — TRY / CATCH
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.