From 75a48225179b95ddf8b0baeaba79eef56aeffa79 Mon Sep 17 00:00:00 2001
From: danrega <16720986+danrega@users.noreply.github.com>
Date: Wed, 2 Aug 2023 14:15:03 +0200
Subject: [PATCH] Update content
---
06_Dynamic_Programming.md | 731 ++++++++++++++-----
16_Data_Types_and_Objects.md | 4 +-
src/zcl_demo_abap_display.clas.abap | 73 +-
src/zcl_demo_abap_dynamic_prog.clas.abap | 867 +++++++++++++++++------
4 files changed, 1237 insertions(+), 438 deletions(-)
diff --git a/06_Dynamic_Programming.md b/06_Dynamic_Programming.md
index 2742a5c..13e9c61 100644
--- a/06_Dynamic_Programming.md
+++ b/06_Dynamic_Programming.md
@@ -9,6 +9,9 @@
- [Data References](#data-references)
- [Dynamic ABAP Statements](#dynamic-abap-statements)
- [Runtime Type Services (RTTS)](#runtime-type-services-rtts)
+ - [Getting Type Information at Runtime](#getting-type-information-at-runtime)
+ - [Dynamically Creating Data Types at Runtime](#dynamically-creating-data-types-at-runtime)
+ - [Dynamically Creating Data Objects at Runtime](#dynamically-creating-data-objects-at-runtime)
- [More Information](#more-information)
- [Executable Example](#executable-example)
@@ -26,7 +29,7 @@
- The name `itab` of the data object is determined at compile time and remains stable throughout the execution of the program.
- However, there can also be use cases where the attributes of such a data object are not statically determined. This is where dynamic aspects enter the picture: Attributes, names, types etc. are not determined at compile time but rather at runtime.
- There are ABAP statements that include these dynamic aspects in the syntax. Assume you have a simple program and a UI that includes an input field storing the input in a data object named `dbtab`. As input, you expect the name of a database table to be provided. In the end, you want to retrieve all entries of the database table and store them in an internal table. This table should be displayed. So, there is random input at runtime and your program must be able to deal with it.
- - See the following `SELECT` statement. As also shown further down, the `FROM` clause does not include a statically defined table to be selected from. Instead, there is a pair of parentheses including a data object. Assume the data object holds the name of the database table. At runtime, the data retrieval happens from the database table that was inserted in the input field.
+ - See the following `SELECT` statement. The `FROM` clause does not include a statically defined table to be selected from. Instead, there is a pair of parentheses including a data object. It is a character-like data object. Assume the data object holds the name of the database table. At runtime, the data retrieval happens from the database table that was inserted in the input field.
```abap
DATA(dbtab) = `ZDEMO_ABAP_FLI`.
@@ -38,8 +41,8 @@
- Further aspects for dynamic programming in ABAP enter the picture if you want to determine information about data types and data objects at runtime ([RTTI](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_identific_glosry.htm)) or even create them ([RTTC](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_creation_glosry.htm)).
-- In general, dynamic programming also comes with some downsides. For example, the ABAP compiler cannot check the dynamic programming feature like the `SELECT` statement mentioned above. There is no syntax warning or suchlike. The checks are performed at runtime only which has an impact on the performance. Plus, the testing of [procedures](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenprocedure_glosry.htm "Glossary Entry")
-that include dynamic programming features is difficult.
+- In general, dynamic programming also comes with some downsides. For example, the ABAP compiler cannot check the dynamic programming feature like the `SELECT` statement mentioned above. There is no syntax warning or suchlike. The checks are performed only at runtime, which has an impact on the performance. Plus, the testing of [procedures](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenprocedure_glosry.htm "Glossary Entry")
+that include dynamic programming features may be difficult.
(back to top)
@@ -47,7 +50,7 @@ that include dynamic programming features is difficult.
## Excursion: Field Symbols and Data References
[Field symbols](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenfield_symbol_glosry.htm "Glossary Entry")
-and [data references](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_reference_glosry.htm "Glossary Entry") are dealt with here since they are supporting elements for dynamic programming.
+and [data references](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_reference_glosry.htm "Glossary Entry") are covered here since they are supporting elements for dynamic programming.
### Field Symbols
@@ -58,7 +61,7 @@ Field symbols ...
- can be used as placeholders for a data object at an [operand position](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenoperand_position_glosry.htm).
- Consider there is a data object in your program. A field symbol is also available that is assigned the memory area of this data object. Accessing a field symbol is like accessing the [named data object](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abennamed_data_object_glosry.htm) or part of the object itself.
- do not reserve physical space in the [data area](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_area_glosry.htm) of a program like a data object. Instead, they work as dynamic identifiers of a memory area in which a specific data object or part of an object is located.
-- can be typed either with [generic data types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abengeneric_data_type_glosry.htm "Glossary Entry") or [complete data types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abencomplete_data_type_glosry.htm "Glossary Entry").
+- can be typed either with [generic data types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abengeneric_data_type_glosry.htm "Glossary Entry") or [complete data types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abencomplete_data_type_glosry.htm "Glossary Entry").
- are declared using the statement [`FIELD-SYMBOLS`](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abapfield-symbols.htm) or the [declaration operator](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendeclaration_operator_glosry.htm) [`FIELD-SYMBOL`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenfield-symbol_inline.htm). Their names must be included between angle brackets.
**Declaring field symbols**
@@ -75,12 +78,15 @@ FIELD-SYMBOLS: TYPE i,
LIKE some_data_object.
"Examples for generic types
-FIELD-SYMBOLS TYPE data.
-FIELD-SYMBOLS TYPE any table.
+FIELD-SYMBOLS TYPE c. "Text field with a generic length
+FIELD-SYMBOLS TYPE csequence. "Text-like (c, string)
+FIELD-SYMBOLS TYPE data. "Any data type
+FIELD-SYMBOLS TYPE any table. "Internal table with any table type
"Declaring field symbols inline
-"In an inline declaration, the typing of the field symbol is done with the generic type data.
-"Prominent use case: Inline declaration of a field symbol for an internal table.
+"In an inline declaration, the typing of the field symbol is done
+"with the generic type data.
+"Example use case: Inline declaration of a field symbol for an internal table.
LOOP AT itab ASSIGNING FIELD-SYMBOL().
...
ENDLOOP.
@@ -122,14 +128,14 @@ FIELD-SYMBOLS TYPE data.
ASSIGN num TO .
ASSIGN struc TO .
ASSIGN tab TO .
-ASSIGN num TO . "Could be any of the data objects
+ASSIGN num TO . "Could be any of the data objects
"Inline declaration is possible, too. The type
"is automatically derived.
ASSIGN num TO FIELD-SYMBOL().
-"CASTING addition for matching types of data object and field symbol
-"when assigning memory areas
+"CASTING addition for matching types of data object and field
+"symbol when assigning memory areas
TYPES c_len_3 TYPE c LENGTH 3.
DATA(chars) = 'abcdefg'.
@@ -142,6 +148,9 @@ FIELD-SYMBOLS TYPE data.
"Explicit casting
ASSIGN chars TO CASTING TYPE c_len_3.
+
+DATA chars_l4 TYPE c LENGTH 4.
+ASSIGN chars TO CASTING LIKE chars_l4.
```
> **š” Note**
@@ -158,10 +167,10 @@ ASSIGN chars TO CASTING TYPE c_len_3.
> ```
>- See more information on the addition `CASTING` [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapassign_casting.htm).
-**Field symbols in use**
+**Examples using field symbols**
``` abap
-"For example, in assignments
+"Assignments
DATA num TYPE i VALUE 1.
FIELD-SYMBOLS TYPE i.
ASSIGN num TO .
@@ -171,7 +180,7 @@ ASSIGN num TO .
"Loops
"Here, field symbols are handy since you can avoid an
-"actual copying of the table line to boost performance.
+"actual copying of the table line.
SELECT *
FROM zdemo_abap_fli
INTO TABLE @DATA(itab).
@@ -181,11 +190,12 @@ FIELD-SYMBOLS LIKE LINE OF itab.
LOOP AT itab ASSIGNING .
-carrid = ... "The field symbol represents a line of the table.
-connid = ... "Components are accessed with the component selector.
- "Here, a new value is assigned.
+ "Here, it is assumed that a new value is assigned.
...
ENDLOOP.
-"Inline declaration of field symbol
+"Inline declaration of a field symbol. It receives a suitable
+"type automatically.
LOOP AT itab ASSIGNING FIELD-SYMBOL().
-carrid = ...
-connid = ...
@@ -201,8 +211,7 @@ ENDLOOP.
...
- are references that point to any data object or to their parts (for example, components, lines of internal tables).
-- are contained in [data reference
- variables](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_reference_variable_glosry.htm "Glossary Entry")
+- are contained in [data reference variables](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_reference_variable_glosry.htm "Glossary Entry")
in ABAP programs.
[Data reference variables](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_reference_variable_glosry.htm "Glossary Entry")
@@ -216,95 +225,153 @@ ENDLOOP.
> **š” Note**
> [Object references](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenobject_reference_glosry.htm "Glossary Entry")
-and [object reference variables](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenobject_refer_variable_glosry.htm "Glossary Entry") are not part of this cheat sheet. To get more details, refer to the ABAP Keyword Documentation or the cheat sheet [ABAP Object Orientation](04_ABAP_Object_Orientation.md).
+and [object reference variables](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenobject_refer_variable_glosry.htm "Glossary Entry") are not part of this cheat sheet. To get more details, refer to the [ABAP Keyword Documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenobject_reference_type.htm) or the cheat sheet [ABAP Object Orientation](04_ABAP_Object_Orientation.md).
**Declaring data reference variables**
``` abap
-"Example declarations of data reference variables
-"Note that they do not yet point to a data object.
-DATA: ref1 TYPE REF TO i, "Complete data type
- ref2 TYPE REF TO some_dbtab, "Complete data type
- ref3 LIKE REF TO some_data_object,
- ref4 TYPE REF TO data. "Generic data type
+"Example declarations of data reference variables with static types.
+"The static types can be complete or generic (but only data can be used).
+"Note that they do not yet point to a data object. At this stage,
+"initial reference variables contain null references.
+DATA: ref_a TYPE REF TO i, "Complete data type
+ ref_b TYPE REF TO some_dbtab, "Complete data type
+ ref_c LIKE REF TO some_data_object,
+ ref_d TYPE REF TO data, "Generic data type
+ ref_e LIKE ref_a. "Referring to an existing data reference variable
```
-**Creating data references to existing data objects** using the
+As shown below, instead of the explicit declaration, inline declarations are also possible.
+See also the cheat sheet [Data Types and Data Objects](16_Data_Types_and_Objects.md).
+
+**Assigning references to existing data objects** using the
[reference operator](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenreference_operator_glosry.htm "Glossary Entry")
`REF`.
``` abap
"Declaring a data object
-
DATA num TYPE i VALUE 5.
"Declaring data reference variables
-
DATA ref1 TYPE REF TO i.
DATA ref_gen TYPE REF TO data.
"Creating data references to data objects.
-"The # sign means that the type is derived from the context.
+"The # character stands for a data type that is determined in the
+"following hierarchy:
+"- If the data type required in an operand position is unique and
+" known completely, the operand type is used.
+"- If the operand type cannot be derived from the context, the
+" data type of the data object within the parentheses is used.
+"- If the data type of the data object within the parentheses is
+" not known statically, the generic type data is used.
ref1 = REF #( num ).
ref_gen = REF #( num ).
-"You can also use inline declarations to omit the explicit declaration.
-
+"Creating a data reference variable inline.
+"Note: No empty parentheses can be specified after REF.
DATA(ref2) = REF #( num ).
-"You can explicitly specify the data type after REF.
+"Data reference variable of type ref to data by specifying the
+"generic type data after REF
+DATA(ref3) = REF data( ... ).
-DATA(ref3) = REF string( `hallo` ).
+"A non-generic type can be used; only if an upcast works (see
+"upcasts below)
+DATA(ref3) = REF some_type( ... ).
-"The older syntax GET REFERENCE having the same effect should not be used anymore.
+"The older syntax GET REFERENCE having the same effect should
+"not be used anymore.
"GET REFERENCE OF num INTO ref1.
-"GET REFERENCE OF num INTO DATA(ref4).
+"GET REFERENCE OF num INTO DATA(ref5).
```
-**Creating new data objects at runtime**: You create an [anonymous
-data object](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenanonymous_data_object_glosry.htm "Glossary Entry")
-at runtime by assigning the reference to the data object of a data reference variable. You can use the [instance
-operator](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abeninstance_operator_glosry.htm "Glossary Entry")
-[`NEW`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenconstructor_expression_new.htm).
-It replaces the older syntax [`CREATE DATA`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapcreate_data.htm). However, as shown below, `CREATE DATA` is required for specifying a dynamically determined type.
+**Creating new data objects at runtime**:
+[Anonymous data objects](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenanonymous_data_object_glosry.htm "Glossary Entry") ...
+- are dynamically created at runtime.
+- are relevant if the data type is only known when the program is executed.
+- cannot be addressed by a name (-> "anonymous").
+- expect a data reference variable when declared. The content of an anonymous data object can only be accessed using dereferenced variables as shown below or field symbols.
+- can be created using the statement [`CREATE DATA`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapcreate_data.htm), the instance operator [`NEW`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenconstructor_expression_new.htm), or the addition [`NEW`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapselect_into_target.htm) of the `INTO` clause in a `SELECT` statement.
-``` abap
-"Declaring data reference variables
+> **š” Note**
+> The following snippet covers statically defined types. Data objects can also be created with `CREATE DATA` dynamically using dynamic type definitions (the type name is specified within a pair of parentheses) and type description objects ([`TYPE HANDLE` addition](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abapcreate_data_handle.htm)) as shown further down.
+> Using [`CREATE OBJECT`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapcreate_object.htm) statements, you can create an object as an instance of a class and assign the reference to the object to an [object reference variable](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenobject_refer_variable_glosry.htm). Find more information in the [ABAP Keyword Documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapcreate_object.htm).
-DATA ref1 TYPE REF TO i. "Complete type
-DATA ref_gen TYPE REF TO data. "Generic type
+```abap
+"CREATE DATA statements
+"Note that there are many additions available. The examples
+"show a selection. Behind TYPE and LIKE, the syntax offers
+"the same possibilities as the DATA statement.
-"Creating anonymous data objects
-"Using the # sign and the explicit type: see REF #( ) above.
+"Creating an anonymous data object with an implicit type.
+"If neither of the additions TYPE or LIKE are specified, the
+"data reference variable must be completely typed.
+DATA dref_1 TYPE REF TO string.
+CREATE DATA dref_1.
-ref1 = NEW #( ).
-ref_gen = NEW string( ).
+"Creating anonymous data objects with explicit data type
+"specification.
+"Data reference variable with a generic type to be used in
+"the following examples for the anonymous data object.
+DATA dref_2 TYPE REF TO data.
-"For directly assigning values, insert the values within the parentheses.
+"Elementary, built-in ABAP type
+CREATE DATA dref_2 TYPE p LENGTH 8 DECIMALS 3.
-ref1 = NEW #( 123 ).
+"Anomyous internal table ...
+"using the LIKE addition to refer to an existing internal table
+DATA itab TYPE TABLE OF zdemo_abap_carr.
+CREATE DATA dref_2 LIKE itab.
-"Using inline declarations to omit a prior declaration of a variable.
+"by specifying the entire table type
+CREATE DATA dref_2 TYPE HASHED TABLE OF zdemo_abap_carr
+ WITH UNIQUE KEY carrid.
-DATA(ref2) = NEW i( 456 ).
+"Anonymous structures
+CREATE DATA dref_2 LIKE LINE OF itab.
+CREATE DATA dref_2 TYPE zdemo_abap_carr.
-TYPES i_table TYPE STANDARD TABLE OF i WITH EMPTY KEY.
+"Creating reference variable
+CREATE DATA dref_2 TYPE REF TO itab.
-DATA(ref3) = NEW i_table( ( 1 ) ( 2 ) ( 3 ) ( 4 ) ( 5 ) ).
+"NEW operator
+"- Works like CREATE DATA dref TYPE type statements and can
+" be used in general expression positions.
+"- Allows to assign values to the new anonymous data objects
+" in parentheses
-"CREATE DATA statements (older syntax)
-"DATA ref4 TYPE REF TO string.
-"DATA ref5 TYPE REF TO data.
+"Creating data reference variables
+DATA: dref_3 TYPE REF TO i,
+ dref_4 TYPE REF TO data.
-"CREATE DATA ref4.
+"# character after NEW if the data type can be identified
+"completely instead of the explicit type specification (only
+"non-generic types possible)
+dref_3 = NEW #( 123 ).
+dref_3 = NEW i( 456 ).
+dref_4 = NEW zdemo_abap_carr( ). "not assigning any values
+dref_4 = NEW string( `hi` ).
-"Note: TYPE ... needed because of generic type data
-"CREATE DATA ref5 TYPE p LENGTH 6 DECIMALS 2.
+"Creating anonymous data objects inline
+"In doing so, you can omit a prior declaration of a variable.
+DATA(dref_5) = NEW i( 789 ).
+DATA(dref_6) = NEW zdemo_abap_carr( carrid = 'AB'
+ carrname = 'AB Airlines' ).
-"CREATE DATA ref5 LIKE ref4.
-```
+"ABAP SQL SELECT statements
+"Using the NEW addition in the INTO clause, an anonymous data
+"object with a suitable type can be created in place.
+SELECT *
+ FROM zdemo_abap_carr
+ INTO TABLE NEW @DATA(dref_7). "internal table
-**Assigning existing data references** to other data references. As mentioned above regarding the assignment, note that static types of both data
+SELECT SINGLE *
+ FROM zdemo_abap_carr
+ INTO NEW @DATA(dref_8). "structure
+```
+
+**Assignments between two data reference variables**. As mentioned above regarding the assignment, note that static types of both data
reference variables must be compatible. As a result of an assignment, both the target reference variable and the source reference variable point to the same data object.
Excursion: Static vs. dynamic type, upcasts and downcasts
@@ -432,6 +499,8 @@ ref_generic = NEW i( ).
"In older ABAP releases, CREATE DATA statements were needed.
CREATE DATA ref_generic TYPE i.
+"As mentioned above, the content of anonymous data objects can only be
+"accessed using dereferenced data variables and field symbols.
"The only option to access the variable in older releases was via field symbols.
ASSIGN ref_generic->* TO FIELD-SYMBOL().
= 123.
@@ -449,11 +518,11 @@ SELECT *
INTO TABLE @ref_sel->*.
```
-**Data references in use**
+**Examples using data references**
Some example contexts of using data references are as follows:
-**Overwriting data reference variables**:
+*Overwriting data reference variables*:
``` abap
dref = NEW i( 1 ).
@@ -462,7 +531,7 @@ dref = NEW i( 1 ).
dref = NEW i( 2 ).
```
-**Retaining data references**:
+*Retaining data references*:
``` abap
"This snippet shows that three data references are created
@@ -486,12 +555,13 @@ DO 3 TIMES.
ENDDO.
```
-**Processing internal tables**:
+*Processing internal tables*:
``` abap
"Similar use case to using field symbols: In a loop across an internal table,
-"you can store the content of the line in a data reference variable
+"you assign the content of the line in a data reference variable
"instead of actually copying the content to boost performance.
+"Again, the inline declaration comes in handy.
"Filling an internal table.
SELECT *
@@ -500,15 +570,17 @@ SELECT *
LOOP AT fli_tab REFERENCE INTO DATA(ref).
- "A component of the table line might be addressed.
+ "A component of the table line may be addressed.
+ "Note the object component selector; the dereferencing operator together
+ "with the component selector is also possible: ->*-
ref->carrid = ...
...
ENDLOOP.
```
-**Data reference variables as part of structures and internal tables**:
+*Data reference variables as part of structures and internal tables*:
``` abap
-"In contrast to field symbols, data reference variables can be used as
+"Unlike field symbols, data reference variables can be used as
"components of structures or columns in internal tables.
"Structure
@@ -529,8 +601,8 @@ itab[ 1 ]-ref->* = 123.
```
> **āļø Hint**
-> The question might now arise when to actually use either a field symbol
-or a data reference variable. It depends on your use case. However, data
+> When to actually use either a field symbol
+or a data reference variable? It depends on your use case. However, data
reference variables are more powerful as far as their usage options are
concerned, and they better fit into the modern (object-oriented) ABAP
world. Recommended read: [Accessing Data Objects Dynamically (F1 docu for standard ABAP)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abendyn_access_data_obj_guidl.htm "Guideline").
@@ -540,7 +612,18 @@ world. Recommended read: [Accessing Data Objects Dynamically (F1 docu for standa
## Dynamic ABAP Statements
As already mentioned above, there are ABAP statements that support the dynamic specification of syntax elements.
-In this context, you can usually use elementary, character-like data objects - the content is usually provided in capital letters - specified within a pair of parentheses. In the `SELECT` list of an ABAP SQL `SELECT` statement, for example, you can use a standard table with a character-like row type. The dynamically specified syntax elements can be included as operands in various ABAP statements. The following code snippets are intended to give you an idea and rough overview.
+In this context, you can usually use elementary, character-like data objects - the content is usually provided in capital letters - specified within a pair of parentheses.
+``` abap
+"Named, character-like data object specified within parenteses
+"used by an ABAP statement
+DATA(field_name) = 'CARRNAME'.
+SORT itab BY (field_name).
+
+"Unnamed, character-like data object specified within parenteses
+SORT itab BY ('CURRCODE').
+```
+
+In the `SELECT` list of an ABAP SQL `SELECT` statement, for example, you can use a standard table with a character-like row type. The dynamically specified syntax elements can be included as operands in various ABAP statements. The following code snippets are intended to provide a rough overview.
Note that dynamically specifying syntax elements has downsides, too. Consider some erroneous character-like content of such data objects. There is no syntax warning. At runtime, it can lead to runtime errors.
@@ -555,11 +638,11 @@ Note that dynamically specifying syntax elements has downsides, too. Consider so
FROM zdemo_abap_carr
INTO TABLE @DATA(itab).
- "Named data object
+ "Named data object specified within parenteses
DATA(field_name) = 'CARRNAME'.
- SORT itab BY (field_name).
+ SORT itab BY (field_name).
- "Unnamed data object
+ "Unnamed data object specified within parenteses
SORT itab BY ('CURRCODE').
"READ TABLE: Dynamically specifying keys
@@ -584,7 +667,7 @@ Note that dynamically specifying syntax elements has downsides, too. Consider so
- `ASSIGN` statements
``` abap
- "Dynamically accessing components of structures
+ "Dynamically assigning components of structures
"Populating a structure
SELECT SINGLE *
@@ -598,29 +681,33 @@ Note that dynamically specifying syntax elements has downsides, too. Consider so
ASSIGN wa-(comp_name) TO . "named data object
ASSIGN wa-('CARRID') TO . "unnamed data object
- "The statements set sy-subrc value. No exception occurs in case of an unsuccessful assignment.
+ "The statements set sy-subrc value. No exception occurs in
+ "case of an unsuccessful assignment.
ASSIGN wa-('XYZ') TO .
IF sy-subrc <> 0.
...
ENDIF.
- "Numeric expressions are possible. Its value is interpreted as the position
- "of the component in the structure.
+ "Numeric expressions are possible. Its value is interpreted
+ "as the position of the component in the structure.
ASSIGN wa-(4) TO .
- "If the value is 0, the memory area of the entire structure is assigned to the field symbol.
+ "If the value is 0, the memory area of the entire structure is
+ "assigned to the field symbol.
ASSIGN wa-(0) TO .
"The statements above replace the following, older statements.
ASSIGN COMPONENT 'CARRID' OF STRUCTURE wa TO .
ASSIGN COMPONENT 5 OF STRUCTURE wa TO .
- "Populating a structure that is referenced by a data reference variable
+ "Populating a structure that is referenced by a data reference
+ "variable
SELECT SINGLE *
FROM zdemo_abap_carr
INTO NEW @DATA(ref_struc).
- "Note the object component selector. The field symbol is created inline here.
+ "Note the object component selector. The field symbol is created
+ "inline here.
ASSIGN ref_struc->('CARRNAME') TO FIELD-SYMBOL().
*************************************************************
@@ -633,35 +720,57 @@ Note that dynamically specifying syntax elements has downsides, too. Consider so
ASSIGN (cl_name)=>some_dobj TO .
ASSIGN (cl_name)=>(dobj) TO .
- "Class reference variable pointing to an object that contains attributes
- "and that are specified dynamically.
+ "Class reference variable pointing to an object that contains
+ "attributes and that are specified dynamically.
DATA cl_ref TYPE REF TO cl_some_class.
cl_ref = NEW #( ).
ASSIGN cl_ref->('some_attribute') TO FIELD-SYMBOL().
- "If ELSE UNASSIGN is specified, no memory area is assigned to the field symbol.
- "It has the state unassigned after the ASSIGN statement.
+ "If ELSE UNASSIGN is specified, no memory area is assigned to
+ "the field symbol. It has the state unassigned after the ASSIGN
+ "statement.
ASSIGN cl_ref->('attr_xyz') TO FIELD-SYMBOL() ELSE UNASSIGN.
```
-- Dynamically specifying data types
+- Dynamically specifying data types/creating (data) objects
+
+ > **š” Note**
+ > - For dynamic syntax elements in `CREATE OBJECT` statements, find more information [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapcreate_object_explicit.htm) (note that parameters can be specified dynamically, too).
+ > - In addition to character-like data objects for the type name specified in the parentheses, you can also use [absolute type names](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabsolute_typename_glosry.htm) (see the information about RTTI below).
``` abap
- "Anonymous data objects are created using a type determined at runtime.
- "Note that the NEW operator cannot be used here.
-
+ "Anonymous data objects are created using a type determined at
+ "runtime. See more information below. Note that the NEW operator
+ "cannot be used here.
CREATE DATA dref TYPE (some_type).
CREATE DATA dref TYPE TABLE OF (some_type).
+ CREATE DATA dref TYPE REF TO (some_type).
- "Assigning a data object to a field symbol casting a dynamically specified type
-
+ "Assigning a data object to a field symbol casting a dynamically
+ "specified type
ASSIGN dobj TO CASTING TYPE (some_type).
+
+ "Dynamically creating an object as an instance of a class and
+ "assigning the reference to the object to an object reference
+ "variable. oref can be an object or interface reference variable.
+ "The reference variable is created here with the generic 'object'.
+ DATA oref TYPE REF TO object.
+ CREATE OBJECT oref TYPE (some_class).
+
+ "Note: As covered further down and in the executable example,
+ "CREATE DATA/OBJECT and ASSIGN statements have the HANDLE addition
+ "after which dynmically created types can be specified. A type
+ "description object is expected.
+ CREATE DATA dref TYPE HANDLE type_descr_obj.
+ CREATE OBJECT oref TYPE HANDLE type_descr_obj.
+ ASSIGN dobj TO CASTING TYPE HANDLE type_descr_obj.
```
- Dynamically specifying clauses in ABAP SQL statements
``` abap
- "This snippet demonstrates a selection of possible dynamic specifications in ABAP SQL SELECT statements.
+ "This snippet demonstrates a selection of possible dynamic
+ "specifications in ABAP SQL SELECT statements.
"Dynamic SELECT list
DATA(select_list) = `CARRID, CONNID, COUNTRYFR, COUNTRYTO`.
@@ -688,14 +797,16 @@ Note that dynamically specifying syntax elements has downsides, too. Consider so
FROM (db_table)
INTO TABLE @itab->*.
- "Similar to the NEW operator, you can use the addition NEW here to create an anonymous data object
- "in place. The advantage is that the data type is constructed in a suitable way.
+ "Similar to the NEW operator, you can use the addition NEW here
+ "to create an anonymous data object in place. The advantage is
+ "that the data type is constructed in a suitable way.
SELECT *
FROM (db_table)
INTO TABLE NEW @DATA(dref_tab).
"Dynamic WHERE clause
- "This is an example for using an internal table with a character-like row type
+ "This is an example for using an internal table with a
+ "character-like row type
DATA(where_clause) = VALUE string_table( ( `CARRID = 'LH'` )
( `OR CARRID = 'AA'` ) ).
@@ -710,8 +821,10 @@ Note that dynamically specifying syntax elements has downsides, too. Consider so
``` abap
"Notes:
"- Dynamic method calls require a CALL METHOD statement.
- "- The first 3 examples assume that there are no mandatory parameters defined for the method.
- "- The example covers only static methods. Dynamic method calls for instance methods are also possible.
+ "- The first 3 examples assume that there are no mandatory
+ " parameters defined for the method.
+ "- The example covers only static methods. Dynamic method calls
+ " for instance methods are also possible.
"Method dynamically specified
CALL METHOD class=>(meth).
@@ -733,8 +846,8 @@ Note that dynamically specifying syntax elements has downsides, too. Consider so
CALL METHOD class=>(meth) PARAMETER-TABLE ptab.
"Notes on PARAMETER-TABLE ptab
- "- The table (of type abap_parmbind_tab; line type is abap_parmbind) must
- " be filled and have a line for all non-optional parameters.
+ "- The table (of type abap_parmbind_tab; line type is abap_parmbind)
+ " must be filled and have a line for all non-optional parameters.
"- Components: name -> formal parameter name
" kind -> kind of parameter, e. g. importing
" value -> pointer to appropriate actual parameter,
@@ -747,18 +860,12 @@ Note that dynamically specifying syntax elements has downsides, too. Consider so
## Runtime Type Services (RTTS)
[RTTS](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_services_glosry.htm "Glossary Entry")
-represent a hierarchy of [type description
-classes](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abentype_class_glosry.htm "Glossary Entry")
-containing methods for [Runtime Type Creation
-(RTTC)](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_creation_glosry.htm "Glossary Entry")
-and [Runtime Type Identification
-(RTTI)](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_identific_glosry.htm "Glossary Entry").
-Using these classes, you can ...
-
-- get type information on data objects, data types or
+represent a hierarchy of [type description classes](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abentype_class_glosry.htm "Glossary Entry")
+containing methods for
+- getting type information on data objects, data types or
[instances](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abeninstance_glosry.htm "Glossary Entry")
- at runtime.
-- define and create new data types at runtime.
+ at runtime ([Runtime Type Identification (RTTI)](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_identific_glosry.htm "Glossary Entry")).
+- defining and creating new data types as [type description objects](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abentype_object_glosry.htm) at runtime ([Runtime Type Creation (RTTC)](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_creation_glosry.htm "Glossary Entry")).
The hierarchy of type description classes is as follows.
@@ -798,88 +905,368 @@ F2 help information in
[ADT](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenadt_glosry.htm "Glossary Entry"),
for more details.
-The following examples show the retrieval of information. Instead of the
+(back to top)
+
+### Getting Type Information at Runtime
+
+With RTTI, you can determine data types at runtime using description methods in type description classes.
+To get the type information, you can get a reference to a type description object of a type, that is, an instance of a type description class.
+The type properties are represented by attributes that are accessible through the type description object.
+
+
+> **š” Note**
+> - For each type, there is exactly one type description object.
+> - For each type category (elementary type, table, and so on), there is a type description class (e.g. `CL_ABAP_STRUCTDESCR` for structures, as shown in the hierarchy tree above) that has special attributes (i.e. the properties of the respective types).
+> - References to type description objects can be used, for example, after the `TYPE HANDLE` addition of the `CREATE DATA` and `ASSIGN` statements.
+
+The following examples show the retrieval of type information. Instead of the
cumbersome extra declaration of data reference variables, you can use
-[inline
-declarations](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abeninline_declaration_glosry.htm "Glossary Entry").
-[Method
-chaining](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenmethod_chaining_glosry.htm "Glossary Entry")
+[inline declarations](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abeninline_declaration_glosry.htm "Glossary Entry").
+[Method chaining](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenmethod_chaining_glosry.htm "Glossary Entry")
comes in handy, too.
-``` abap
-"The properties of a type are retrieved using RTTI
-"In ADT, you may want to choose CTRL + SPACE after ...=> to explore the options.
-DATA(some_type) = cl_abap_typedescr=>describe_by_data( var ).
+```abap
+"Getting a reference to a type description object of a type.
+"i.e. getting an instance of a type description class.
+"To do so, the static methods of the class CL_ABAP_TYPEDESCR can be used.
+"As shown below, the type decription object can be used to create data
+"objects dynamically. Note that instances of classes are not covered.
-"The components of a structure are retrieved.
-"Like above, the describe_by_data method is used together with a variable.
+"Type for which information should be retrieved
+TYPES elem_type TYPE c LENGTH 5.
-DATA(components) = CAST cl_abap_structdescr(
- cl_abap_typedescr=>describe_by_data( some_struc )
- )->components.
+"Creating a data reference variable to hold the reference to
+"the type description object
+DATA type_descr_obj_elem TYPE REF TO cl_abap_elemdescr.
-"The attributes of a global class are retrieved. In contrast to the
-"example above the describe_by_name method is used together with the actual name.
+"Retrieving type information by creating an instance of a type description
+"class. As the name implies, the describe_by_name method expects the name
+"of the type. In the following example, the reference to the type object is
+"assigned using a downcast to the reference variable of type CL_ABAP_ELEMDESCR
+"created above.
+type_descr_obj_elem = CAST #( cl_abap_typedescr=>describe_by_name( 'ELEM_TYPE' ) ).
-DATA(attributes) = CAST cl_abap_classdescr(
- cl_abap_classdescr=>describe_by_name( 'CL_SOME_CLASS' )
- )->attributes.
+"Using the older cast operator ?=
+type_descr_obj_elem ?= cl_abap_typedescr=>describe_by_name( 'ELEM_TYPE' ).
-"Casting and method chaining as above in contrast to the following extra declarations
-"If the variables were not declared inline as in the example, there would be even more lines of code.
-DATA(a) = cl_abap_typedescr=>describe_by_data( some_struc ).
-DATA(b) = CAST cl_abap_structdescr( a ).
-DATA(c) = b->components.
-```
+"Inline declaration is handy to avoid helper variables.
+DATA(type_descr_obj_inl_1) = CAST cl_abap_elemdescr(
+ cl_abap_typedescr=>describe_by_name( 'ELEM_TYPE' ) ).
-The following example demonstrates the dynamic creation of data objects.
-Note the [`TYPE HANDLE`](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abapcreate_data_handle.htm)
-addition as part of the `CREATE DATA` statement that is used when referring to dynamically created data types.
+"You may want to check the type description object in the debugger.
+"Various methods/attributes provide you with detailed information.
+"The following examples show a selection:
+"Kind/Type kind/Output length
+DATA(kind) = type_descr_obj_inl_1->kind. "E (elementary)
+DATA(type_kind) = type_descr_obj_inl_1->type_kind. "C
+DATA(output_length) = type_descr_obj_inl_1->output_length. "5
-``` abap
-"RTTC examples
+"In the following example, the type properties are retrieved
+"without casting. The data object has the type ref to
+"cl_abap_typedescr. See the hierarchy tree above.
+"The reference in the type description object references an
+"object from one of the classes CL_ABAP_ELEMDESCR, CL_ABAP_ENUMDESCR,
+"CL_ABAP_REFDESCR, CL_ABAP_STRUCTDESCR, CL_ABAP_TABLEDSECR,
+"CL_ABAP_CLASSDESCR, or CL_ABAP_INTFDESCR.
+"In the following case, it is CL_ABAP_ELEMDESCR.
+"Note that in most of the following examples, the explicit
+"casting is included when retrieving a reference to the type
+"description object.
+TYPES another_elem_type TYPE n LENGTH 3.
+DATA(type_descr_obj_inl_2) = cl_abap_typedescr=>describe_by_name( 'ANOTHER_ELEM_TYPE' ).
-"Creation of an anonymous data object using a type description object for a
-"dictionary structure that is obtained using RTTI
-
-"Declaring a data reference variable with a generic type
-DATA dref TYPE REF TO data.
-
-"Getting type description using RTTI
-DATA(type) = CAST cl_abap_datadescr(
+"More types
+"Structured data type (here, using the name of a database table)
+DATA(type_descr_obj_struc) = CAST cl_abap_structdescr(
cl_abap_typedescr=>describe_by_name( 'ZDEMO_ABAP_CARR' ) ).
-"Creating an anonymous data object using the retrieved type description
-CREATE DATA dref TYPE HANDLE type.
+"Various attributes/methods available for detailed information
+"Kind
+DATA(struc_kind) = type_descr_obj_struc->kind. "S
-"Creating an internal table dynamically
+"Getting components of the structure (e.g. the component names
+"and type description objects for the individual components)
+DATA(comps_struc) = type_descr_obj_struc->get_components( ).
-"Getting type description using RTTI
-DATA(line_type) = CAST cl_abap_structdescr(
- cl_abap_tabledescr=>describe_by_name( `ZDEMO_ABAP_CARR` ) ).
+"The follwing attribute also lists the component names and types
+"(but not the type desription objects as is the case above)
+DATA(comps_struc2) = type_descr_obj_struc->components.
-"Defining primary table keys of internal table type to be created
-DATA(itab_keys) = VALUE abap_keydescr_tab( ( name = 'CARRID' )
- ( name = 'CARRNAME' ) ).
+"Kind of structure
+DATA(struct_kind) = type_descr_obj_struc->struct_kind. "F (flat)
-"Creating internal table type using the create method of cl_abap_tabledescr
-DATA(table_type) = cl_abap_tabledescr=>create(
- p_line_type = line_type
- p_table_kind = cl_abap_tabledescr=>tablekind_sorted
- p_unique = cl_abap_typedescr=>true
- p_key = itab_keys ).
+"Internal table type
+TYPES tab_type TYPE SORTED TABLE OF zdemo_abap_carr
+ WITH UNIQUE KEY carrid.
-"Creating internal table based on the created table type
-DATA ref_tab TYPE REF TO data.
+DATA(type_descr_obj_tab) = CAST cl_abap_tabledescr(
+ cl_abap_typedescr=>describe_by_name( 'TAB_TYPE' ) ).
-CREATE DATA ref_tab TYPE HANDLE table_type.
+"Kind
+DATA(tab_kind) = type_descr_obj_tab->kind. "T
+
+"The following method returns more information than the attribute
+"below (e.g. key kind, i.e. if it is a unique key, etc.)
+DATA(tab_keys) = type_descr_obj_tab->get_keys( ).
+DATA(tab_keys2) = type_descr_obj_tab->key.
+
+"Getting internal table components
+"The method get_table_line_type returns a variable of type ref to
+"cl_abap_datadescr. This way you can retrieve the table components.
+"Method chaining is useful here.
+DATA(tab_comps) = CAST cl_abap_structdescr(
+ type_descr_obj_tab->get_table_line_type( ) )->get_components( ).
+
+"Reference type
+TYPES ref_str TYPE REF TO string.
+DATA(type_descr_obj_ref) = CAST cl_abap_refdescr(
+ cl_abap_typedescr=>describe_by_name( 'REF_STR' ) ).
+
+"Returns the type description object of the referenced type
+DATA(ref_type) = type_descr_obj_ref->get_referenced_type( ).
+
+"Getting the absolute type name
+DATA(ref_type_abs_name) =
+ type_descr_obj_ref->get_referenced_type( )->absolute_name. "\TYPE=STRING
+
+"Kind/Type kind
+DATA(ref_kind) = type_descr_obj_ref->kind. "R
+DATA(ref_type_type_kind) =
+ type_descr_obj_ref->get_referenced_type( )->type_kind. "g (string)
+
+"Getting a reference to a type description object of an existing
+"data object. Instead of referring to the name of a type, referring
+"to a data object here. The relevant method is describe_by_data.
+
+"Elementary data object
+DATA dobj_elem type i.
+DATA(ty_des_obj_el) = CAST cl_abap_elemdescr(
+ cl_abap_typedescr=>describe_by_data( dobj_elem ) ).
+
+"Structure
+DATA dobj_struc type zdemo_abap_carr.
+DATA(ty_des_obj_struc) = CAST cl_abap_structdescr(
+ cl_abap_typedescr=>describe_by_data( dobj_struc ) ).
+
+"Internal table
+DATA dobj_itab type table of zdemo_abap_carr with empty key.
+DATA(ty_des_obj_itab) = CAST cl_abap_tabledescr(
+ cl_abap_typedescr=>describe_by_data( dobj_itab ) ).
+
+"Reference variable
+DATA dref_var type ref to string.
+DATA(ty_des_obj_dref) = CAST cl_abap_refdescr(
+ cl_abap_typedescr=>describe_by_data( dref_var ) ).
+```
+
+Excursions:
+
+```abap
+"Casting and method chaining as above in contrast to the following
+"extra declarations. If the variables were not declared inline as
+"in the example, there would be even more lines of code.
+DATA(a) = cl_abap_typedescr=>describe_by_data( some_struc ).
+DATA(b) = CAST cl_abap_structdescr( a ).
+DATA(c) = b->components.
+
+"As mentioned earlier about type name specifications for statements
+"such as CREATE DATA, in addition to character-like data objects for
+"the type name specified in the parentheses, you can also use absolute
+"type names.
+
+"Type to refer to
+TYPES type4abs TYPE p LENGTH 4 DECIMALS 3.
+
+"Data and object reference variables with generic types
+DATA dref4abs TYPE REF TO data.
+DATA oref4abs TYPE REF TO object.
+
+"Getting absolute names
+DATA(abs_name_type) = cl_abap_typedescr=>describe_by_name(
+ 'TYPE4ABS' )->absolute_name.
+DATA(abs_name_cl) = cl_abap_typedescr=>describe_by_name(
+ 'ZCL_DEMO_ABAP_DYNAMIC_PROG' )->absolute_name.
+
+"Data references
+"Named data object holding the absolute name
+CREATE DATA dref4abs TYPE (abs_name_type).
+
+"Unnamed data object
+CREATE DATA dref4abs TYPE ('\TYPE=STRING').
+
+"Object references
+"Named data object
+CREATE OBJECT oref4abs TYPE (abs_name_cl).
+
+"Unnamed data object
+CREATE OBJECT oref4abs TYPE ('\CLASS=ZCL_DEMO_ABAP_DYNAMIC_PROG').
+```
+
+(back to top)
+
+### Dynamically Creating Data Types at Runtime
+You can create data types at program runtime using methods of the type description classes of RTTS.
+These types are only valid locally in the program. They are also anonymous, i.e. they are only accessible through type description objects.
+As shown above, you can get a reference to a type description object of a type using the static methods of the class `CL_ABAP_TYPEDESCR`.
+```abap
+"For example, a structured type
+DATA(type_descr_obj) = CAST cl_abap_structdescr(
+ cl_abap_typedescr=>describe_by_name( 'SOME_STRUC_TYPE' ) ).
+```
+
+The focus here is on using RTTC methods such as `get...`.
+
+```abap
+"Creating type description objects using ...
+"... elementary data types
+"Conceptually, all elementary, built-in ABAP types already
+"exist and can be accessed by the corresponding get_* methods.
+"In ADT, click CTRL + space after cl_abap_elemdescr=>...
+"to check out the options. The following examples show a
+"selection.
+
+DATA(tdo_elem_i) = cl_abap_elemdescr=>get_i( ).
+DATA(tdo_elem_string) = cl_abap_elemdescr=>get_string( ).
+
+"For the length specification of type c and others, there is
+"an importing parameter available.
+DATA(tdo_elem_c_l20) = cl_abap_elemdescr=>get_c( 10 ).
+
+"Type p with two parameters to be specified.
+DATA(tdo_elem_p) = cl_abap_elemdescr=>get_p( p_length = 3
+ p_decimals = 2 ).
+
+"Note: Instead of calling get_i() and others having no importing
+"parameters, you could also call the describe_by_name( ) method
+"and pass the type names (Iā STRING etc.) as arguments.
+"DATA(tdo_elem_i_2) = CAST cl_abap_elemdescr(
+" cl_abap_typedescr=>describe_by_name( 'I' ) ).
+"DATA(tdo_elem_string_2) = CAST cl_abap_elemdescr(
+" cl_abap_typedescr=>describe_by_name( 'STRING' ) ).
+
+"... structured data types
+"They are created based on a component description table.
+
+"A structured type such as the following shall be created dynamically
+"using a type description object.
+TYPES: BEGIN OF struc_type,
+ a TYPE string,
+ b TYPE i,
+ c TYPE c LENGTH 5,
+ d TYPE p LENGTH 4 DECIMALS 3,
+ END OF struc_type.
+
+"Creating a type description object using RTTC method
+"Using the get method, you can create the type description object
+"dynamically based on a component table. The component table is
+"of type abap_component_tab. In this example, the component table
+"is created inline.
+DATA(tdo_struc) = cl_abap_structdescr=>get(
+ VALUE #(
+ ( name = 'A' type = cl_abap_elemdescr=>get_string( ) )
+ ( name = 'B' type = cl_abap_elemdescr=>get_i( ) )
+ ( name = 'C' type = cl_abap_elemdescr=>get_c( 5 ) )
+ ( name = 'D' type = cl_abap_elemdescr=>get_p( p_length = 4
+ p_decimals = 3 ) ) ) ).
+
+"... internal table types
+"Note: Specifying the line type is mandatory, the rest is optional.
+
+"An internal table type such as the following shall be created dynamically
+"using a type description object.
+TYPES std_tab_type_std_key TYPE STANDARD TABLE OF string
+ WITH DEFAULT KEY.
+
+"Creating a type description object using RTTC method
+"Not specifying the other optional parameters means that the
+"default values are used, for example, standard table is the
+"default value for p_table_kind.
+DATA(tdo_tab_1) = cl_abap_tabledescr=>get(
+ p_line_type = cl_abap_elemdescr=>get_string( ) ).
+
+"Another internal table type for which more parameter specifications
+"are needed. The following internal table type shall be created using
+"a type description object.
+TYPES so_table_type TYPE SORTED TABLE OF zdemo_abap_flsch
+ WITH UNIQUE KEY carrid connid.
+
+"Creating a type description object using RTTC method
+"The following example also demonstrates how comfortably constructor
+"operators can be used at these positions.
+DATA(tdo_tab_2) = cl_abap_tabledescr=>get(
+ p_line_type = CAST cl_abap_structdescr(
+ cl_abap_tabledescr=>describe_by_name( 'ZDEMO_ABAP_FLSCH' ) )
+ p_table_kind = cl_abap_tabledescr=>tablekind_sorted
+ p_key = VALUE #( ( name = 'CARRID' ) ( name = 'CONNID' ) )
+ p_unique = cl_abap_typedescr=>true ).
+
+" ... reference types
+"Reference types such as the following shall be created using a
+"type description object.
+TYPES some_ref_type2t TYPE REF TO t.
+TYPES some_ref_type2cl TYPE REF TO zcl_demo_abap_dynamic_prog.
+
+"Using RTTC methods
+"You can create a reference type from a base type. This base type
+"may be class, interface or data type.
+DATA(tdo_ref_1) = cl_abap_refdescr=>get( cl_abap_elemdescr=>get_t( ) ).
+DATA(tdo_ref_2) = cl_abap_refdescr=>get(
+ cl_abap_typedescr=>describe_by_name( 'ZCL_DEMO_ABAP_DYNAMIC_PROG' ) ).
+"Alternative: get_by_name method
+DATA(tdo_ref_3) = cl_abap_refdescr=>get_by_name( 'T' ).
+DATA(tdo_ref_4) = cl_abap_refdescr=>get_by_name( 'ZCL_DEMO_ABAP_DYNAMIC_PROG' ).
+```
+
+(back to top)
+
+### Dynamically Creating Data Objects at Runtime
+
+As shown above, anonymous data objects can be dynamically created using `CREATE DATA` statements in many ways by specifying the type ...
+- statically: `CREATE DATA dref TYPE string.`
+- dynamically: `CREATE DATA dref TYPE (some_type).`
+
+Another way to dynamically create data objects with dynamic type specification is to use types created at runtime with RTTC methods.
+The `CREATE DATA` statement provides the [`TYPE HANDLE`](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abapcreate_data_handle.htm) addition after which you can specify type description objects.
+
+``` abap
+DATA dref_cr TYPE REF TO data.
+
+"Elementary data object
+"Type description object for an elementary type
+DATA(tdo_elem_c_l20) = cl_abap_elemdescr=>get_c( 10 ).
+"Creating an elementary data object based on a type description object
+CREATE DATA dref_cr TYPE HANDLE tdo_elem_c_l20.
+
+"Structure
+DATA(tdo_struc) = cl_abap_structdescr=>get(
+ VALUE #(
+ ( name = 'COMP1' type = cl_abap_elemdescr=>get_string( ) )
+ ( name = 'COMP2' type = cl_abap_elemdescr=>get_i( ) )
+ ( name = 'COMP3' type = cl_abap_elemdescr=>get_c( 3 ) ) ) ).
+
+"Creating a structure based on a type description object
+CREATE DATA dref_cr TYPE HANDLE tdo_struc.
+
+"Internal table
+"In the case below, it is a standard table with standard key by
+"default because the other parameters are not specified.
+DATA(tdo_tab) = cl_abap_tabledescr=>get(
+ p_line_type = CAST cl_abap_structdescr(
+ cl_abap_tabledescr=>describe_by_name( 'ZDEMO_ABAP_CARR' ) ) ).
+
+"Creating an internal table based on a type description object
+CREATE DATA dref_cr TYPE HANDLE tdo_tab.
+
+"Data reference
+DATA(tdo_ref) = cl_abap_refdescr=>get( cl_abap_elemdescr=>get_t( ) ).
+CREATE DATA dref_cr TYPE HANDLE tdo_ref.
```
(back to top)
## More Information
- It is recommended that you also consult section [Dynamic Programming Techniques (F1 docu for standard ABAP)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abendynamic_prog_technique_gdl.htm) in the ABAP Keyword Documentation since it provides important aspects that should be considered when dealing with dynamic programming in general (e. g. security aspects or runtime error prevention).
-- There are even further dynamic programming techniques in the unrestricted language scope like the
+- There are even further dynamic programming techniques in the unrestricted language scope such as the
generation or execution of programs at runtime. They are not part of this cheat sheet. Find more details on the related syntax (e. g. `GENERATE SUBROUTINE POOL`, `READ REPORT` and `INSERT REPORT` in the ABAP Keyword Documentation for Standard ABAP: [Dynamic Program Development (F1 docu for standard ABAP)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenabap_language_dynamic.htm)
## Executable Example
diff --git a/16_Data_Types_and_Objects.md b/16_Data_Types_and_Objects.md
index 9009887..cca38bc 100644
--- a/16_Data_Types_and_Objects.md
+++ b/16_Data_Types_and_Objects.md
@@ -53,7 +53,7 @@ Data objects:
## ABAP Data Types
-ABAP is rich in built-in data types and offers a wide range of options for defining data types and data objects in in different contexts.
+ABAP is rich in built-in data types and offers a wide range of options for defining data types and data objects in different contexts.
Data types can be divided into three groups:
- [Elementary data types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenelementary_data_type_glosry.htm)
- [Complex data types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abencomplex_data_type_glosry.htm)
@@ -63,7 +63,7 @@ For an overview, see the [ABAP Type Hierarchy](https://help.sap.com/doc/abapdocu
### Elementary Data Types
- Elementary (or scalar) data types are based directly on a set of [built-in ABAP types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenbuiltin_abap_type_glosry.htm).
-- Are not composed of of other data types.
+- Are not composed of other data types.
- Are types for holding numeric values, text information, binary data and special types for date and time.
- Are further divided into elementary types of fixed and variable length.
- Note: The length and the memory requirements of data objects of fixed length data types are fixed, that is, they cannot change at runtime. The length and memory requirements of data objects of variable length data types can actually change at runtime, depending on their contents.
diff --git a/src/zcl_demo_abap_display.clas.abap b/src/zcl_demo_abap_display.clas.abap
index 9bc9d40..768a4ed 100644
--- a/src/zcl_demo_abap_display.clas.abap
+++ b/src/zcl_demo_abap_display.clas.abap
@@ -4,18 +4,21 @@
* output in the ADT console
*
* -------------------------- NOTE -------------------------------------
-* This class is used to display deep types contained in the cheat sheet
-* example classes in older ABAP releases.
+* This helper class is only used to display complex types contained in
+* the example classes of the ABAP cheat sheets in older ABAP releases.
+* In newer ABAP releases, this helper class is, in principle, not needed.
+* You can use the write method of the classrun interface directly and
+* display all types.
*
* The code presented in this class is intended only to support the ABAP
* cheat sheets. It is not intended for direct use in a production system
-* environment. The code examples in the ABAP cheat sheets are primarily
-* intended to provide a better explanation and visualization of the
-* syntax and semantics of ABAP statements, not to solve concrete
-* programming tasks. For production application programs, you should
-* always work out your own solution for each individual case. There is
-* no guarantee for the correctness or completeness of the code.
-* Furthermore, there is no legal responsibility or liability for any
+* environment. The code examples in the ABAP cheat sheets are primarily
+* intended to provide a better explanation and visualization of the
+* syntax and semantics of ABAP statements, not to solve concrete
+* programming tasks. For production application programs, you should
+* always work out your own solution for each individual case. There is
+* no guarantee for the correctness or completeness of the code.
+* Furthermore, there is no legal responsibility or liability for any
* errors or their consequences that may occur when using the the example
* code.
*
@@ -59,99 +62,61 @@ CLASS ZCL_DEMO_ABAP_DISPLAY IMPLEMENTATION.
ENDMETHOD.
METHOD display.
-
"Checking data type
DATA(type_descr) = cl_abap_typedescr=>describe_by_data( input ).
-
CASE type_descr->kind.
-
WHEN cl_abap_typedescr=>kind_struct.
-
DATA(struct_descr) = CAST cl_abap_structdescr( type_descr ).
-
"Checking for complex output
IF struct_descr->struct_kind = cl_abap_structdescr=>structkind_nested
OR line_exists( struct_descr->components[ type_kind = cl_abap_typedescr=>typekind_table ] )
OR line_exists( struct_descr->components[ type_kind = cl_abap_typedescr=>typekind_dref ] )
OR line_exists( struct_descr->components[ type_kind = cl_abap_typedescr=>typekind_oref ] ).
-
DATA(to_be_serialized) = abap_true.
-
ELSE.
-
DATA(display) = mo_out->get( data = input name = name ).
-
ENDIF.
-
WHEN cl_abap_typedescr=>kind_table.
-
DATA(table_descr) = CAST cl_abap_tabledescr( type_descr ).
-
TRY.
DATA(line_type_struct_descr) = CAST cl_abap_structdescr( table_descr->get_table_line_type( ) ).
-
"Checking for complex output
IF line_type_struct_descr->struct_kind = cl_abap_structdescr=>structkind_nested
OR line_exists( line_type_struct_descr->components[ type_kind = cl_abap_typedescr=>typekind_table ] )
OR line_exists( line_type_struct_descr->components[ type_kind = cl_abap_typedescr=>typekind_dref ] )
OR line_exists( line_type_struct_descr->components[ type_kind = cl_abap_typedescr=>typekind_oref ] ).
-
to_be_serialized = abap_true.
-
ELSE.
-
display = mo_out->get( data = input name = name ).
-
ENDIF.
-
CATCH cx_sy_move_cast_error.
-
to_be_serialized = abap_true.
-
ENDTRY.
-
WHEN cl_abap_typedescr=>kind_class.
-
to_be_serialized = abap_true.
-
WHEN cl_abap_typedescr=>kind_intf.
-
to_be_serialized = abap_true.
-
WHEN cl_abap_typedescr=>kind_elem.
-
display = mo_out->get( data = COND string( WHEN name IS INITIAL THEN input ELSE `"` && name && `":` && cl_abap_char_utilities=>newline && input ) ).
-
WHEN cl_abap_typedescr=>kind_ref.
-
"Checking for data references
IF type_descr->type_kind = cl_abap_typedescr=>typekind_dref.
-
"Checking type of dereferenced data object
DATA(type_check_dref) = cl_abap_typedescr=>describe_by_data( input->* ).
-
"Processing (non-)elementary types
IF type_check_dref->kind = type_descr->kind_elem.
-
display = mo_out->get( data = COND string( WHEN name IS INITIAL THEN input->* ELSE `"` && name && `":` && cl_abap_char_utilities=>newline && input->* ) ).
-
ELSE.
-
to_be_serialized = abap_true.
-
ENDIF.
-
ELSE.
to_be_serialized = abap_true.
ENDIF.
-
ENDCASE.
"Processing complex output by serializiation
FIND SUBSTRING `Data type not yet supported ...` IN display MATCH OFFSET DATA(off) MATCH LENGTH DATA(len).
-
IF sy-subrc = 0 OR to_be_serialized = abap_true.
-
"ABAP JSON serializing
DATA(json) = /ui2/cl_json=>serialize( data = input
pretty_name = /ui2/cl_json=>pretty_mode-low_case
@@ -160,16 +125,12 @@ CLASS ZCL_DEMO_ABAP_DISPLAY IMPLEMENTATION.
format_output = abap_true
assoc_arrays = abap_true
assoc_arrays_opt = abap_true ).
-
IF to_be_serialized = abap_true.
-
IF name IS INITIAL.
REPLACE PCRE `^` IN display WITH json && cl_abap_char_utilities=>newline.
ELSE.
REPLACE PCRE `^` IN display WITH `"` && name && `":` && cl_abap_char_utilities=>newline && json && cl_abap_char_utilities=>newline.
-
ENDIF.
-
"substring found
ELSE.
IF name IS INITIAL.
@@ -177,26 +138,18 @@ CLASS ZCL_DEMO_ABAP_DISPLAY IMPLEMENTATION.
ELSE.
REPLACE SECTION OFFSET off LENGTH len OF display WITH `"` && name && `":` && cl_abap_char_utilities=>newline && json && cl_abap_char_utilities=>newline.
ENDIF.
-
ENDIF.
-
mo_out->write( display ).
-
ELSE.
-
mo_out->write( display ).
-
ENDIF.
-
ENDMETHOD.
METHOD next_section.
-
mo_out->write( `_________________________________________________________________________________`
&& cl_abap_char_utilities=>newline
&& cl_abap_char_utilities=>newline
&& heading
&& cl_abap_char_utilities=>newline ).
-
ENDMETHOD.
-ENDCLASS.
+ENDCLASS.
\ No newline at end of file
diff --git a/src/zcl_demo_abap_dynamic_prog.clas.abap b/src/zcl_demo_abap_dynamic_prog.clas.abap
index c6bdee2..267b3ee 100644
--- a/src/zcl_demo_abap_dynamic_prog.clas.abap
+++ b/src/zcl_demo_abap_dynamic_prog.clas.abap
@@ -1,6 +1,6 @@
***********************************************************************
*
-* ABAP cheat sheet: Dynamic programming
+* ABAP cheat sheet: Dynamic programming
*
* -------------------------- PURPOSE ----------------------------------
* - Example to demonstrate various syntax options and concepts related
@@ -31,9 +31,9 @@
* or use the debugger.
*
* ----------------------------- NOTE -----------------------------------
-* Some code sections are commented out. The syntax is only available in
+* Some code sections are commented out. The syntax is only available in
* newer ABAP releases. Comment them in if you are running a newer
-* ABAP release, for example, in the SAP BTP environment.
+* ABAP release, for example, in the SAP BTP environment.
*
* The code presented in this class is intended only to support the ABAP
* cheat sheets. It is not intended for direct use in a production system
@@ -98,7 +98,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
"- Type: either a complete data type or a generic type.
"Complete types
- "Here, a chained statement using a colon.
+ "Here, a chained statement with a colon is used.
FIELD-SYMBOLS: TYPE i,
TYPE zdemo_abap_flsch,
TYPE LINE OF tab_type,
@@ -107,12 +107,10 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
"Generic types
"There are plenty of options for generic ABAP types. Check the
"keyword docu.
- "The most prominent is 'data' that stands for any data type (the
- "older generic type 'any' has the same effect).
- FIELD-SYMBOLS TYPE csequence.
- FIELD-SYMBOLS TYPE data.
- FIELD-SYMBOLS TYPE any.
- FIELD-SYMBOLS TYPE ANY TABLE.
+ FIELD-SYMBOLS TYPE c. "Text field with a generic length
+ FIELD-SYMBOLS TYPE csequence. "Text-like (c, string)
+ FIELD-SYMBOLS TYPE data. "Any data type
+ FIELD-SYMBOLS TYPE ANY TABLE. "Internal table with any table type
"Declaring field symbols inline
"Prominent use case: Inline declaration of a field symbol for an internal table
@@ -157,7 +155,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
tab_a TO ,
tab_a TO .
- "Inline declaration is possible, too. The type is automatically derived.
+ "Inline declaration is possible, too. The type is derived automatically.
ASSIGN num_a TO FIELD-SYMBOL().
output->display( `No output for this section. See the code.` ).
@@ -226,32 +224,63 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
output->next_section( `5) Type Casting with Field Symbols` ).
- "Use the CASTING addition for matching types of data object and field symbol
- "when assigning memory areas. You can cast either implicitly or explicitly
- "by specifying the concrete type.
- "In the example, a data type and object are created. The data object is
- "assigned to a field symbol. In case of implicit casting, the field symbol
- "is typed with the created data type, so only CASTING is needed. In case
- "of explicit casting, the field symbol is typed with a generic type.
- "Here, just having CASTING would not be sufficient.
- "As a result, the type that only accepts 3 characters is respected.
+ "The example demonstrates the CASTING addition. Various additions after
+ "CASTING are possible.
- TYPES c_len_3 TYPE c LENGTH 3.
+ TYPES type_d_l9 TYPE c LENGTH 9.
- DATA(chars) = 'abcdefg'.
+ DATA: dobj_d_l5 TYPE c LENGTH 5,
+ dobj_d_l10 TYPE c LENGTH 10 VALUE '1234567890',
+ type_name_d TYPE string VALUE 'TYPE_D_L9'.
- FIELD-SYMBOLS TYPE c_len_3.
+ FIELD-SYMBOLS: TYPE data,
+ TYPE type_d_l9.
- "Implicit casting
- ASSIGN chars TO CASTING.
+ "Casting to a statically, completely specified type
+ "CASTING addition without any more additions: Field symbol inherits
+ "the data type of the data object. The field symbol must be either
+ "completely typed or with one of the generic built-in ABAP types
+ "c, n, p, or x. The other field symbol declared in the example
+ "cannot be used.
+ ASSIGN dobj_d_l10 TO CASTING.
- FIELD-SYMBOLS TYPE data.
+ output->display( input = name = `` ).
- "Explicit casting
- ASSIGN chars TO CASTING TYPE c_len_3.
+ ASSIGN dobj_d_l10 TO CASTING TYPE type_d_l9.
+
+ output->display( input = name = `` ).
+
+ "Casting to a generic type
+ ASSIGN dobj_d_l10 TO CASTING TYPE c.
+
+ output->display( input = name = `` ).
+
+ "Casting to a static field type
+ ASSIGN dobj_d_l10 TO CASTING LIKE dobj_d_l5.
+
+ output->display( input = name = `` ).
+
+ "Casting to a dynamic field type
+ ASSIGN dobj_d_l10 TO CASTING LIKE .
+
+ output->display( input = name = `` ).
+
+ "Anticipating dynamic specification of data types
+ "for the CASTING addition.
+ "The type name is specified as a character-like data
+ "object within parentheses.
+ ASSIGN dobj_d_l10 TO CASTING TYPE (type_name_d).
+
+ output->display( input = name = `` ).
+
+ "Anticipating RTTS
+ "A type description object is created which can be
+ "specified after the TYPE HANDLE additions.
+ DATA(sometype) = CAST cl_abap_datadescr(
+ cl_abap_typedescr=>describe_by_name( 'TYPE_D_L9' ) ).
+ ASSIGN dobj_d_l10 TO CASTING TYPE HANDLE sometype.
output->display( input = name = `` ).
- output->display( input = name = `` ).
**********************************************************************
@@ -391,7 +420,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
output->display( input = tab_f1 name = `tab_f1` ).
- "Regarding the field symbol, the data type is derived automatically.
+ "The following example shows a field symbol declared inline.
LOOP AT ASSIGNING FIELD-SYMBOL().
-connid = '100'.
-fldate = cl_abap_context_info=>get_system_date( ) + 1.
@@ -502,54 +531,96 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
DATA(ref_b2) = REF #( number_b ).
"You can explicitly specify the data type after REF.
- DATA(ref_b3) = REF string( `hallo` ).
+ "DATA(ref_b3) = REF #( g ).
output->display( `No output for this section. See the code.` ).
**********************************************************************
- output->next_section( `11) Creating New Data Objects at Runtime` ).
+ output->next_section( `11) Dynamically Creating Data Objects at Runtime Using Static Type Definitions` ).
- "You create a so-called anonymous data object at runtime by putting the
- "reference into the variable and providing the desired type. Use the
- "instance operator NEW. The older syntax CREATE DATA has the same effect
- "as using the newer instance operator.
- "The example includes various anonymous data objects. Note: To output
- "the content of the data reference variables, they must be dereferenced
- "first. The details are shown further down.
+ "The example code shows the creation of anonymous data objects. They
+ "can be created using the statement CREATE DATA, the instance operator
+ "NEW, or the addition NEW of the INTO clause in a SELECT statement.
+ "A data reference variable is expected when anonymous objects are
+ "declared. They cannot be addressed by a name (hence anonymous).
+ "Note:
+ "- The examples cover static type definitions. As shown further down,
+ " there are options to dynamically specify the type definitions.
+ "- To output the content of the data reference variables, they
+ " must be dereferenced first. The details are shown further down.
- "Declaring data reference variables
- DATA ref_c1 TYPE REF TO i. "Complete type
- DATA ref_data_c TYPE REF TO data. "Generic type
+ "CREATE DATA statements
+ "Note that there are many additions available. The examples show a selection.
+ "Behind TYPE and LIKE, the syntax offers the same possibilities as the DATA statement.
- "Creating anonymous data objects
- "Using the '#' sign and the explicit type: see REF #( ) above.
- ref_c1 = NEW #( ).
- ref_data_c = NEW string( ).
+ "Creating an anonymous data object with an implicit type.
+ "If neither of the additions TYPE or LIKE are specified, the data reference variable
+ "must be completely typed.
+ DATA dref_c1 TYPE REF TO string.
+ CREATE DATA dref_c1.
- "For directly assigning values, insert the values within the parentheses.
- ref_c1 = NEW #( 123 ).
+ "Creating anonymous data objects with explicit data type specification.
+ "Data reference variable with a generic type to be used in the following examples
+ "for the anonymous data object.
+ DATA dref_c2 TYPE REF TO data.
- "Using inline declarations to omit a prior declaration of a variable.
- DATA(ref_c2) = NEW i( 456 ).
+ "Elementary, built-in ABAP type
+ CREATE DATA dref_c2 TYPE p LENGTH 8 DECIMALS 3.
- "Internal table type
- TYPES i_table TYPE STANDARD TABLE OF i WITH EMPTY KEY.
+ "Anomyous internal table ...
+ "using the LIKE addition to refer to an existing internal table
+ DATA itab_c TYPE TABLE OF zdemo_abap_carr.
+ CREATE DATA dref_c2 LIKE itab_c.
- "Filling internal table
- DATA(ref_c3) = NEW i_table( ( 1 ) ( 2 ) ( 3 ) ( 4 ) ( 5 ) ).
+ "by specifying the entire table type
+ CREATE DATA dref_c2 TYPE HASHED TABLE OF zdemo_abap_carr WITH UNIQUE KEY carrid.
- "Older syntax
- DATA ref_c4 TYPE REF TO string.
- DATA ref_c5 TYPE REF TO data.
+ "Anonymous structures
+ CREATE DATA dref_c2 LIKE LINE OF itab_c.
+ CREATE DATA dref_c2 TYPE zdemo_abap_carr.
- CREATE DATA ref_c4.
- CREATE DATA ref_c5 TYPE p LENGTH 6 DECIMALS 2.
- CREATE DATA ref_c5 LIKE ref_c4.
+ "Creating reference variable
+ TYPES elem_type_c TYPE c LENGTH 3.
+ CREATE DATA dref_c2 TYPE REF TO elem_type_c.
- output->display( input = ref_c1->* name = `ref_c1->*` ).
- output->display( input = ref_c2->* name = `ref_c2->*` ).
- output->display( input = ref_c3->* name = `ref_c3->*` ).
+ "NEW operator
+ "- Works like CREATE DATA dref TYPE type statements and can be used in general
+ " expression positions.
+ "- Allows to assign values to the new anonymous data objects in parentheses
+
+ "Creating data reference variables
+ DATA: dref_c3 TYPE REF TO i,
+ dref_c4 TYPE REF TO data.
+
+ "# character after NEW if the data type can be identified completely
+ "instead of the explicit type specification (only non-generic types)
+ dref_c3 = NEW #( 123 ).
+ dref_c3 = NEW i( 456 ).
+ dref_c4 = NEW zdemo_abap_carr( ). "not assigning any values
+ dref_c4 = NEW string( `hi` ).
+
+ "Creating anonymous data objects inline
+ "In doing so, you can omit a prior declaration of a variable.
+ DATA(dref_c5) = NEW i( 789 ).
+ DATA(dref_c6) = NEW zdemo_abap_carr( carrid = 'AB' carrname = 'AB Airlines' ).
+
+ "ABAP SQL SELECT statements
+ "Using the NEW addition in the INTO clause, an anonymous data object with
+ "suitable type can be created in place.
+ SELECT *
+ FROM zdemo_abap_carr
+ INTO TABLE NEW @DATA(dref_c7) "Internal table
+ UP TO 3 ROWS.
+
+ SELECT SINGLE *
+ FROM zdemo_abap_carr
+ WHERE carrid = 'LH'
+ INTO NEW @DATA(dref_c8). "Structure
+
+ output->display( input = dref_c6->* name = `dref_c6->*` ).
+ output->display( input = dref_c7->* name = `dref_c7->*` ).
+ output->display( input = dref_c8->* name = `dref_c8->*` ).
**********************************************************************
@@ -664,7 +735,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
output->display( input = ref_e2->carrid name = `ref_e2->carrid` ).
- "This syntax also works but it's less comfortable.
+ "The following syntax also works (dereferencing operator and the component selector).
ref_e2->*-carrname = 'United Airlines'.
output->display( input = ref_e2->*-carrname name = `ref_e2->*-carrname` ).
@@ -678,7 +749,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
"a logical expression with IS [NOT] BOUND.
"The example shows both a data reference that is bound and not bound.
- DATA(ref_f1) = NEW string( `hallo` ).
+ DATA(ref_f1) = NEW string( `hello` ).
DATA ref_f2 TYPE REF TO i.
IF ref_f1 IS BOUND.
@@ -700,7 +771,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
"Note that the garbage collector takes care of removing the references
"automatically once the data is not used any more by a reference.
- DATA(ref_g1) = NEW string( `hallo` ).
+ DATA(ref_g1) = NEW string( `hello` ).
IF ref_g1 IS INITIAL.
output->display( `Before CLEAR: ref_g1 is initial.` ).
@@ -808,7 +879,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
**********************************************************************
- output->next_section( `19) Data References as Part of ` &&
+ output->next_section( `19) Data References as Part of ` &&
`Structures and Internal Tables` ).
"In contrast to field symbols, data reference variables can be used as
@@ -850,7 +921,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
**********************************************************************
output->next_section( `Dynamic ABAP Statements` ).
- output->display( `20a) Dynamic Specifications in ASSIGN Statements (1) - Attributes of Classes/Interfaces` ).
+ output->display( `20) Dynamic Specifications in ASSIGN Statements (1) - Attributes of Classes/Interfaces` ).
"The following examples demonstrate a selection of various dynamic specifications
"that are possible with ASSIGN statements.
@@ -888,9 +959,9 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
output->display( input = name = `` ).
**********************************************************************
-"Note: Comment in the following example in newer ABAP releases and in the SAP BTP environment.
+ "Note: Comment in the following example in newer ABAP releases and in the SAP BTP environment.
-* output->next_section( `20b) Dynamic Specifications in ASSIGN Statements (2) - Setting sy-subrc/ELSE UNASSIGN` ).
+* output->next_section( `21) Dynamic Specifications in ASSIGN Statements (2) - Setting sy-subrc/ELSE UNASSIGN` ).
*
* "In dynamic assignments, the statement ASSIGN sets the return code sy-subrc.
* "If ELSE UNASSIGN is specified, no memory area is assigned to the field symbol. It has the state unassigned after the ASSIGN statement.
@@ -917,11 +988,11 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
* ENDLOOP.
**********************************************************************
-"Note: The following code contains syntax that is only available in
-"newer ABAP releases and in the SAP BTP environment. In these contexts,
-"you can comment in the code.
+ "Note: The following code contains syntax that is only available in
+ "newer ABAP releases and in the SAP BTP environment. In these contexts,
+ "you can comment in the code.
- output->next_section( `20c) Dynamic Specifications in ASSIGN Statements (3) - Structure Components` ).
+ output->next_section( `22) Dynamic Specifications in ASSIGN Statements (3) - Structure Components` ).
"Dynamic specification of structure components that are assigned to a field symbol.
@@ -973,10 +1044,242 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
output->display( input = name = `` ).
output->display( input = name = `` ).
+**********************************************************************
+
+ output->next_section( `23) Dynamic Specifications in ASSIGN Statements (4) - Type Casting` ).
+
+ "As covered above, the CASTING addition of the ASSIGN statement
+ "has dynamic syntax elements.
+ DATA dobj_c_l5 TYPE c LENGTH 5 VALUE 'abcde'.
+ TYPES dtype_c_l2 TYPE c LENGTH 2.
+ FIELD-SYMBOLS TYPE data.
+
+ "A text literal with the name of a type is specified within the parentheses.
+ ASSIGN dobj_c_l5 TO CASTING TYPE ('DTYPE_C_L2').
+
+ output->display( input = name = `` ).
+
+**********************************************************************
+
+ output->next_section( `Dynamically Creating Data Objects at Runtime Using Dynamic Type Definitions` ).
+ output->display( `24) Miscellaneous Data Objects (1)` ).
+
+ "In an example above, anonymous data objects are created using static
+ "type definitions. In this example, anonymous data objects are created
+ "using a type determined at runtime.
+ "The values of an internal table of type string represent type names.
+ "The type name is used for the dynamic type specification in CREATE
+ "DATA statements that use various additions. The following is
+ "created dynamically: elementary data object, structure, internal
+ "table, data reference. For output purposes, the newly created data
+ "objects are assigned values.
+ "Note:
+ "- The NEW operator cannot be used here.
+ "- The creation of a data object based on a type description object is shown
+ " below (TYPE HANDLE addition).
+ "- Dynamic type specifications for ASSIGN statements together with the
+ " CASTING addition are shown above.
+
+ DATA(type_names) = VALUE string_table( ( `I` )
+ ( `STRING` )
+ ( `ZDEMO_ABAP_CARR` ) ).
+
+ DATA dataref TYPE REF TO data.
+ DATA some_str TYPE string VALUE `some string`.
+ DATA some_structure TYPE zdemo_abap_carr.
+
+ LOOP AT type_names REFERENCE INTO DATA(refwa).
+ output->display( |***** Loop iteration { sy-tabix }. Type: { refwa->* } *****| ).
+
+ CASE refwa->*.
+ WHEN `I`.
+ CREATE DATA dataref TYPE (refwa->*).
+ dataref->* = 123.
+
+ output->display( input = dataref->* name = `dataref->*` ).
+
+ CREATE DATA dataref TYPE TABLE OF (refwa->*).
+
+ INSERT 1 INTO TABLE dataref->*.
+ INSERT 2 INTO TABLE dataref->*.
+
+ output->display( input = dataref->* name = `dataref->*` ).
+
+ CREATE DATA dataref TYPE REF TO (refwa->*).
+ dataref->* = REF i( 456 ).
+
+ output->display( input = dataref->* name = `dataref->*` ).
+ WHEN `STRING`.
+ CREATE DATA dataref TYPE (refwa->*).
+ dataref->* = `hello`.
+
+ output->display( input = dataref->* name = `dataref->*` ).
+
+ CREATE DATA dataref TYPE TABLE OF (refwa->*).
+ INSERT `hello` INTO TABLE dataref->*.
+ INSERT `abap` INTO TABLE dataref->*.
+
+ output->display( input = dataref->* name = `dataref->*` ).
+
+ CREATE DATA dataref TYPE REF TO (refwa->*).
+ dataref->* = REF string( `hi` ).
+
+ output->display( input = dataref->* name = `dataref->*` ).
+ WHEN `ZDEMO_ABAP_CARR`.
+ CREATE DATA dataref TYPE (refwa->*).
+ SELECT SINGLE * FROM zdemo_abap_carr INTO @dataref->*.
+
+ output->display( input = dataref->* name = `dataref->*` ).
+
+ CREATE DATA dataref TYPE TABLE OF (refwa->*).
+ SELECT * FROM zdemo_abap_carr INTO TABLE @dataref->* UP TO 3 ROWS.
+
+ output->display( input = dataref->* name = `dataref->*` ).
+
+ CREATE DATA dataref TYPE REF TO (refwa->*).
+ SELECT SINGLE * FROM zdemo_abap_carr INTO NEW @dataref->*.
+
+ output->display( input = dataref->* name = `dataref->*` ).
+ ENDCASE.
+ ENDLOOP.
+
+**********************************************************************
+
+ output->next_section( `25) Elementary Data Object (2)` ).
+
+ "The example demonstrates the following:
+ "- The method call takes care of providing the name of a built-in data type and more
+ "- An elementary data object is created based on the data type
+ "- For demonstration purposes, RTTI (as shown further down in more detail) is used
+ " to check on the created data object by retrieving the type description.
+
+ DATA(b_type) = lcl_det_at_runtime=>get_builtin_type( ).
+
+ DATA ref_bt TYPE REF TO data.
+
+ TRY.
+ CASE b_type-builtin_type.
+ WHEN 'd' OR 'decfloat16' OR 'decfloat34' OR 'f' OR 'i'
+ OR 'string' OR 't' OR 'xstring'.
+
+ CREATE DATA ref_bt TYPE (b_type-builtin_type).
+ WHEN 'c' OR 'n' OR 'x'.
+ CREATE DATA ref_bt TYPE (b_type-builtin_type) LENGTH b_type-len.
+ WHEN 'p'.
+ CREATE DATA ref_bt TYPE p LENGTH b_type-len DECIMALS b_type-dec.
+ WHEN OTHERS.
+ output->display( `That didn't work.` ).
+ ENDCASE.
+
+ "Getting type information using RTTI
+ DATA(descr_builtin_type) = CAST cl_abap_elemdescr(
+ cl_abap_typedescr=>describe_by_data( ref_bt->* ) ).
+
+ output->display( |Built-in type determined at runtime: { b_type-builtin_type } | ).
+ output->display( `Created data object at runtime:` ).
+ output->display( input = descr_builtin_type name = `descr_builtin_type` ).
+
+ CATCH cx_root.
+ output->display( `Something went wrong.` ).
+ ENDTRY.
+
+**********************************************************************
+
+ output->next_section( `26) Structure (3)` ).
+
+ "The example demonstrates the following:
+ "- The method call takes care of providing the name of a database table name.
+ "- A structured data object is created based on the dynamically determined type.
+ " It is used as target data object for a SELECT statement. As shown further
+ " down in more detail, clauses of SELECT statements can be specified
+ " dynamically.
+
+ "Retrieving table name
+ DATA(type4struc) = lcl_det_at_runtime=>get_dyn_table_name( ).
+
+ DATA ref_dynstruc TYPE REF TO data.
+
+ "Creating structured data object
+ CREATE DATA ref_dynstruc TYPE (type4struc).
+
+ "Dynamic specification of the FROM clause
+ SELECT SINGLE *
+ FROM (type4struc)
+ INTO @ref_dynstruc->*.
+
+ output->display( |Structured data type/database table name determined at runtime: { type4struc } | ).
+ output->display( input = ref_dynstruc->* name = `ref_dynstruc->*` ).
+
+**********************************************************************
+
+ output->next_section( `27) Internal Table (4)` ).
+
+ "The example demonstrates the following:
+ "- The method call takes care of providing the name of a database table name.
+ "- An internal table is created based on the dynamically determined type.
+ " It is used as target data object for a SELECT statement.
+ "- The UP TO ... ROWS addition is provided with a random number in the example.
+ "- AS in the example above, the SELECT statement includes the dynamic
+ " specification of the FROM clause.
+
+ "Retrieving table name
+ DATA(type_name) = lcl_det_at_runtime=>get_dyn_table_name( ).
+
+ DATA ref_n TYPE REF TO data.
+
+ "Creating internal table based on the type determined at runtime
+ CREATE DATA ref_n TYPE TABLE OF (type_name).
+
+ "Specifying random number for up to clause
+ DATA(random_upto) = cl_abap_random_int=>create(
+ seed = cl_abap_random=>seed( ) min = 2
+ max = 6 )->get_next( ).
+
+ "Dynamic specification of the FROM clause
+ SELECT *
+ FROM (type_name)
+ INTO TABLE @ref_n->*
+ UP TO @random_upto ROWS.
+
+ output->display( |Table/type name determined at runtime: { type_name } | ).
+ output->display( |At most, { random_upto } lines should have been read from the database table.| ).
+ output->display( input = ref_n->* name = `ref_n->*` ).
+
+**********************************************************************
+
+ output->next_section( `28) Excursion: Absolute Type Names for Dynamically Specifying Types` ).
+
+ "In addition to character-like data objects for the type name specified within the
+ "parentheses, you can also use absolute type names for statements such as CREATE DATA.
+ "The absolute type name is retrieved using RTTI. See more on RTTI further down.
+
+ "Type to refer to
+ TYPES type4abs TYPE p LENGTH 4 DECIMALS 3.
+ "Data and object reference variables
+ DATA dref4abs TYPE REF TO data.
+ DATA oref4abs TYPE REF TO object.
+ "Getting absolute names using RTTI
+ DATA(abs_name_type) = cl_abap_typedescr=>describe_by_name( 'TYPE4ABS' )->absolute_name.
+ DATA(abs_name_cl) = cl_abap_typedescr=>describe_by_name( 'ZCL_DEMO_ABAP_DYNAMIC_PROG' )->absolute_name.
+
+ "Data references
+ ""Named data object holding the absolute name
+ CREATE DATA dref4abs TYPE (abs_name_type).
+ "Unnamed data object
+ CREATE DATA dref4abs TYPE ('\TYPE=STRING').
+
+ "Object references
+ "Named data object
+ CREATE OBJECT oref4abs TYPE (abs_name_cl).
+ "Unnamed data object
+ CREATE OBJECT oref4abs TYPE ('\CLASS=ZCL_DEMO_ABAP_DYNAMIC_PROG').
+
+ output->display( `No output for this section. See the code.` ).
+
**********************************************************************
output->next_section( `Dynamically Specifying Components/Clauses in Statements for Processing Internal Tables with ...` ).
- output->display( `21) SORT` ).
+ output->display( `29) SORT` ).
"A field is determined at runtime on whose basis a sorting is done on an
"internal table.
@@ -997,7 +1300,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
**********************************************************************
- output->next_section( `22) READ TABLE` ).
+ output->next_section( `30) READ TABLE` ).
"Dynamic key specification in READ TABLE statements
@@ -1038,7 +1341,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
**********************************************************************
- output->next_section( `23) MODIFY` ).
+ output->next_section( `31) MODIFY` ).
"Dynamic WHERE condition in MODIFY statements
"Note:
@@ -1086,7 +1389,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
**********************************************************************
- output->next_section( `24) DELETE` ).
+ output->next_section( `32) DELETE` ).
"Dynamic WHERE condition in DELETE statements
@@ -1100,8 +1403,8 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
( 500 )
( 600 ) ).
- output->display( `Internal table content before modifications:` ).
- output->display( input = itab_del_tab_dyn name = `itab_del_tab_dyn` ).
+ output->display( `Internal table content before modifications:` ).
+ output->display( input = itab_del_tab_dyn name = `itab_del_tab_dyn` ).
DO 3 TIMES.
TRY.
@@ -1129,7 +1432,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
**********************************************************************
- output->next_section( `25) LOOP` ).
+ output->next_section( `33) LOOP` ).
"Dynamic specification of the key in LOOP statements
"In the example, the loop can be executed with the entries 'skey' and 'primary_key'.
@@ -1160,7 +1463,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
**********************************************************************
output->next_section( `Dynamically Specifying Clauses in ABAP SQL SELECT Statements` ).
- output->display( `26) SELECT List` ).
+ output->display( `34) SELECT List` ).
"In the example, the SELECT list that is used in a SELECT statement is
"determined at runtime.
@@ -1180,7 +1483,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
**********************************************************************
- output->next_section( `27) FROM Clause` ).
+ output->next_section( `35) FROM Clause` ).
"In the example, the FROM clause that is used in a SELECT statement is
"determined at runtime. Here, the number of entries of a database table
@@ -1197,7 +1500,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
**********************************************************************
- output->next_section( `28) WHERE Clause` ).
+ output->next_section( `36) WHERE Clause` ).
"In the example, the WHERE clause that is used in a SELECT statement is
"determined at runtime. Here, the WHERE clause is based on a string
@@ -1218,14 +1521,15 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
**********************************************************************
- output->next_section( `29) Excursion: Multiple Dynamically Specified ` &&
+ output->next_section( `37) Excursion: Multiple Dynamically Specified ` &&
`Clauses in an ABAP SQL SELECT Statement` ).
"In this example, multiple clauses in a SELECT statement are
"determined at runtime to demonstrate the rich variety of possibilities.
- "Note: The rows and target table specifications are not real dynamic specifications in the
- "SELECT statement in the sense of syntax elements enclosed by parentheses. Here, they are just
- "included to provide some more 'dynamic' touch of the statement :)
+ "Note: The rows and target table specifications are not real dynamic
+ "specifications in the SELECT statement in the sense of syntax elements
+ "enclosed by parentheses. Here, they are just included to provide some
+ "more 'dynamic' touch of the statement :)
"Getting all clauses of the SELECT statement
DATA(dyn_syntax_elem) = lcl_det_at_runtime=>get_dyn_syntax_elements( ).
@@ -1255,7 +1559,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
**********************************************************************
- output->next_section( `30) Dynamic Invoke` ).
+ output->next_section( `38) Dynamic Invoke` ).
"In the example, both class and method are determined at runtime for
"the method call. The suitable parameter table is filled in the
@@ -1296,7 +1600,157 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
**********************************************************************
- output->next_section( `31) RTTI: Determining Data and Object Types at Runtime` ).
+ output->next_section( `39) RTTI: Getting Type Information at Runtime/Getting a Reference to a Type Description Object` ).
+
+ "Getting a reference to a type description object of a type.
+ "i.e. getting an instance of a type description class
+ "As shown below, the type decription object can be used
+ "to create data objects dynamically.
+
+ "Type for which information should be retrieved
+ TYPES: elem_type TYPE c LENGTH 5.
+
+ "Creating a data reference variable to hold the reference to
+ "the type description object
+ DATA type_descr_obj_elem TYPE REF TO cl_abap_elemdescr.
+
+ "Retrieving type information by creating an instance of a type description class
+ "As the name implies, the describe_by_name method expects the name of the type
+ "The following example uses the CAST operator for the necessary downcast.
+ type_descr_obj_elem = CAST #( cl_abap_typedescr=>describe_by_name( 'ELEM_TYPE' ) ).
+
+ "Using the older ?= operator
+ type_descr_obj_elem ?= cl_abap_typedescr=>describe_by_name( 'ELEM_TYPE' ).
+
+ "Inline declaration is handy to avoid helper variables.
+ DATA(type_descr_obj_elem_inl) = CAST cl_abap_elemdescr(
+ cl_abap_typedescr=>describe_by_name( 'ELEM_TYPE' ) ).
+
+ "You may also want to check the type description object in the debugger.
+ output->display( input = type_descr_obj_elem_inl name = `type_descr_obj_elem_inl` ).
+
+ "Various methods/attributes (note that they vary depending on the type) provide
+ "you with detailed information.
+ "The following examples show a selection.
+ "Kind/Type kind/Output length
+ DATA(kind_elem) = type_descr_obj_elem_inl->kind.
+ DATA(type_kind_elem) = type_descr_obj_elem_inl->type_kind.
+ DATA(output_length_elem) = type_descr_obj_elem_inl->output_length.
+
+ output->display( input = kind_elem name = `kind_elem` ).
+ output->display( input = type_kind_elem name = `type_kind_elem` ).
+ output->display( input = output_length_elem name = `output_length_elem` ).
+
+ "In the following example, the type properties are retrieved
+ "without casting. The data object has the type ref to
+ "cl_abap_typedescr. See the hierarchy tree of type description classes.
+ "The reference in the type description object references an
+ "object from one of the classes CL_ABAP_ELEMDESCR, CL_ABAP_ENUMDESCR,
+ "CL_ABAP_REFDESCR, CL_ABAP_STRUCTDESCR, CL_ABAP_TABLEDSECR,
+ "CL_ABAP_CLASSDESCR, or CL_ABAP_INTFDESCR.
+ "In the following case, it is CL_ABAP_ELEMDESCR.
+ "Note that in most of the RTTI examples in this class, the explicit
+ "casting is included when retrieving a reference to the type
+ "description object.
+ TYPES another_elem_type TYPE n LENGTH 3.
+ DATA(type_descr_obj_elem_inl_2) = cl_abap_typedescr=>describe_by_name( 'ANOTHER_ELEM_TYPE' ).
+
+ output->display( input = type_descr_obj_elem_inl_2->kind name = `type_descr_obj_elem_inl_2->kind` ).
+ output->display( input = type_descr_obj_elem_inl_2->type_kind name = `type_descr_obj_elem_inl_2->type_kind` ).
+
+ "More types
+ "Structured data type (here, using the name of a database table)
+ DATA(type_descr_obj_struc) = CAST cl_abap_structdescr(
+ cl_abap_typedescr=>describe_by_name( 'ZDEMO_ABAP_CARR' ) ).
+
+ "Various attributes/methods available for detailed information
+ "Kind
+ DATA(struc_kind) = type_descr_obj_struc->kind.
+ "Components of the structure (e.g. the component names and type description
+ "objects for the individual components)
+ DATA(comps_struc) = type_descr_obj_struc->get_components( ).
+ "The attribute also lists the component names and types (but not the type
+ "desription objects)
+ DATA(comps_struc2) = type_descr_obj_struc->components.
+ "Kind of structure
+ DATA(struct_kind) = type_descr_obj_struc->struct_kind.
+
+ output->display( input = struc_kind name = `struc_kind` ).
+ output->display( input = comps_struc name = `comps_struc` ).
+ output->display( input = comps_struc2 name = `comps_struc2` ).
+ output->display( input = struct_kind name = `struct_kind` ).
+
+ "Internal table type
+ TYPES table_type TYPE SORTED TABLE OF zdemo_abap_carr WITH UNIQUE KEY carrid.
+
+ DATA(type_descr_obj_tab) = CAST cl_abap_tabledescr(
+ cl_abap_typedescr=>describe_by_name( 'TABLE_TYPE' ) ).
+
+ "Kind
+ DATA(tab_kind) = type_descr_obj_tab->kind.
+ "The following method returns more information than the attribute below
+ "(e.g. key kind (unique) etc.)
+ DATA(tab_keys) = type_descr_obj_tab->get_keys( ).
+ DATA(tab_keys2) = type_descr_obj_tab->key. "Attribute; lists the keys
+ "Getting internal table components
+ "The method get_table_line_type returns a variable of type ref to cl_abap_datadescr.
+ "This way you can retrieve the table components. Method chaining comes in handy.
+ DATA(tab_comps) = CAST cl_abap_structdescr(
+ type_descr_obj_tab->get_table_line_type( ) )->get_components( ).
+
+ output->display( input = tab_kind name = `tab_kind` ).
+ output->display( input = tab_keys name = `tab_keys` ).
+ output->display( input = tab_keys2 name = `tab_keys2` ).
+ output->display( input = tab_comps name = `tab_comps` ).
+
+ "Reference type
+ TYPES ref_str TYPE REF TO string.
+ DATA(type_descr_obj_ref) = CAST cl_abap_refdescr(
+ cl_abap_typedescr=>describe_by_name( 'REF_STR' ) ).
+
+ "Kind
+ DATA(ref_kind) = type_descr_obj_ref->kind.
+ "Returns type description object of the referenced type
+ DATA(ref_type) = type_descr_obj_ref->get_referenced_type( ).
+ "Absolute type name
+ DATA(ref_type_abs_name) =
+ type_descr_obj_ref->get_referenced_type( )->absolute_name.
+ "Type kind
+ DATA(ref_type_type_kind) =
+ type_descr_obj_ref->get_referenced_type( )->type_kind.
+
+ output->display( input = ref_kind name = `ref_kind` ).
+ output->display( input = ref_type name = `ref_type` ).
+ output->display( input = ref_type_abs_name name = `ref_type_abs_name` ).
+ output->display( input = ref_type_type_kind name = `ref_type_type_kind` ).
+
+ "Getting a reference to a type description object of an existing data object.
+ "Instead of referring to the name of a type, referring to a data object here.
+ "The relevant method is describe_by_data
+
+ "Elementary data object
+ DATA dobj_elem TYPE i.
+ DATA(ty_des_obj_el) = CAST cl_abap_elemdescr(
+ cl_abap_typedescr=>describe_by_data( dobj_elem ) ).
+
+ "Structure
+ DATA dobj_struc TYPE zdemo_abap_carr.
+ DATA(ty_des_obj_struc) = CAST cl_abap_structdescr(
+ cl_abap_typedescr=>describe_by_data( dobj_struc ) ).
+
+ "Internal table
+ DATA dobj_itab TYPE TABLE OF zdemo_abap_carr WITH EMPTY KEY.
+ DATA(ty_des_obj_itab) = CAST cl_abap_tabledescr(
+ cl_abap_typedescr=>describe_by_data( dobj_itab ) ).
+
+ "Reference variable
+ DATA dref_var TYPE REF TO string.
+ DATA(ty_des_obj_dref) = CAST cl_abap_refdescr(
+ cl_abap_typedescr=>describe_by_data( dref_var ) ).
+
+**********************************************************************
+
+ output->next_section( `40) RTTI: Getting Type Information at Runtime for Miscellaneous Types` ).
"The example demonstrates RTTI as follows:
"- The method call takes care of providing the name of a type. It is implemented
@@ -1321,13 +1775,12 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
output->display( |Type name determined at runtime: { get_type }| ).
- DATA: dref TYPE REF TO data.
+ DATA dref TYPE REF TO data.
IF get_type <> `LCL_DET_AT_RUNTIME`
AND get_type <> `IF_OO_ADT_CLASSRUN`.
TRY.
CREATE DATA dref TYPE (get_type).
-
CATCH cx_sy_create_data_error.
output->display( `Create data error!` ).
ENDTRY.
@@ -1340,46 +1793,32 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
IF some_type->kind = cl_abap_typedescr=>kind_elem.
DATA(el) = CAST cl_abap_elemdescr( some_type ).
output->display( input = el name = `el` ).
-
"Various attributes and methods possible
output->display( input = el->type_kind name = `el->type_kind` ).
-
output->display( input = el->absolute_name name = `el->absolute_name` ).
-
output->display( input = el->get_relative_name( ) name = `el->get_relative_name( )` ).
"Structure
ELSEIF some_type->kind = cl_abap_typedescr=>kind_struct.
DATA(stru) = CAST cl_abap_structdescr( some_type ).
-
output->display( input = stru->absolute_name name = `stru->absolute_name` ).
-
output->display( input = stru->components name = `stru->components` ).
-
output->display( input = stru->struct_kind name = `stru->struct_kind` ).
-
output->display( input = stru->get_components( ) name = `stru->get_components( )` ).
"Internal table
ELSEIF some_type->kind = cl_abap_typedescr=>kind_table.
DATA(tab) = CAST cl_abap_tabledescr( some_type ).
-
output->display( input = tab->absolute_name name = `tab->absolute_name` ).
-
output->display( input = tab->table_kind name = `tab->table_kind` ).
-
output->display( input = tab->get_keys( ) name = `tab->get_keys` ).
-
output->display( input = tab->get_table_line_type( ) name = `tab->get_table_line_type( )` ).
"Reference
ELSEIF some_type->kind = cl_abap_typedescr=>kind_ref.
DATA(ref_descr) = CAST cl_abap_refdescr( some_type ).
-
output->display( input = ref_descr->absolute_name name = `ref_descr->absolute_name` ).
-
output->display( input = ref_descr->get_referenced_type( ) name = `ref_descr->get_referenced_type( )` ).
-
ELSE.
output->display( `Others ...` ).
ENDIF.
@@ -1392,13 +1831,9 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
"Class
IF some_type->kind = cl_abap_typedescr=>kind_class.
-
DATA(class_desc) = CAST cl_abap_classdescr( some_type ).
-
output->display( input = class_desc->absolute_name name = `class_desc->absolute_name` ).
-
output->display( input = class_desc->attributes name = `class_desc->attributes` ).
-
output->display( input = class_desc->methods name = `class_desc->methods` ).
"Creating an object based on a type determined at runtime
@@ -1406,113 +1841,164 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
TRY.
CREATE OBJECT oref TYPE (get_type).
-
"Retrieving type information
DATA(descr_ref) = cl_abap_typedescr=>describe_by_object_ref( oref ).
-
output->display( input = descr_ref->absolute_name name = `descr_ref->absolute_name` ).
-
output->display( input = descr_ref->kind name = `descr_ref->kind` ).
-
CATCH cx_root.
output->display( `Error` ).
-
ENDTRY.
"Interface
ELSEIF some_type->kind = cl_abap_typedescr=>kind_intf.
DATA(if_descr) = CAST cl_abap_intfdescr( some_type ).
-
output->display( input = if_descr->absolute_name name = `if_descr->absolute_name` ).
-
output->display( input = if_descr->methods name = `class_desc->methods` ).
-
ELSE.
output->display( `Others ...` ).
ENDIF.
-
ENDIF.
**********************************************************************
- output->next_section( `32) RTTC: Dynamically Creating Elementary Data Objects` ).
+ output->next_section( `41) RTTC: Dynamically Creating Data Types at Runtime` ).
- "The example demonstrates RTTC as follows:
- "- The method call takes care of providing the name of a built-in data type and more
- "- Depending on the type an elementary data object is created
- "- For demonstration purposes, RTTI is used to check on the created data object by
- " retrieving the type description.
+ "You can create data types at program runtime using methods of the type
+ "description classes of RTTS. These types are only valid locally in the
+ "program. They are also anonymous, i.e. they are only accessible through
+ "type description objects. As shown above, you can get a reference to a
+ "type description object of a type using the static methods of the class
+ "CL_ABAP_TYPEDESCR. The focus here is on using RTTC methods such as get*.
- DATA(b_type) = lcl_det_at_runtime=>get_builtin_type( ).
+ "Creating type description objects using ...
+ "... elementary data types
+ "Conceptually, all elementary, built-in ABAP types already exist and can
+ "be accessed by the corresponding get_* methods.
+ "In ADT, click CTRL + space after cl_abap_elemdescr=>... to check out the options.
+ "The following examples show a selection.
+ DATA(tdo_elem_i) = cl_abap_elemdescr=>get_i( ).
+ DATA(tdo_elem_string) = cl_abap_elemdescr=>get_string( ).
+ "For the length specification of type c, there is an importing parameter available.
+ DATA(tdo_elem_c_l20) = cl_abap_elemdescr=>get_c( 10 ).
+ "Type p with two parameters to be specified.
+ DATA(tdo_elem_p) = cl_abap_elemdescr=>get_p( p_length = 3 p_decimals = 2 ).
- DATA ref_bt TYPE REF TO data.
+ "Instead of calling get_i() and others having no importing parameters, you could also call
+ "the describe_by_name( ) method and pass the type names (Iā STRING etc.) as arguments.
+ "DATA(tdo_elem_i_2) = CAST cl_abap_elemdescr(
+ " cl_abap_typedescr=>describe_by_name( 'I' ) ).
+ "DATA(tdo_elem_string_2) = CAST cl_abap_elemdescr(
+ " cl_abap_typedescr=>describe_by_name( 'STRING' ) ).
- TRY.
- CASE b_type-builtin_type.
- WHEN 'd' OR 'decfloat16' OR 'decfloat34' OR 'f' OR 'i'
- OR 'string' OR 't' OR 'xstring'.
+ "... structured data types
+ "They are created based on a component description table.
- CREATE DATA ref_bt TYPE (b_type-builtin_type).
- WHEN 'c' OR 'n' OR 'x'.
- CREATE DATA ref_bt TYPE (b_type-builtin_type) LENGTH b_type-len.
- WHEN 'p'.
- CREATE DATA ref_bt TYPE p LENGTH b_type-len DECIMALS b_type-dec.
- WHEN OTHERS.
- output->display( `That didn't work.` ).
- ENDCASE.
+ "A structured type such as the following shall be created using a
+ "type description object.
+ TYPES:
+ BEGIN OF struc_type,
+ a TYPE string,
+ b TYPE i,
+ c TYPE c LENGTH 5,
+ d TYPE p LENGTH 4 DECIMALS 3,
+ END OF struc_type.
- "Getting type information using RTTI
- DATA(descr_builtin_type) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( ref_bt->* ) ).
+ "Creating a type description object using RTTC method
+ "Using the get method, you can create the type description object
+ "dynamically based on a component table. The component table is of type
+ "abap_component_tab. In this example, the component table is created inline.
+ DATA(tdo_struc) = cl_abap_structdescr=>get(
+ VALUE #(
+ ( name = 'A' type = cl_abap_elemdescr=>get_string( ) )
+ ( name = 'B' type = cl_abap_elemdescr=>get_i( ) )
+ ( name = 'C' type = cl_abap_elemdescr=>get_c( 5 ) )
+ ( name = 'D' type = cl_abap_elemdescr=>get_p( p_length = 4 p_decimals = 3 ) ) ) ).
- output->display( |Built-in type determined at runtime: { b_type-builtin_type } | ).
- output->display( `Created data object at runtime:` ).
- output->display( input = descr_builtin_type name = `descr_builtin_type` ).
+ "... internal table types
+ "Note: Specifying the line type is mandatory, the rest is optional.
- CATCH cx_root.
- output->display( `Something went wrong.` ).
- ENDTRY.
+ "An internal table type such as the following shall be created using a
+ "type description object.
+ TYPES std_tab_type_std_key TYPE STANDARD TABLE OF string WITH DEFAULT KEY.
+
+ "Creating a type description object using RTTC method
+ "Not specifying the other optional parameters means that the
+ "default values are used, for example, standard table is the
+ "default value for p_table_kind.
+ DATA(tdo_tab_1) = cl_abap_tabledescr=>get(
+ p_line_type = cl_abap_elemdescr=>get_string( ) ).
+
+ "Another internal table type for which more parameter specifications are needed
+ "The following internal table type shall be created using a type description object.
+ TYPES so_table_type TYPE SORTED TABLE OF zdemo_abap_flsch WITH UNIQUE KEY carrid connid.
+
+ "Creating a type description object using RTTC method
+ "The following example also demonstrates how comfortably constructor
+ "operators can be used at these positions.
+ DATA(tdo_tab_2) = cl_abap_tabledescr=>get(
+ p_line_type = CAST cl_abap_structdescr( cl_abap_tabledescr=>describe_by_name( 'ZDEMO_ABAP_FLSCH' ) )
+ p_table_kind = cl_abap_tabledescr=>tablekind_sorted
+ p_key = VALUE #( ( name = 'CARRID' ) ( name = 'CONNID' ) )
+ p_unique = cl_abap_typedescr=>true ).
+
+ " ... reference types
+ "Reference types such as the following shall be created using a
+ "type description object.
+ TYPES some_ref_type2t TYPE REF TO t.
+ TYPES some_ref_type2cl TYPE REF TO zcl_demo_abap_dynamic_prog.
+
+ "Using RTTC methods
+ "You can create a reference type from a base type. This base type
+ "may be class, interface or data type.
+ DATA(tdo_ref_1) = cl_abap_refdescr=>get( cl_abap_elemdescr=>get_t( ) ).
+ DATA(tdo_ref_2) = cl_abap_refdescr=>get( cl_abap_typedescr=>describe_by_name( 'ZCL_DEMO_ABAP_DYNAMIC_PROG' ) ).
+ "Alternative: get_by_name method
+ DATA(tdo_ref_3) = cl_abap_refdescr=>get_by_name( 'T' ).
+ DATA(tdo_ref_4) = cl_abap_refdescr=>get_by_name( 'ZCL_DEMO_ABAP_DYNAMIC_PROG' ).
+
+ output->display( `No output for this section. See the code.` ).
**********************************************************************
- output->next_section( `33) RTTC: Dynamically Creating Structured Data Object (1)` ).
+ output->next_section( `42) Dynamically Creating Data Objects at Runtime Using Type Description Objects (1) - Miscellaneous` ).
- "The example demonstrates RTTC as follows:
- "- The method call takes care of providing the name of a database table name.
- "- A structured data object is created based on the dynamically determined type.
- " It is used as target data object for a SELECT statement.
- "- A SELECT loop is used to sequentially process the read database table lines.
- " Here, the processed line is just output.
- "- The integer for the UP TO clause is specified at runtime.
+ "Using the TYPE HANDLE addition to CREATE DATA statements, you can
+ "dynamically create data objects at runtime based on type description objects.
+ "The following example uses type description objects from the previous example.
+ "For output purposes, the created data objects are assigned values.
- "Retrieving table name
- DATA(type4struc) = lcl_det_at_runtime=>get_dyn_table_name( ).
+ DATA dref_typ_obj TYPE REF TO data.
- DATA ref_dynstruc TYPE REF TO data.
+ "Elementary data object
+ CREATE DATA dref_typ_obj TYPE HANDLE tdo_elem_i.
+ dref_typ_obj->* = 5 + 4.
- "Creating structure data object
- CREATE DATA ref_dynstruc TYPE (type4struc).
+ output->display( input = dref_typ_obj->* name = `dref_typ_obj->*` ).
- "specifying random number for up to clause
- DATA(random_upto) = cl_abap_random_int=>create(
- seed = cl_abap_random=>seed( ) min = 2
- max = 6 )->get_next( ).
+ "Structured data object
+ CREATE DATA dref_typ_obj TYPE HANDLE tdo_struc.
+ dref_typ_obj->('A') = `hello`.
+ dref_typ_obj->('B') = 4 + 3.
+ dref_typ_obj->('C') = 'abcde'.
+ dref_typ_obj->('D') = '1.234'.
- output->display( |Structured data type/database table name determined at runtime: { type4struc } | ).
- output->display( |At most, { random_upto } lines should have been read from the database table.| ).
+ output->display( input = dref_typ_obj->* name = `dref_typ_obj->*` ).
- "SELECT loop
- SELECT *
- FROM (type4struc)
- INTO @ref_dynstruc->*
- UP TO @random_upto ROWS.
+ "Internal table
+ CREATE DATA dref_typ_obj TYPE HANDLE tdo_tab_2.
+ SELECT * FROM zdemo_abap_flsch INTO TABLE @dref_typ_obj->* UP TO 3 ROWS.
- output->display( input = ref_dynstruc->* ).
+ output->display( input = dref_typ_obj->* name = `dref_typ_obj->*` ).
- ENDSELECT.
+ "Reference
+ CREATE DATA dref_typ_obj TYPE HANDLE tdo_ref_3.
+ dref_typ_obj->* = NEW t( '120000' ).
+
+ output->display( input = dref_typ_obj->* name = `dref_typ_obj->*` ).
**********************************************************************
- output->next_section( `34) RTTC: Dynamically Creating Structured Data Object (2)` ).
+ output->next_section( `43) Dynamically Creating Data Objects at Runtime Using Type Description Objects (2) - Structure` ).
"This example includes the dynamic definition of a structure with three components
"using the GET method of the CL_ABAP_STRUCTDESCR class.
@@ -1568,34 +2054,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
**********************************************************************
- output->next_section( `35) RTTC: Dynamically Creating Internal Table (1)` ).
-
- "The example demonstrates RTTC as follows:
- "- The method call takes care of providing the name of a database table name.
- "- An internal table is created based on the dynamically determined type.
- " It is used as target data object for a SELECT statement.
- "- The SELECT statement includes the dynamic specification of the FROM clause.
-
- "Retrieving table name
- DATA(type_name) = lcl_det_at_runtime=>get_dyn_table_name( ).
-
- DATA ref_n TYPE REF TO data.
-
- "Creating internal table based on the type determined at runtime
- CREATE DATA ref_n TYPE TABLE OF (type_name).
-
- "Dynamic specification of FROM clause
- SELECT *
- FROM (type_name)
- INTO TABLE @ref_n->*
- UP TO 3 ROWS.
-
- output->display( |Table/type name determined at runtime: { type_name } | ).
- output->display( input = ref_n->* name = `ref_n->*` ).
-
-**********************************************************************
-
- output->next_section( `36) RTTC: Dynamically Creating Internal Table (2)` ).
+ output->next_section( `44) Dynamically Creating Data Objects at Runtime Using Type Description Objects (3) - Internal Table` ).
"In the example an internal table type is created based on a DDIC type.
"See the comments in the code.
@@ -1620,8 +2079,8 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION.
APPEND VALUE #( name = -name
type = st->get_component_type( -name ) ) TO comp_table.
- "Just for fun. The SELECT statement further down includes a dynamic specification
- "of the ORDER BY clause :)
+ "The SELECT statement further down includes a dynamic specification
+ "of the ORDER BY clause.
"In this case, just using the second field since MANDT is the first.
IF sy-tabix = 2.
DATA(dyn_order_by) = -name.