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.
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.
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 sameOPERATOR type( … )shape. - Check release notes for your stack. ABAP 7.50, 7.54, 7.56, and 7.57 each added further constructs. Features like
FINALrequire relatively recent releases. - Code reviews accelerate adoption. Pair experienced developers with those learning modern syntax. Review diffs to reinforce patterns.