3.1Bloom · ANot started

Obsolete language elements to hunt

Reading depth

What you'll learn

Hunt the obsolete constructs — MOVE, MOVE-CORRESPONDING, header lines, FORM/PERFORM, TABLES, DESCRIBE, double-negative CHECK, CONCATENATE — and swap each for its modern, inlinable equivalent.

  • MOVE → b = a; MOVE-CORRESPONDING → CORRESPONDING #( ).
  • LOOP AT itab. (header line) → LOOP AT itab ASSIGNING FIELD-SYMBOL(<fs>).
  • OCCURS/header lines → typed tables; FORM/PERFORM → methods; drop TABLES outside dynpros.

Your logic is sound — most of modernizing ABAP is learning the modern spelling of things you already do well, not relearning the craft. It is largely a search-and-replace of constructs that are obsolete (or outright forbidden in classes and in Restricted ABAP) for their modern forms. MOVE a TO b becomes the assignment operator b = a; MOVE-CORRESPONDING becomes the constructor CORRESPONDING #( ); and a bare LOOP AT itab. with an implicit header line becomes LOOP AT itab ASSIGNING FIELD-SYMBOL(<fs>), because header lines are obsolete and illegal in classes.

Structural relics go too: OCCURS n WITH HEADER LINE becomes a typed DATA itab TYPE STANDARD TABLE OF ty WITH EMPTY KEY; FORM/PERFORM procedures become class methods; and the TABLES statement (outside dynpros) becomes an explicit local DATA declaration. These are not cosmetic — procedural forms and header lines are genuine Clean Core smells that block a package from going to ABAP Cloud.

Finally, prefer the expressive built-ins: DESCRIBE TABLE itab LINES n becomes n = lines( itab ); the double-negative CHECK NOT .. IS INITIAL becomes a positive IF .. IS NOT INITIAL; and CONCATENATE gives way to string templates. Each swap is shorter, inlinable, and easier to read at the call site.

Key points

  • MOVE → b = a; MOVE-CORRESPONDING → CORRESPONDING #( ).
  • LOOP AT itab. (header line) → LOOP AT itab ASSIGNING FIELD-SYMBOL(<fs>).
  • OCCURS/header lines → typed tables; FORM/PERFORM → methods; drop TABLES outside dynpros.
  • DESCRIBE TABLE ... LINES → lines( ); CHECK NOT .. IS INITIAL → IF .. IS NOT INITIAL.
  • CONCATENATE → string templates.

Examples

BeforeHeader line and DESCRIBE

Implicit header line plus DESCRIBE TABLE — obsolete, and the header line will not compile in a class.

ABAPloop at itab.
  write itab-matnr.
endloop.
describe table itab lines lv_n.
AfterField symbol and lines( )

An explicit field symbol replaces the header line; lines( ) replaces DESCRIBE and is inlinable.

ABAPloop at itab assigning field-symbol(<row>).
  out->write( <row>-matnr ).
endloop.
data(lv_n) = lines( itab ).
BeforeDouble-negative CHECK and CONCATENATE

A double negative plus CONCATENATE — both have clearer modern forms.

ABAPcheck not lv_name is initial.
concatenate lv_first lv_last into lv_full
  separated by space.
AfterPositive IF and a string template

A positive condition and an inline template read directly.

ABAPif lv_name is not initial.
  data(lv_full) = |{ lv_first } { lv_last }|.
endif.

Source notes: clean-core-curriculum §3.1

Ask Claude

Build a prompt from this lesson + your question and open a fresh Claude chat with it pre-filled — handy for adapting a before/after pattern to your own object.

Code exercise · ABAP

The two CHECK statements sit deep in this method and exit it silently — abaplint flags the deep CHECK/EXIT anti-pattern. Refactor to fail-fast guard clauses so the contract is explicit and the happy path stays flat, then re-check until it's clean.

The starter trips abaplint rule exit_or_check. Fix the code until the check is clean.

Hint

Replace each `check <cond>.` with `if not <cond>. raise exception type cx_static_check. endif.`