This commit is contained in:
danrega
2024-09-24 18:00:44 +02:00
parent 537f71433c
commit 239b041f62
4 changed files with 393 additions and 31 deletions

View File

@@ -74,7 +74,7 @@
- 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.
- 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.
- The testing of [procedure](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.
- Including external input in dynamic ABAP SQL statements without an appropriate handling, there can be potential security risks. You can, for example, use the `CL_ABAP_DYN_PRG` class to manage security risks.
@@ -3833,10 +3833,10 @@ ENDTRY.
- After the [`HANDLE`](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abapcreate_data_handle.htm) addition, a reference variable of the static type of class `CL_ABAP_DATADESCR` or its subclasses that points to a type description object are expected.
The following examples show snippets that have already been covered in several sections above.
The use the following methods to get type description objects:
They use the following methods to get type description objects:
- `cl_abap_typedescr=>describe_by_name` (based on an existing type name)
- `cl_abap_typedescr=>describe_by_data` (based on an existing data object)
- `...=>get*` (getting type description objects for elementary and other types)
- `...=>get*` (getting type description objects for elementary and other types; other get* methods are shown further down)
```abap
"------------------------------------------------------------------
@@ -3858,7 +3858,7 @@ DATA(tdo_from_name3) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_n
"------------------------------------------------------------------
"--- Getting a type description object from an existing data ------
"--- object name --------------------------------------------------
"--- object -------------------------------------------------------
"--- describe_by_data method --------------------------------------
"------------------------------------------------------------------
@@ -3868,8 +3868,7 @@ DATA struct_dobj TYPE zdemo_abap_fli.
DATA tab_dobj TYPE TABLE OF zdemo_abap_fli WITH EMPTY KEY.
DATA(tdo_from_dobj1) = cl_abap_typedescr=>describe_by_data( elem_dobj ).
DATA(dobj_name) = `STRUCT_DOBJ`.
DATA(tdo_from_dobj2) = cl_abap_typedescr=>describe_by_data( dobj_name ).
DATA(tdo_from_dobj2) = cl_abap_typedescr=>describe_by_data( struct_dobj ).
"As shown above, using a cast to get more details.
DATA(tdo_from_dobj3) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( tab_dobj ) ).
@@ -3892,9 +3891,9 @@ DATA(tdo_elem_dec34) = cl_abap_elemdescr=>get_decfloat34( ).
DATA(tdo_elem_f) = cl_abap_elemdescr=>get_f( ).
DATA(tdo_elem_xstr) = cl_abap_elemdescr=>get_xstring( ).
DATA(tdo_elem_i) = cl_abap_elemdescr=>get_i( ).
DATA(tdo_elemd_int1) = cl_abap_elemdescr=>get_int1( ).
DATA(tdo_elemd_int2) = cl_abap_elemdescr=>get_int2( ).
DATA(tdo_elemd_int8) = cl_abap_elemdescr=>get_int8( ).
DATA(tdo_elem_int1) = cl_abap_elemdescr=>get_int1( ).
DATA(tdo_elem_int2) = cl_abap_elemdescr=>get_int2( ).
DATA(tdo_elem_int8) = cl_abap_elemdescr=>get_int8( ).
"For the length specification of type c and others, there is
"an importing parameter available.

View File

@@ -25,6 +25,8 @@
- [Using Keys and Identifying RAP BO Instances in a Nutshell](#using-keys-and-identifying-rap-bo-instances-in-a-nutshell)
- [RAP Concepts](#rap-concepts)
- [Ensuring Data Consistency in a RAP Transaction](#ensuring-data-consistency-in-a-rap-transaction)
- [RAP Additional and Unmanaged Save](#rap-additional-and-unmanaged-save)
- [Handling Dependencies on RAP Business Objects in ABAP Unit](#handling-dependencies-on-rap-business-objects-in-abap-unit)
- [More Information](#more-information)
- [Executable Examples](#executable-examples)
@@ -168,8 +170,7 @@ The following points cover RAP-related terms such as *RAP business objects* and
when the RAP BO is accessed. This is covered in more detail
further down.
- Usually, saver classes are not needed in managed RAP BOs (except
for special variants of managed RAP BOs which are not covered
here). Local handler classes are usually
for special variants of managed RAP BOs such as [RAP additional save](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrap_add_save_glosry.htm) and [RAP unmanaged save](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrap_unman_save_glosry.htm)). Local handler classes are usually
needed in managed RAP BOs if implementations are required that
go beyond standard operations.
- Note: In more complex scenarios, with RAP BOs that
@@ -1617,11 +1618,6 @@ MODIFY ENTITIES OF root_ent IN LOCAL MODE
### Using Keys and Identifying RAP BO Instances in a Nutshell
<details>
<summary>Expand to view the details</summary>
<br>
The following bullet points outline important aspects regarding
keys and identifying [RAP BO
instances](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrap_bo_instance_glosry.htm "Glossary Entry") in ABAP EML statements.
@@ -1732,15 +1728,8 @@ contains all relevant components for the chosen scenario.
>```
> In cases where different data objects of key component groups of a BDEF derived type are to be assigned to the same key component group of the same entity, a direct assignment works without a syntax warning because the content is identical. A direct assignment is recommended (`...wa1_root-%tky = wa2_root-%tky ...`). The use of the `CORRESPONDING` operator is unnecessary and less performant. This is true, for example, for key component group assignments in the context of RAP response parameters failed and reported.
</details>
### RAP Concepts
<details>
<summary>Expand to view the details</summary>
<br>
**RAP numbering**
- A concept that deals with setting values for primary key fields.
@@ -1820,15 +1809,9 @@ contains all relevant components for the chosen scenario.
> `%pid` and `%tmp`) is unique and mapped to the final
> keys that are to be contained in `%key`.
</details>
### Ensuring Data Consistency in a RAP Transaction
<details>
<summary>Expand to view the details</summary>
<br>
The [LUW](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenluw_glosry.htm) concept, which deals with the transfer of data from one consistent state to another, applies to applications using RAP. RAP transactions are integrated with the [SAP LUW](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensap_luw_glosry.htm), which is a prerequisite for transactional consistency. RAP provides a standardized approach and rules ([RAP BO contract](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrap_bo_contract_glosry.htm)) for the [RAP business object (BO)](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrap_bo_glosry.htm) runtime to ensure that the RAP transaction is correctly implemented, data inconsistencies are avoided, and the SAP LUW is successfully completed.
**Phases of a RAP Transaction**
@@ -1903,7 +1886,60 @@ The following restrictions apply to operations and/or statements in the individu
|Report processing (`SUBMIT ...`) <br><br>(unrestricted ABAP language scope)|- |- |- |Not allowed in transactional contexts. Results in a syntax or runtime error. <br>`SUBMIT ... AND RETURN` does not currently return an error, but it leads to potentially unwanted screen processing, and because of the missing return channel, there is no proper error handling. |
</details>
<p align="right"><a href="#top">⬆️ back to top</a></p>
### RAP Additional and Unmanaged Save
- As covered in the RAP terms section, *managed* is an implementation type that is specified in the BDEF, and which determines the [RAP BO provider](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrap_bo_provider_glosry.htm "Glossary Entry"), and thus, how the transactional buffer is provided and how the behavior of a RAP BO is implemented.
- In a managed RAP BO, the RAP framework automatically executes the save, eliminating the need for any additional logic. However, you can modify this behavior by adding or replacing the default save logic. This is not applicable to unmanaged BOs, where the save is user-defined.
- RAP additional save
- This feature enhances the default save sequence by incorporating additional save logic.
- You can apply this additional save logic to the entire BO or a specific entity.
- For example, you can add functionality to be executed during the save, such as change documents or writing to an application log.
- The relevant BDEF syntax is `with additional save`
```abap
managed with additional save implementation in class bp_some_abp unique;
strict(2);
...
```
- The additional save logic is implemented in the `save_modified` RAP saver method.
- `save_modified` has three importing parameters with specific BDEF derived types:
- `create` of type `REQUEST FOR CHANGE ...`
- `update` of type `REQUEST FOR CHANGE ...`
- `delete` of type `REQUEST FOR DELETE ...`
- These BDEF derived types are deep structures containing internal tables with RAP BO instance keys and/or data, i.e. they contain those instances that are to be created, updated or deleted.
- Optional additions are available in the BDEF. With the specification in the code snippet above, by default, only the values of the key fields and changed fields are passed to the `save_modified` method. Using the addition `with full data`, you can, as the name implies, pass all instance data: `managed with additional save with full data implementation in class ...`.
- RAP unmanaged save
- This feature replaces the default managed save logic with a custom save logic.
- BDEF syntax:
```abap
managed with unmanaged save implementation in class bp_some_abp unique;
strict(2);
...
```
- Also in this case, ...
- you can apply the save logic to the entire BO or an individual entity.
- the implementation is done in the `save_modified` RAP saver method.
- More information:
- [ABAP Keyword Documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenbdl_saving.htm)
- Development guide for the ABAP RESTful Application Programming Model:
- [Additional Save](https://help.sap.com/docs/abap-cloud/abap-rap/additional-save)
- [Unmanaged Save](https://help.sap.com/docs/abap-cloud/abap-rap/unmanaged-save)
<p align="right"><a href="#top">⬆️ back to top</a></p>
### Handling Dependencies on RAP Business Objects in ABAP Unit
The [ABAP Unit Tests](14_ABAP_Unit_Tests.md) cheat sheet includes an example demonstrating the handling of dependencies on RAP business objects:
- Creating transactional buffer test doubles using the `CL_BOTD_TXBUFDBL_BO_TEST_ENV` class
- Mocking ABAP EML APIs using the `CL_BOTD_MOCKEMLAPI_BO_TEST_ENV` class
Note that there is a RAP-specific variant of the `CREATE OBJECT` statement available. [`CREATE OBJECT ... FOR TESTING.`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapcreate_object_for_testing.htm) enables the instantiation of RAP handler classes. Find more information in the [Development guide for the ABAP RESTful Application Programming Model](https://help.sap.com/docs/abap-cloud/abap-rap/test).
<p align="right"><a href="#top">⬆️ back to top</a></p>

View File

@@ -1673,7 +1673,7 @@ For more information about evaluating ABAP unit test results, see [here](https:/
## More Information
- openSAP course: [Writing Testable Code for ABAP](https://open.sap.com/courses/wtc1.OpenSAP+WTC1_W1U5+Writing+Testable+Code+for+ABAPComent)
- [Writing Testable Code for ABAP](https://learning.sap.com/courses/writing-testable-code-for-abap) course
- ABAP Keyword Documentation
- [ABAP Unit](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_unit.htm)
- [Testing repository objects](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abentest_relations.htm)

View File

@@ -18,6 +18,7 @@
- [Assigning References to Data Reference Variables](#assigning-references-to-data-reference-variables)
- [Creating Anonymous Data Objects](#creating-anonymous-data-objects)
- [Constants and Immutable Variables](#constants-and-immutable-variables)
- [Built-In Data Objects](#built-in-data-objects)
- [Type Conversions, Compatibility and Assignments](#type-conversions-compatibility-and-assignments)
- [Terms Related to Data Types and Objects in a Nutshell](#terms-related-to-data-types-and-objects-in-a-nutshell)
- [Notes on the Declaration Context](#notes-on-the-declaration-context)
@@ -1123,6 +1124,332 @@ SELECT * FROM zdemo_abap_carr INTO TABLE @FINAL(itab_final_inl).
<p align="right"><a href="#top">⬆️ back to top</a></p>
### Built-In Data Objects
In [ABAP programs](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_program_glosry.htm), you can use built-in data objects, including:
| Built-in data object | Details |
| -------- | ------- |
| ABAP system fields | These fields, filled by the [ABAP runtime framework](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_runtime_frmwk_glosry.htm), can be used to query system information and more. Typically, they should only be read, and not overwritten. The fields are components of the built-in structure `sy` (or `syst`). Prominent ones are `sy-subrc` (return code of many ABAP statements; typically, the value 0 indicates success), `sy-tabix` (row index of internal tables), and `sy-index` (loop pass index), which can be used in [ABAP for Cloud Development](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_for_cloud_dev_glosry.htm). However, most of these fields should not be used in ABAP for Cloud Development (indicated by a syntax warning) because they refer to [Standard ABAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenstandard_abap_glosry.htm) contexts (e.g. classic dynpros and lists), or their values are not relevant in a cloud context. More information about the purpose of the individual components is available at [ABAP System Fields (F1 documentation for Standard ABAP)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abensystem_fields.htm).|
| `space` constant | It is of type type `c`, length 1, and contains a blank character. |
| `me` self-reference | Used in ABAP Objects, it's a local reference variable for instance method implementations. At runtime, it points to the instance executing the method. It is primarily used to be explicit about, for exmaple, using instance attributes of the class, especially if there is a local data object with the same name.|
Expand the following collapsible section to view the code of an example. To try it out, create a demo class named `zcl_some_class` and paste the code into it. After activation, choose *F9* in ADT to execute the class. The example is set up to display output in the console.
<details>
<summary>Expand to view the code</summary>
<!-- -->
```abap
CLASS zcl_some_class DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
DATA str TYPE string VALUE `Data object 'str' declared in the private visibility section`.
ENDCLASS.
CLASS zcl_some_class IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
"In ABAP for Cloud Development, the following statement will show a syntax warning saying that
"sy should not be used. Here, it is used for demonstration purposes.
"In the example, RTTI is used to get all component names of the built-in data object sy. In the loop,
"ABAP statements are created (they represent simple assignments using the various sy components) and
"output to the console. You can insert all the output DATA(...) = ... statements in the demo class's
"main method implementation. The purpose is to demonstrate that most of the sy components should not be
"used in ABAP for Cloud Development. Most of the statements will show a syntax warning in ABAP for Cloud
"Development. Check the ABAP Keyword Documentation (for Standard ABAP) and the F2 information for the
"purpose of the individual sy components.
LOOP AT CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data( sy ) )->components INTO DATA(co).
DATA(sycomp) = to_lower( co-name ).
DATA(code) = |DATA(sy{ sycomp }) = sy-{ sycomp }.|.
out->write( code ).
ENDLOOP.
out->write( |\n| ).
out->write( |\n| ).
"Demonstrating prominent sy components that can be used in ABAP for Cloud Development
"------------------------------------------------------------------------------
"------------------ sy-subrc: Return code of ABAP statements ------------------
"------------------------------------------------------------------------------
"Many ABAP statements set a sy-subrc value. Check the ABAP Keyword Documentation
"for individual statements. Usually, the value 0 indicates a successful execution.
DATA(some_string) = `ABAP`.
"FIND statements
"Found
FIND `P` IN some_string.
ASSERT sy-subrc = 0.
"Not found
FIND `p` IN some_string RESPECTING CASE.
ASSERT sy-subrc = 4.
DATA(some_itab) = VALUE string_table( ( `a` ) ( `b` ) ( `c` ) ( `d` ) ).
"READ TABLE statements
"Entry available
READ TABLE some_itab INTO DATA(wa1) INDEX 3.
ASSERT sy-subrc = 0.
"Entry not available
READ TABLE some_itab INTO DATA(wa2) INDEX 7.
ASSERT sy-subrc = 4.
"ABAP SQL statements
DELETE FROM zdemo_abap_tab1.
IF sy-subrc = 0.
out->write( `DELETE: All rows were deleted.` ).
ELSE.
out->write( `DELETE: No row was deleted because it was already empty.` ).
ENDIF.
INSERT zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 1 ) ( key_field = 2 ) ) ).
IF sy-subrc = 0.
out->write( `INSERT: All rows of the internal table were inserted.` ).
ENDIF.
INSERT zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 3 ) ( key_field = 3 ) ) ) ACCEPTING DUPLICATE KEYS.
IF sy-subrc = 4.
out->write( `INSERT ... ACCEPTING DUPLICATE KEYS: sy-subrc has the value 4 in this case. Not all rows of the ` &&
`internal table were inserted because a row with the key already exists.` ).
ENDIF.
DELETE FROM zdemo_abap_tab1 WHERE key_field = 3.
IF sy-subrc = 0.
out->write( `DELETE: The row matching the WHERE condition was deleted.` ).
ELSE.
out->write( `DELETE: No match according to the WHERE condition.` ).
ENDIF.
DELETE FROM zdemo_abap_tab1 WHERE key_field = 3.
IF sy-subrc = 0.
out->write( `DELETE: The row matching the WHERE condition was deleted.` ).
ELSE.
out->write( `DELETE: No match according to the WHERE condition.` ).
ENDIF.
"------------------------------------------------------------------------------
"--------------------------- sy-index: Loop indexes ---------------------------
"------------------------------------------------------------------------------
CLEAR some_string.
"DO loops
DO 5 TIMES.
some_string = some_string && sy-index.
ENDDO.
ASSERT some_string = `12345`.
CLEAR some_string.
DO 10 TIMES.
some_string = some_string && sy-index.
IF sy-index = 7.
EXIT.
ENDIF.
ENDDO.
ASSERT some_string = `1234567`.
CLEAR some_string.
DATA number TYPE i.
"WHILE loop
WHILE number < 9.
number = sy-index.
some_string = some_string && number.
ENDWHILE.
ASSERT some_string = `123456789`.
"------------------------------------------------------------------------------
"------------------- sy-tabix: Row index of internal tables -------------------
"------------------------------------------------------------------------------
"Demo standard internal table with 5 entries
DATA(std_itab) = VALUE string_table( ( `a` ) ( `b` ) ( `c` ) ( `d` ) ( `e` ) ).
"READ TABLE statement using a free key
READ TABLE std_itab INTO DATA(wa3) WITH KEY table_line = `b`.
ASSERT sy-tabix = 2.
"Demo hashed internal table with 5 entries
DATA(hashed_itab) = VALUE string_hashed_table( ( `a` ) ( `b` ) ( `c` ) ( `d` ) ( `e` ) ).
"READ TABLE statement using a free key
READ TABLE hashed_itab INTO DATA(wa4) WITH KEY table_line = `b`.
"Hashed tables do not have a primary table index.
ASSERT sy-tabix = 0.
CLEAR some_string.
"LOOP statements
LOOP AT std_itab INTO DATA(wa5).
some_string = some_string && sy-tabix.
ENDLOOP.
ASSERT some_string = `12345`.
CLEAR some_string.
"Step addition
"In the example, the table is looped across backwards
"indicated by the negative value. The step size 1 indicates
"that each line is respected.
LOOP AT std_itab INTO DATA(wa6) STEP -1.
some_string = some_string && sy-tabix.
ENDLOOP.
ASSERT some_string = `54321`.
CLEAR some_string.
"Forward loop, step size = 2
LOOP AT std_itab INTO DATA(wa7) STEP 2.
some_string = some_string && sy-tabix.
ENDLOOP.
ASSERT some_string = `135`.
CLEAR some_string.
"FROM/TO additions
LOOP AT std_itab INTO DATA(wa8) FROM 2 TO 4.
some_string = some_string && sy-tabix.
ENDLOOP.
ASSERT some_string = `234`.
CLEAR some_string.
"STEP/FROM additions
LOOP AT std_itab INTO DATA(wa9) STEP 2 FROM 2.
some_string = some_string && sy-tabix.
ENDLOOP.
ASSERT some_string = `24`.
CLEAR some_string.
"Hashed table
LOOP AT hashed_itab INTO DATA(wa10).
some_string = some_string && sy-tabix.
ENDLOOP.
ASSERT some_string = `00000`.
"------------------------------------------------------------------------------
"------------------------ sy-dbcnt: Edited table rows -------------------------
"------------------------------------------------------------------------------
DELETE FROM zdemo_abap_tab1.
DATA(dbcnt) = sy-dbcnt.
out->write( |Dbtab rows deleted: { dbcnt }| ).
INSERT zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 1 ) ( key_field = 2 ) ) ).
ASSERT sy-dbcnt = 2.
INSERT zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 3 ) ( key_field = 3 ) ) ) ACCEPTING DUPLICATE KEYS.
ASSERT sy-dbcnt = 1.
MODIFY zdemo_abap_tab1 FROM @( VALUE #( key_field = 1 char1 = 'aaa' ) ).
ASSERT sy-dbcnt = 1.
UPDATE zdemo_abap_tab1 SET char2 = 'bbb'.
ASSERT sy-dbcnt = 3.
DELETE FROM zdemo_abap_tab1 WHERE num1 IS INITIAL.
ASSERT sy-dbcnt = 3.
"------------------------------------------------------------------------------
"------------- sy-fdpos: Occurrence in byte or character strings --------------
"------------------------------------------------------------------------------
"For example, relevant in comparison expressions such as CS (constains string).
"If the comparison is true, sy-fdpos contains the offset of the found value. If it
"is false, sy-fdpos contains the length of the searched string.
some_string = `###abap###`.
IF some_string CS `p`.
out->write( |The substring is found. Offset of first finding: { sy-fdpos }| ).
ELSE.
out->write( |The substring is not found. Length of searched string: { sy-fdpos }| ).
ASSERT sy-fdpos = strlen( some_string ).
ENDIF.
IF some_string CS `#`.
out->write( |The substring is found. Offset of first finding: { sy-fdpos }| ).
ELSE.
out->write( |The substring is not found. Length of searched string: { sy-fdpos }| ).
ASSERT sy-fdpos = strlen( some_string ).
ENDIF.
IF some_string CS `Y`.
out->write( |The substring is found. Offset of first finding: { sy-fdpos }| ).
ELSE.
out->write( |The substring is not found. Length of searched string: { sy-fdpos }| ).
ASSERT sy-fdpos = strlen( some_string ).
ENDIF.
"------------------------------------------------------------------------------
"----------------------------- Constant space ---------------------------------
"------------------------------------------------------------------------------
"Has the data type c, length 1, and contains a blank character.
"Note: Trailing blanks are ignored in most operand positions. Therfore, the constant
"space should not be used in such positions.
some_string = |{ space }{ space }|.
ASSERT some_string = ``.
some_string = `#` && space && space && space && space && space && `#`.
ASSERT some_string = `##`.
"Using a CONCATENATE statement, blanks are respected after the SEPARATED BY
"addition only
CONCATENATE space space INTO some_string SEPARATED BY space.
ASSERT some_string = ` `.
"Text field literal, concatentation without SEPARATED BY space
DATA some_char TYPE c LENGTH 5.
CONCATENATE '#' space space '#' INTO some_char.
ASSERT some_char = '##'.
CONCATENATE space space '#' space '#' INTO some_char.
ASSERT some_char = '##'.
"------------------------------------------------------------------------------
"----------------------------- Self-reference me ------------------------------
"------------------------------------------------------------------------------
"When implementing instance methods, you can optionally make use of the implicitly available
"object reference variable me which is always available at runtime and points to the respective
"object itself. You can use it to refer to components of the instance of a particular class.
"Intentionally creating a data object that has the same name as a data object
"created in the private visibility section of the demo class.
DATA str TYPE string VALUE `Local data object 'str'`.
"Demo assignments
"dobj1 contains the value of the locally declared data object
DATA(dobj1) = str.
"dobj2 contains the value of the class attribute
DATA(dobj2) = me->str.
out->write( data = dobj1 name = `dobj1` ).
out->write( data = dobj2 name = `dobj2` ).
ENDMETHOD.
ENDCLASS.
```
</details>
<p align="right"><a href="#top">⬆️ back to top</a></p>
## Type Conversions, Compatibility and Assignments
A value assignment means that the value of a data object is transferred to a target data object. If the data types of the source and target are compatible, the content is copied unchanged. If they are incompatible and a suitable [conversion rule](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenconversion_rule_glosry.htm) exists, the content is converted.
The following cases must be distinguished with regard to the data type: