Cheat Sheet Modern ABAP
This poster is the perfect complement to the training courses
by Brandeis Consulting
The ABAP language has evolved tremendously since NetWeaver ABAP 7.40. Many new language constructs have been added. Especially, of course, many new expressions. With them you can write clean code and save many auxiliary variables and declarations. The new language elements should be used to make the code more robust and readable. However, faster execution is not to be expected.
This poster shows the most important and useful new features. Omitted are the new ABAP SQL syntax and ABAP Built-In Functions.
Inline Declarations
With inline declarations, a variable can be defined where it is used for the first time, that is, where a value is assigned to it for the first time. In many places in ABAP code, the data type of a variable results from the context.
With DATA(<variable name>)
a variable can be defined where it is needed.
Modern ABAP
LOOP AT ResultTab INTO DATA(ResultLine).
...
ENDLOOP.
Classic ABAP
DATA ResultLine LIKE LINE OF ResultTab.
LOOP AT ResultTab INTO ResultLine.
...
ENDLOOP.
The main advantage of the inline declaration is, besides the more compact code, more flexibility. If the field list changes in the example, the data type of RESULT
is automatically adjusted. Especially with JOIN
operations you often don`t have a suitable structure definition either.
Modern ABAP
SELECT *
FROM zbc_users
INTO TABLE @DATA(Result).
Classic ABAP
DATA Result TYPE TABLE OF zbc_users.
SELECT *
FROM zbc_users
INTO TABLE Result.
Field symbols can also be assigned to an existing memory area with inline declarations. Either with an ASSIGN
or with the appropriate statements for accessing internal tables, such as
LOOP AT ... ASSIGNING FIELD-SYMOBL(<fs-name>).
or
READ TABLE ... ASSIGNING FIELD-SYMBOL(<fs-name>) ...
Concatenation Operator &&
Two strings can be concatenated using the &&
operator. This is much more elegant than using CONCATENATE
and also works at operand positions without an auxiliary variable.
Modern ABAP
out->write( `It is the year `
&& sy-datum(4) ).
Classic ABAP
DATA tmp TYPE c LENGTH 100.
CONCATENATE `It is the year `
sy-date(4) INTO tmp.
out->write( tmp ).
Calculation assignment with &&=
When composing strings, it is often necessary to use 'append'. For example, when generating HTML.
Modern ABAP
html &&= `<b>Hello</b>`
Classic ABAP
CONCATENATE html `<b>Hello</b>`
INTO html.
String Templates
String Templates are expressions that generate a string of characters. They consist of liters that can contain embedded expressions, formatting, and control characters. A string template starts and ends with a vertical bar |
. Everything in between is constant text (=literal), unless it is an embedded expression surrounded by curly braces { ... }
.
The characters {
, }
, |
and \
must be escaped in the literal by a backslash \
.
Modern ABAP
out->write( |Today: {
sy-date DATE = USER }| ).
Classic ABAP
DATA tmp TYPE string.
DATA theDate TYPE c LENGTH 10.
WRITE sy-date TO theDate.
CONCATENATE `Today: ` theDate INTO tmp.
out->write( tmp ).
Expressions in String Templates
In curly braces { ... }
, expressions can be embedded directly into the string template. This can be used to call a functional method or perform a calculation, for example. Nice examples of this can be found in the box about the constructor expressions COND
and SWITCH
.
Formatting
The appearance of the expressions can be customized using the formatting options. The most important ones are
WIDTH = <length>
- width in charactersALIGN = <alignment>
- EitherLEFT
,RIGHT
orCENTER
DATE = USER
- format the date according to the user master record, see aboveTIME = USER
- The same for the timeALPHA = IN/OUT
- Alpha conversion
Control characters in String Templates
The control characters
\n
- Line Feed\r
- Carriage Return and\t
- Tabulator
can be used directly in String Templates. So you can easily create multiline texts without using CL_ABAP_CHAR_UTILS=>CR_LF
:
out->write( |Hello\r\nWorld| ).
Enumerations
With enumerations, we have type-safe enumeration types. This means that with the enumeration, a datatype is also defined. And it is checked at design time if the data type is correct for assignments and method calls. So only the values that have been defined can be used.
Definition of an Enumeration
TYPES: BEGIN OF ENUM eColour,
Red,
...
Orange,
Violet,
END OF ENUM eColour.
Enumeration usage
DATA MyColour TYPE eColor.
" MyColour = 0. "Gives an error.
MyColour = Red .
Grouping in a structure
Since sometimes many constant values need to be defined, it is possible to group the individual components of an enumeration in a structure. This makes it easier to find the correct values. The access is the same as for a constant structure:
MyColour = Colour-Red
definition with structure
TYPES:
BEGIN OF ENUM eColour STRUCTURE Colour,
Red,
...
Orange,
Violet,
END OF ENUM eColour STRUCTURE Color.
Fixed values and other data types.
Normally the data type I
is used internally and values are assigned from 0 to N. However, this can also be changed manually. The data type can be up to 8 characters long. It is also important that for a constant always the value IS INITIAL
is used.
TYPES ColourDef TYPE c LENGTH 7.
TYPES: BEGIN OF ENUM eColour
STRUCTURE Colour
BASE TYPE ColourDef,
Black VALUE IS INITIAL,
Red VALUE '#ff0000',
Green VALUE '#00ff00',
Blue VALUE '#0000ff',
END OF ENUM eColour
STRUCTURE Color.
Value and enum type
Since a direct value assignment is not possible or leads to the wrong result in one direction, a conversion with the constructor operator CONV
is always required for storing the values in the database (or for all interfaces):
DATA MyColour TYPE eColour.
DATA ColourHex TYPE ColourDef.
"Wrong content 'GREEN':
ColourHex = Colour-green.
" Correct content '#00ff00' :
ColourHex = conv #( Colour-Green ).
" Syntax error:
" MyColour = '#00ff00'.
" Correct assignment:
MyColour = conv #( '#00ff00' ).
Constructor Expressions
Constructor expressions create a new (data) object of a specific (data) type. So-called constructor operators are used for this purpose. These cover a variety of very different use cases. However, they always have the following syntax in common:
<ConstructorOperator> <DataType>( <Parameter> ).
A simple example: use the VALUE
operator to create an internal table with fixed contents.
DATA tt_tadir TYPE STANDARD TABLE OF tadir.
DATA ObjectCatalog TYPE tt_tadir.
ObjectCatalog = VALUE tt_tadir( ( obj_name = 'ZCL_CS' object = 'CLAS' )
( obj_name = 'MARA' object = 'TABL' ) ).
The data type and the hash character #
Depending on the situation, the appropriate data type is specified, e.g. a data element, a table type, a structure type or a class name.
If the data type can be derived from the context, then it does not need to be specified. Instead, the #
character is used. This is the case, for example, with an assignment.
Readability of constructor expressions
Some operators can perform very complex logic. For this purpose, constructor expressions can also be nested within each other. The code quickly becomes confusing. It is therefore recommended to calculate only simple logic in constructor expressions. For complex logic, classic ABAP is often more readable. There is no way to debug constructor expressions in ADTs.
Create data and objects with VALUE
and NEW
The two operators create data. With VALUE
you get the data directly, with NEW
you get the reference to it. If no parameters are passed, both operators create empty data objects.
Create structures
If structures are created, the individual components can be passed as parameters. Unassigned components are assigned their initial value.
DATA(line) = VALUE tadir( obj_name = 'ZCL_CS' object = 'CLAS' ).
Create internal tables
The individual lines of an internal table are again enclosed in round brackets.
DATA DateRange TYPE RANGE OF dats.
DateRange = VALUE #( ( sign = 'I' option = 'EQ' low = '20221031' )
( sign = 'I' option = 'EQ' low = '20220406' ) ).
Common components of the individual lines can also be defined before the round brackets:
DateRange = VALUE #( sign = 'I' option = 'EQ' ( low = '20221031' )
( low = '20230406' ) ).
BASE
specifies an initial value
For structures, a compatible structure can be specified before the first component with BASE
, which fills the unassigned components with values.
For internal tables an internal table can be specified with BASE
, which is then supplemented by the following lines. So this corresponds to an APPEND
.
NewDateRange = VALUE #( BASE DateRange
( sign = 'I' option = 'EQ' low = '20230101' ) ).
In the VALUE
operator FOR
loops are also possible. These are described in the REDUCE
operator.
Create objects with NEW
Instances of classes can also be created with NEW
:
NEW <class name>( <constructor parameter> )
Data type change with CONV
This operator is used to easily convert data types. This is a common problem with method parameters, for example: the content of a variable matches, but the data type does not.
Modern ABAP
my_method( TEXT = CONV #( sy-datum ) ).
Classic ABAP
DATA DateText TYPE char8.
DateText = sy-date.
my_method( Text = DateText )
See the enumerations for more examples.
Down- and upcast of reference variables with CAST
In classic ABAP, the upcast is done by simple assignment with =
, the downcast with the cast operator ?=
. This always requires an auxiliary variable of the appropriate type. With the CAST
operator, this can be omitted in many cases:
Modern ABAP
DATA Task TYPE zbc_tasks.
DATA(Components) = cast cl_abap_structdescr(
cl_abap_typedescr=>describe_by_data(
Task ) )->get_components( ).
Classic ABAP
DATA Task TYPE zbc_tasks.
DATA StructDescr TYPE REF TO cl_abap_structdescr.
DATA(TypeDescr) = cl_abap_typedescr=>describe_by_data( Task ).
StructDescr ?= TypeDescr.
DATA(Components) = StructDescr->get_components( ).
Case distinctions with COND
and SWITCH
These constructor expressions correspond to the CASE
expression in SQL. Simple case distinctions depending on a single field are implemented with SWITCH
:
Modern ABAP
out->write(
|Hello { SWITCH #( User-Gender
WHEN 'F' THEN 'Mrs.'
WHEN 'M' THEN 'Mr.'
ELSE '' )
} { User-Lastname } | ).
Classic ABAP
DATA salutation TYPE string.
CASE user-gender.
WHEN 'F'. Salutation = 'Mrs.'.
WHEN 'M'. Salutation = 'Mr'.
WHEN OTHERS. Salutation = ''.
ENDCASE.
out->write( |Hello { Salutation
} { user load name }| ).
More complex distinctions with arbitrary conditions are made with COND
:
out->write( |The status is { COND #( WHEN Priority > 3
AND DueDate <= SY-DATUM THEN 'Critical'.
WHEN Priority > 2 THEN 'Medium
ELSE 'Low' ) }|.
Use REDUCE
to calculate a value from an internal table.
This operator calculates a single result value by looping over internal tables. Complex variants have been deliberately omitted, as this operator quickly limits readability.
out->write( REDUCE string( INIT res TYPE string
sep TYPE string
FOR user IN users
NEXT
res &&= sep && User-Firstname
sep = ', ' ) ).
Create Internal Tables with the FILTER
operator
The FILTER
operator can be used to create internal tables based on another internal table by filtering. Either via a simple WHERE
clause or based on another table. Basically, the table type and key must be optimized for filtering, otherwise there will be syntax errors.
FILTER
with WHERE
clause
DATA lt_data TYPE sorted TABLE OF I_CountryText WITH UNIQUE KEY LANGUAGE COUNTRY.
SELECT * FROM i_countrytext INTO TABLE @lt_data.
out->WRITE( FILTER #( lt_data WHERE LANGUAGE = 'D' ) ).
FILTER
with IN ... WHERE
Here we filter for another internal table. This corresponds to an INNER JOIN
in SQL.
DATA lt_data TYPE sorted TABLE OF I_CountryText WITH UNIQUE KEY COUNTRY.
DATA(lt_filter) = VALUE tt_demo( ( COUNTRY = 'DE' )
( COUNTRY = 'US' ) ).
SELECT * FROM i_countrytext WHERE LANGUAGE = 'D' INTO TABLE @lt_data.
out->WRITE( FILTER #( lt_data IN lt_filter WHERE COUNTRY = COUNTRY ) ).
The CORRESPONDING
Operator.
This operator is reminiscent of the MOVE-CORRESPONDING
statement. It can be used for structures as well as for internal tables.
The CORRESPONDING
operator can be used to create another data object from a structured data object, i.e. an internal table or a structure, and to take over the values of identical fields. This is similar to the MOVE-CORRESPONDING
statement.
Basic form of CORRESPONDING
The data is copied to fields with the same names. Fields that do not exist in the source remain empty in the destination.
TasksSmall = corresponding #( TasksOriginal ).
Explicit MAPPING
and EXCEPT
If the components do not have exactly the same name but should still be copied to each other, or if individual components should not be copied, this can be specified explicitly with the MAPPING
and EXCEPT
additions:
TaskSmall = corresponding #( TaskOriginal
MAPPING id = task_id
title = summary
EXCEPT assignee ).
With BASE
initial values are given, see VALUE
operator. This is used to prefill the values for structures or set additional lines at the beginning for internal tables.
CORRESPONDING
with lookup table
This variant performs a lookup to another internal table. This corresponds to a LEFT OUTER JOIN
with a :1 cardinality. As with the FILTER
operator, this only works if the table type and key definition match the join condition in the USING
clause.
DATA Lookup TYPE HASHED TABLE OF I_CountryText WITH UNIQUE KEY Country.
DATA(Original) = VALUE tt_demo( ( Country = 'DE' )
( Country = 'US' ) ).
SELECT * FROM I_CountryText WHERE LANGUAGE = 'D' INTO TABLE @Lookup.
DATA(Result) = CORRESPONDING tt_demo( Original FROM Lookup
USING country = Country
MAPPING country_text = CountryName ).
Predicative Method Calls
Behind the unwieldy term Predicative Method Call lies a simple concept that is standard in (almost) all other programming languages: a method call as a predicate, e.g. it is used directly in an IF
statement. Since in ABAP the values TRUE
and FALSE
are not clearly defined, the following definition applies:
If the return value of a functional method (i.e. with RETURNING
) is initial, the predicate is logically FALSE
, otherwise TRUE
. Thus, it corresponds to IF method( ) IS NOT INITIAL
.
Modern ABAP
IF isRelevant( ).
...
ENDIF.
Classic ABAP
IF isRelevant( ) EQ abap_true.
...
ENDIF.
Table Expressions
Even if the name suggests otherwise, table expressions provide us a row of a table. In SQL, therefore, they would be called row expressions.
They are not copies of the row, but the row in the table. Therefore, write operations on table expressions also modify the table. So they can replace READ ... INTO
and READ ... ASSIGNING
statements.
Construction of table expressions: <table>[ <RowSpecification> ]
The table can be any internal table. The row specification is enclosed in square brackets and can be done in several ways: By specifying the row number for standard tables, a free key or the table key.
Modern ABAP
* Copy of the first row
DATA(row) = users[ 1 ].
* Change the first name of the 1st row
users[ 1 ]-firstname = 'Edgar'.
* Change Peter's last name
users[ firstname = 'Peter'
]-lastname = 'Pan'.
Classic ABAP
DATA row LIKE LINE OF users.
READ TABLE users INTO row INDEX 1.
FIELD SYMBOLS <row> LIKE LINE OF users.
READ TABLE users ASSIGNING <row> INDEX 1.
<row>-firstname = 'Edgar'.
FIELD SYMBOLS <row> LIKE LINE OF users.
READ TABLE users ASSIGNING <row>.
WITH firstname = 'Peter'.
<row>-lastname = 'Pan'.
Accessing non-existent lines will generate an exception CX_SY_ITAB_LINE_NOT_FOUND
.
Modern ABAP
* Changing Peter's last name
TRY.
users[ firstname = 'Peter'
]-lastname = 'Pan'.
CATCH CX_SY_ITAB_LINE_NOT_FOUND.
ENDTRY.
Classic ABAP
* Changing Peter's last name
FIELD SYMBOLS <row> LIKE LINE OF users.
READ TABLE users ASSIGNING <row>.
WITH firstname = 'Peter'.
IF sy-subrc = 0.
<row>-lastname = 'Pan'.
ENDIF.
Alternatively, for read access, use the VALUE
operator to create a default value or mark the access as OPTIONAL
.
...VALUE #( <table>[<RowSpecification>]
DEFAULT <AlternativeValue> | OPTIONAL )
New Group Level Processing
The classic group level processing with AT NEW/END
depends on the sorting of the data and the order of the columns. Both must fit exactly. Thus it is error-prone and sometimes hardly usable. The new group level processing solves this problem by nested LOOP
s.
Modern ABAP
LOOP AT PlantMats
INTO DATA(Grouping)
GROUP BY ( Plant = Grouping-Plant )
INTO DATA(Grp).
" A
LOOP AT GROUP Grp
INTO DATA(PlantMat).
" B
ENDLOOP.
" C
ENDLOOP.
Classic ABAP
LOOP AT PlantMats
INTO DATA(PlantMat).
AT NEW Plant.
" A
ENDAT.
" B
AT END OF Plant.
" C
ENDAT.
ENDLOOP.
Brandeis Consulting
Customized training and consulting from book authors and SAP champions! On our website www.brandeis.de you will find our offer!
(C) Brandeis Consulting Ltd.