Ansicht
Dokumentation

ABAPSHEET_CONSTRUCTOR_EXPRESSIONS - SHEET CONSTRUCTOR EXPRESSIONS

ABAPSHEET_CONSTRUCTOR_EXPRESSIONS - SHEET CONSTRUCTOR EXPRESSIONS

rdisp/max_wprun_time - Maximum work process run time   BAL Application Log Documentation  
This documentation is copyright by SAP AG.
SAP E-Book

Working with Constructor Expressions

This cheat sheet provides an overview on working with constructor expressions. It serves as a collection of syntax and code snippets in one place for your reference. For more details and syntax options, refer to the respective topic.

Introduction

  • As the name implies, these expressions "construct" results of a specific type. This (data or object) type must match the operator. Either the type is specified explicitly before the first parenthesis or the said # character can be specified if the type can be derived implicitly from the operand position. The # character symbolizes the operand type. If no type can be inferred from the operand position, for some constructor operators, the type can also be inferred from the arguments in the parentheses.
  • The use of constructor expressions can make your code leaner and more readable since you can achieve the same with fewer statements.
  • Apart from the concept of type inference, another concept is very handy particularly in this context: Inline declaration.
  • This means that you can declare a variable using DATA(var) (or an immutable variable FINAL(var)) as an operand in the current write position. In doing so, such a variable declared inline can receive the appropriate type and result of the constructor expression in one go.

Note

The construction of a result, i. e. a target data object, implies that the data object is initialized. However, there are variants with which the initialization can be avoided.

VALUE

  • The content of the resulting structure or internal table is determined by the parameters specified in parentheses.

Example: Structure

TYPES: BEGIN OF struc_type,
          a   TYPE i,
          b   TYPE c LENGTH 3,
        END OF struc_type.

DATA struc TYPE struc_type.

struc = VALUE #( a = 1 b = 'aaa' ). "Type inference

As mentioned above, the concept of inline declarations comes into picture here which simplifies ABAP programming. You can construct a new data variable (for example, using DATA(...)), provide the desired type with the constructor expression and assign values in one go.

DATA(structure) = VALUE struc_type( a = 2 b = 'bbb' ).

Note that initial values can be constructed by omitting the component specification or by providing no content within the parentheses.

struc = VALUE #( a = 2 ). "Component b not specified, b remains initial
struc = VALUE #( a = 1 b = value #( ) ). "Explicit setting of initial value for a component
struc = VALUE #( ). "The whole structure is initial

Regarding internal tables, the line specifications are enclosed in an inner pair of parentheses ( ... ). In the following examples, three lines are added to a table.

TYPES tab_type TYPE TABLE OF struc_type WITH EMPTY KEY.
DATA itab TYPE tab_type.

itab = VALUE #( ( a = 1 b = 'aaa' )
                ( a = 2 b = 'bbb' )
                ( a = 3 b = 'ccc' ) ).

"Table declared inline, explicit type specification
DATA(itab2) = VALUE tab_type( ( a = 1 b = 'aaa' )
                              ( a = 2 b = 'bbb' )
                              ( a = 3 b = 'ccc' ) ).

"Unstructured line types work without component names.
"Here, the table type is a string table.
DATA(itab3) = VALUE string_table( ( `abc` ) ( `def` ) ( `ghi` ) ).

In case of deep structures and deep tables, the use of VALUE expressions is handy. The following example demonstrates a deep structure.

DATA: BEGIN OF deep_struc,
        a TYPE i,
        BEGIN OF nested_struc,
          y TYPE i,
          z TYPE c LENGTH 3,
        END OF nested_struc,
      END OF deep_struc.

deep_struc = VALUE #( a = 1 nested_struc = VALUE #( y = 2 z = 'abc' ) ).

BASE addition: A constructor expression without the BASE addition initializes the target variable. Hence, you can use the addition if you do not want to construct a structure or internal table from scratch but keep existing content.

"Structure
struc = VALUE #( a = 1 b = 'aaa' ).

"struc is not initialized, only component b is modified, value of a is kept
struc = VALUE #( BASE struc b = 'bbb' ).

"Internal table
itab = VALUE #( ( a = 1 b = 'aaa' )
                ( a = 2 b = 'bbb' ) ).

"itab has two lines, two more are added instead of initializing the internal table first
itab = VALUE #( BASE itab
                ( a = 3 b = 'ccc' )
                ( a = 4 b = 'ddd' ) ).

LINES OF addition: All or some lines of another table can be included in the target internal table:

itab = VALUE #( ( a = 1 b = 'aaa' )
                ( a = 2 b = 'bbb' )
                ( LINES OF itab2 ) "All lines of itab2
                ( LINES OF itab3 FROM 2 TO 5 ) ). "Specific lines of itab3

Using the inline construction of structures and internal tables, you can avoid the declaration of extra variables in many contexts, especially ABAP SQL statements. See the following examples:

"Modification of individual internal table entries based on a structure created inline
MODIFY TABLE some_itab FROM VALUE #( a = 1 ... ). "Modifying a table line

INSERT VALUE #( a = 2 ... ) INTO TABLE some_itab. "Inserting a table line

DELETE TABLE some_itab FROM VALUE #( a = 3 ). "Deleting a table line

"Modifying multiple database table entries based on an internal table constructed inline
MODIFY scarr FROM TABLE @( VALUE #(
          ( carrid = 'XY'
            carrname = 'XY Airlines'
            currcode = 'USD'
            url =  'some_url' )
          ( carrid = 'ZZ'
            carrname = 'ZZ Airways'
            currcode = 'EUR'
            url =  'some_url' )
          ) ).

Some of the additions and concepts mentioned here are also valid for other constructor expressions further down but not necessarily mentioned explicitly. See the details on the syntactical options of the constructor operators in the ABAP Keyword Documentation.

CORRESPONDING

  • The components or columns of the target data object are filled using assignments of the parameters specified in the parentheses.
  • Pay attention to the assignment and conversion rules to avoid errors when using the operator. Consider, for example, the impact of assigning the values of identically named fields having different types (e.g a field is of type c another field is of type string).

The following list includes a selection of various possible variants for this constructor operator. There are more variants available like the addition EXACT, using a lookup table, the option of discarding duplicates or RAP-specific variants that are not part of this cheat sheet. Find the details in the relevant topic.

  • BASE: Keeps original values. Unlike, for example, the operator VALUE, the parentheses must be set around BASE.
  • MAPPING: Enables the mapping of component names, i. e. a component of a source structure or source table can be assigned to a differently named component of a target structure or target table (e. g. MAPPING c1 = c2).
  • EXCEPT: You can specify components that should not be assigned content in the target data object. They remain initial. In doing so, you exclude identically named components in the source and target object that are not compatible or convertible from the assignment to avoid syntax errors or runtime errors.
  • DEEP: Relevant for deep tabular components. They are resolved at every hierarchy level and identically named components are assigned line by line.
  • $[DEEP$] APPENDING: Relevant for (deep) tabular components. It ensures that the nested target tables are not deleted. The effect without DEEP is that lines of the nested source table are added using CORRESPONDING without addition. The effect with DEEP is that lines of the nested source table are added using CORRESPONDING with the addition DEEP.

See the executable example for demonstrating the effect of the variants:

struc2 = CORRESPONDING #( struc1 ).
tab2 = CORRESPONDING #( tab1 ).

"BASE
struc2 = CORRESPONDING #( BASE ( struc2 ) struc1 ).
tab2 = CORRESPONDING #( BASE ( tab2 ) tab1 ).

"MAPPING/EXACT
struc2 = CORRESPONDING #( struc1 MAPPING comp1 = comp2 ).
tab2 = CORRESPONDING #( tab1 EXCEPT comp1 ).

"Complex assignments with deep components using further additions
st_deep2 = CORRESPONDING #( DEEP st_deep1 ).
st_deep2 = CORRESPONDING #( DEEP BASE ( st_deep2 ) st_deep1 ).
st_deep2 = CORRESPONDING #( APPENDING ( st_deep2 ) st_deep1 ).
st_deep2 = CORRESPONDING #( DEEP APPENDING ( st_deep2 ) st_deep1 ).

Note

CORRESPONDING operator versus MOVE-CORRESPONDING: Although the functionality is the same, note that, as the name implies, constructor operators "construct" and - without the addition BASE - target objects are initialized. Hence, the following two statements are not the same:

struc2 = CORRESPONDING #( struc1 ).
MOVE-CORRESPONDING struc1 TO struc2. "Not matching components are not initialized

NEW

  • The operator has the same capabilities to construct a result as the VALUE operator and basically replaces CREATE DATA and CREATE OBJECT.
  • In case of creating instances, the type name of an expression with NEW is the name of a class (if the name cannot be derived using #). Either the content within the parentheses remains empty or, if a constructor method is defined, the content is a list of parameter bindings for the constructor method.
  • A big advantage of using the NEW for object creation is method chaining, i. e. there is no need to declare an extra variable.

Examples:

"Data references
"Declare data reference variables
DATA dref1 TYPE REF TO i.    "Complete type
DATA dref2 TYPE REF TO data. "Generic type

"Create anonymous data objects
dref1 = NEW #( ).
dref2 = NEW string( ).

"Directly assigning values
dref1 = NEW #( 123 ).
dref2 = NEW string( `hallo` ).

"Use inline declarations to omit a prior declaration of a variable.
DATA(dref3) = NEW i( 456 ).

"Object references
"Declare object reference variables
DATA oref1 TYPE REF TO cl1. "Class without constructor
DATA oref2 TYPE REF TO cl2. "Class with constructor

"Create instances of classes
oref1 = NEW #( ).
"List the parameter bindings for the constructor method
"If there's only one parameter, the explicit specification of the
"parameter name is not needed and the value can be specified directly
oref2 = NEW #( p1 = ... p2 = ... ).

"Use inline declaration
DATA(oref2) = NEW cl2( p1 = ... p2 = ... ).

"Method chaining
"Assume the method meth has an importing parameter int of type REF TO i
... = NEW cl1( )->meth( int = NEW #( 5 ) ).

CONV

  • The CONV operator enforces conversions from one type to another and creates an appropriate result.

  • The operator is particularly suitable for avoiding the declaration of helper variables.

Examples:

DATA(a) = CONV decfloat34( 1 / 5 ). "0.2
DATA(b) = 1 / 5. "Comparison with an expression without CONV; result is 0

Excursion: As outlined above, you can construct structures and internal tables using the VALUE operator. Using this operator for constructing elementary data objects is not possible apart from creating a data object with an initial value, for example DATA(str) = VALUE string( ).. The CONV operator closes this gap. However, in some cases, the use of CONV is redundant.

DATA(c) = CONV decfloat34( '0.4' ).
"Instead of
DATA d TYPE decfloat34 VALUE '0.4'.

"Redundant conversion
DATA(e) = `hallo`. "Derives the string type automatically.
"DATA(f) = CONV string( `hallo` ). "Produces a syntax warning

EXACT

Examples:

"Leads to a data loss when converting to a data object accepting only a single character
TRY.
  DATA(exact1) = EXACT abap_bool( 'XY' ).
  CATCH CX_SY_CONVERSION_DATA_LOSS INTO DATA(error1).
ENDTRY.

"The calculation cannot be executed exactly; a rounding is necessary
TRY.
  DATA(exact2) = EXACT decfloat34( 1 / 3 ).
  CATCH CX_SY_CONVERSION_ROUNDING INTO DATA(error2).
ENDTRY.

REF

  • The type specified after REF and directly before the first parenthesis determines the static type of the result.
  • The operator replaces GET REFERENCE and is particularly useful for avoiding the declaration of helper variables that are only necessary, for example, to specify data reference variables as actual parameters.

Examples:

"Data references
"Declare data object and assign value
DATA number TYPE i VALUE 5.

"Declare data reference variable
DATA dref_a TYPE REF TO i.

"Get references
dref_a = REF #( number ).
DATA(dref_b) = REF string( `hallo` ). "Inline declaration and explicit type specification

"Object references
DATA(oref_a) = NEW some_class( ).
DATA(oref_b) = REF #( oref_a ).

CAST

  • Using the CAST operator, you can carry out upcasts and downcasts and create a reference variable of the static type as a result.
  • The operator is particularly helpful for avoiding the declaration of helper variables that are only necessary for downcasts.

Run Time Type Identification (RTTI) examples:

"Getting component information
DATA(components) =
  CAST cl_abap_structdescr(
    cl_abap_typedescr=>describe_by_data( some_object ) )->components.

"Getting method information
DATA(methods) =
  CAST cl_abap_objectdescr(
    cl_abap_objectdescr=>describe_by_name( 'LOCAL_CLASS' )
        )->methods.

COND

  • There can be multiple logical expressions initiated by WHEN followed by the result specified after THEN. If none of the logical expressions are true, you can specify an ELSE clause at the end. If this clause is not specified, the result is the initial value of the specified or derived data type.
  • Note that all operands specified after THEN must be convertible to the specified or derived data type.

Example:

DATA(b) = COND #( WHEN a BETWEEN 1 AND 3 THEN w
                  WHEN a > 4 THEN x
                  WHEN a IS INITIAL THEN y
                  ELSE z ).

SWITCH

The SWITCH operator is fairly similar to the COND operator and works in the style of CASE statements, i. e. it uses the value of only a single variable that is checked in the case distinction.

DATA(b) = SWITCH #( a
                    WHEN 1 THEN w
                    WHEN 2 THEN x
                    WHEN 3 THEN y
                    ELSE z ).

FILTER

  • The FILTER operator constructs an internal table line by line based on an existing table and conditions specified in a WHERE clause.
  • The conditions can either be based on single values or a filter table
  • Additions:

  • EXCEPT: The specification of EXCEPT means that those lines of the existing table are used that do not meet the condition specified in the WHERE clause. Hence, if EXCEPT is not specified, the lines of the existing table are used that meet the condition.

Examples:

DATA(f1) = FILTER #( tab WHERE comp > 5 ).
DATA(f2) = FILTER #( tab EXCEPT WHERE comp < 3 ).
DATA(f3) = FILTER #( tab USING KEY x WHERE comp = 4 ).

"Filtering based on another table
DATA(f3) = FILTER #( tab IN filter_tab
                     WHERE comp = 3 ).

REDUCE

  • It basically reduces sets of data objects to a single data object. For example, the numeric values of a table column are summed up. As a result, the overall number is constructed.

The following example calculates the total of the numbers from 1 to 10 using the REDUCE operator:

DATA(sum) = REDUCE i( INIT s = 0
                      FOR  i = 1 UNTIL i > 10
                      NEXT s += i ) ). "sum: 55

Notes:

  • INIT ...: A temporary variable is specified that sets an initial value for the result variable.
  • FOR ...: Represents a loop. The loop is carried out until the condition is met after UNTIL.
  • NEXT ...: Represents the assignment to the temporary variable after every iteration.
  • Once the loop has finished, the target variable is assigned the resulting value.

Iteration Expressions with FOR

  • Such expressions are possible in the following contexts:
  • REDUCE: The reduction result is created in the iteration steps.

  • NEW and VALUE: Used in the context of looping across internal tables. New table lines are created in the iteration steps and inserted into a target table.

FOR ... WHILE (see FOR ... UNTIL in the REDUCE section): The following example with REDUCE has the same effect as the example using UNTIL shown above.

DATA(sum) = REDUCE i( INIT y = 0
                      FOR n = 1 THEN n + 1 WHILE n < 11
                      NEXT y += n ).

FOR ... IN:

  • The operand specified after FOR represents an iteration variable, i. e. a work area, that contains the data while looping across the table.
  • This variable is only visible within the FOR expression, i. e. it cannot be used outside of the expression.
  • The type of the variable is determined by the type of the internal table specified after IN.
  • One or more iteration expressions can be specified using FOR.
  • The components or the whole table line that should be returned are specified within the pair of parentheses before the closing parenthesis.
  • In contrast to LOOP statements, the sequential processing cannot be debugged.

Some examples for looping across tables and storing values in target tables:

"Loop across table and store the whole line in a new table;
"target table must have the same table type as source table itab;
"without the WHERE condition, all lines are considered
TYPES t_type LIKE itab.

... = VALUE t_type( FOR wa IN itab
                    "WHERE ( comp1 > 2 )
                    ( wa ) ).

"Store specific components having different names by specifying the assignment individually;
"assumption: target type is not compatible to the type of itab;
"a field mapping is provided; pay attention to potential type conversion
... = VALUE t_type( FOR wa IN itab
                    "WHERE ( comp1 > 2 )
                    ( compX = wa-comp1
                      compY = wa-comp2 ) ).

"Store specific components having the same names;
"assumption: Target type is not compatible to the type of itab;
"if there are identically named components in the table types, you might also use CORRESPONDING
... = VALUE t_type( FOR wa IN itab
                    "WHERE ( comp1 > 2 )
                    ( CORRESPONDING #( wa ) ) ).

"Multiple iteration expressions
... = VALUE t_type( FOR wa1 IN itab1 WHERE ( comp1 = 4 )
                    FOR wa2 IN itab2 WHERE ( comp2 > 5 )
                    FOR wa3 IN itab3 WHERE ( comp3 < 3 )
                    ( compX = wa1-comp1
                      compY = wa2-comp2
                      compZ = wa3-comp3 ) ).

LET Expressions

  • LET expressions allow you to declare local helper fields (variables or fields symbols) and assign values (the type is derived from the defined value) to be used in constructor expressions, for example, in iteration expressions using FOR or results specified in the conditional expressions of COND and SWITCH.
  • Note that the helper field is only valid in the context in which the LET expression is specified.

Examples:

"Create a string table using a LET expression
DATA(str_tab) = VALUE string_table( LET it = `be` IN
                    ( |To { it } is to do| )
                    ( |To { it } or not to { it }| )
                    ( |To do is to { it }| )
                    ( |Do { it } do { it } do| ) ).

"Conditional expressions
DATA(a) = COND #( LET b = c IN
                  WHEN b > x THEN ...
                  WHEN b < y THEN ...
                  ...
                  ELSE ... ).

Demonstration Program

The example Working with Constructor Expressions demonstrates the constructor expressions outlined above in one program.






Fill RESBD Structure from EBP Component Structure   Fill RESBD Structure from EBP Component Structure  
This documentation is copyright by SAP AG.

Length: 37991 Date: 20240509 Time: 085033     sap01-206 ( 329 ms )