Update
This commit is contained in:
@@ -506,7 +506,7 @@ s2 = CORRESPONDING #( s1 MAPPING d = c EXCEPT b ).
|
|||||||
|
|
||||||
"Specifying an asterisk (*) after EXCEPT in combination with specifying mappings
|
"Specifying an asterisk (*) after EXCEPT in combination with specifying mappings
|
||||||
"means that all non-specified components after MAPPING remain initial in the target
|
"means that all non-specified components after MAPPING remain initial in the target
|
||||||
s2 = CORRESPONDING #( s1 MAPPING d = c EXCEPT * ).
|
s2 = CORRESPONDING #( s1 MAPPING d = c EXCEPT * ).
|
||||||
|
|
||||||
*A B D
|
*A B D
|
||||||
*0 bbbbb
|
*0 bbbbb
|
||||||
@@ -760,20 +760,32 @@ DATA(oref5) = NEW cl_b( 123 ).
|
|||||||
Examples:
|
Examples:
|
||||||
``` abap
|
``` abap
|
||||||
"Result: 0.2
|
"Result: 0.2
|
||||||
DATA(a) = CONV decfloat34( 1 / 5 ).
|
DATA(conv_res) = CONV decfloat34( 1 / 5 ).
|
||||||
|
|
||||||
"Comparison with an expression without CONV; the result is 0, the data type is i
|
"Comparison with an expression without CONV
|
||||||
DATA(b) = 1 / 5.
|
"The result is 0, the data type is i.
|
||||||
|
DATA(res) = 1 / 5.
|
||||||
|
|
||||||
|
"Example with internal table types
|
||||||
|
TYPES inttab_type TYPE TABLE OF i WITH EMPTY KEY.
|
||||||
|
DATA itab TYPE SORTED TABLE OF i WITH NON-UNIQUE DEFAULT KEY.
|
||||||
|
FIELD-SYMBOLS <fs> TYPE inttab_type.
|
||||||
|
|
||||||
|
"The following assignment is not possible due to incompatible types,
|
||||||
|
"although the internal table has the same line type (but there is a
|
||||||
|
"different table type and key).
|
||||||
|
"ASSIGN itab TO <fs>.
|
||||||
|
|
||||||
|
"Using CONV to convert the internal table to the required table type.
|
||||||
|
DATA(conv_itab) = CONV inttab_type( itab ).
|
||||||
|
ASSIGN conv_itab TO <fs>.
|
||||||
```
|
```
|
||||||
|
|
||||||
Excursion: As outlined above, you can construct structures and internal
|
**Constructing data objects with the CONV operator**
|
||||||
tables using the `VALUE` operator. Using this operator for
|
|
||||||
constructing [elementary data
|
As outlined above, you can construct structures and internal
|
||||||
objects](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenelementary_data_object_glosry.htm "Glossary Entry")
|
tables using the `VALUE` operator. Using `VALUE` for
|
||||||
is not possible apart from creating a data object with an initial value,
|
constructing [elementary data objects](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenelementary_data_object_glosry.htm "Glossary Entry") and providing values is not possible. You can only use it to create a data object with an initial value, for example `DATA(str) = VALUE string( ).`. The `CONV` operator closes this gap.
|
||||||
for example `DATA(str) = VALUE string( ).`. The `CONV`
|
|
||||||
operator closes this gap. However, in some cases, the use of
|
|
||||||
`CONV` is redundant.
|
|
||||||
|
|
||||||
``` abap
|
``` abap
|
||||||
DATA(c) = CONV decfloat34( '0.4' ).
|
DATA(c) = CONV decfloat34( '0.4' ).
|
||||||
@@ -787,12 +799,10 @@ e = '0.4'.
|
|||||||
"Redundant conversion
|
"Redundant conversion
|
||||||
"Derives the string type automatically
|
"Derives the string type automatically
|
||||||
DATA(f) = `hallo`.
|
DATA(f) = `hallo`.
|
||||||
|
|
||||||
"Produces a syntax warning
|
"Produces a syntax warning
|
||||||
"DATA(g) = CONV string( `hallo` ).
|
"DATA(g) = CONV string( `hallo` ).
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
<p align="right"><a href="#top">⬆️ back to top</a></p>
|
<p align="right"><a href="#top">⬆️ back to top</a></p>
|
||||||
|
|
||||||
## EXACT
|
## EXACT
|
||||||
@@ -816,16 +826,35 @@ DATA(f) = `hallo`.
|
|||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
``` abap
|
``` abap
|
||||||
"Leads to a data loss when converting to a data object accepting only a single character
|
"-------------- Lossless assignments -------------
|
||||||
|
|
||||||
|
"Note: An assignment is made in accordance with conversion rules. Check
|
||||||
|
"the ABAP Keyword Documentation for these rules. An assignment is only
|
||||||
|
"made if no values are lost. Otherwise, an error occurs. Either it is
|
||||||
|
"detected by static code checks or at runtime raising a catchable exception.
|
||||||
|
TYPES clen3 TYPE c LENGTH 3.
|
||||||
|
DATA(as1) = EXACT clen3( abap_true ).
|
||||||
|
DATA(as2) = EXACT clen3( 'XY' ).
|
||||||
|
"DATA(as3) = EXACT clen3( 'abcd' ).
|
||||||
|
|
||||||
|
"Catching exception
|
||||||
TRY.
|
TRY.
|
||||||
DATA(exact1) = EXACT abap_bool( 'XY' ).
|
DATA(as4) = EXACT clen3( 'abcd' ).
|
||||||
CATCH CX_SY_CONVERSION_DATA_LOSS INTO DATA(error1).
|
CATCH cx_sy_conversion_data_loss.
|
||||||
ENDTRY.
|
ENDTRY.
|
||||||
|
|
||||||
"The calculation cannot be executed exactly; a rounding is necessary
|
"-------------- Lossless Calculations -------------
|
||||||
|
|
||||||
|
"The first statement works, whereas the second statement raises an exception.
|
||||||
|
"A rounding to two decimal places is required.
|
||||||
|
TYPES packednum TYPE p LENGTH 8 DECIMALS 2.
|
||||||
|
DATA(calc1) = EXACT packednum( 1 / 4 ).
|
||||||
|
"DATA(calc2) = EXACT packednum( 1 / 3 ).
|
||||||
|
|
||||||
|
"Catching exceptions when rounding in lossless calculations
|
||||||
TRY.
|
TRY.
|
||||||
DATA(exact2) = EXACT decfloat34( 1 / 3 ).
|
DATA(calc3) = EXACT packednum( 1 / 3 ).
|
||||||
CATCH CX_SY_CONVERSION_ROUNDING INTO DATA(error2).
|
CATCH cx_sy_conversion_rounding.
|
||||||
ENDTRY.
|
ENDTRY.
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -860,11 +889,21 @@ DATA dref_a TYPE REF TO i.
|
|||||||
"Getting references
|
"Getting references
|
||||||
dref_a = REF #( num ).
|
dref_a = REF #( num ).
|
||||||
|
|
||||||
|
"Inline declaration
|
||||||
|
DATA(dref_b) = REF #( `hallo` ).
|
||||||
"Inline declaration and explicit type specification
|
"Inline declaration and explicit type specification
|
||||||
DATA(dref_b) = REF string( `hallo` ).
|
DATA(dref_c) = REF abap_bool( 'X' ).
|
||||||
|
|
||||||
|
"Specifying table expressions as arguments. The example code includes
|
||||||
|
"additions to avoid an exception if table lines are not found.
|
||||||
|
DATA int_tab TYPE TABLE OF i WITH EMPTY KEY.
|
||||||
|
int_tab = VALUE #( ( 1 ) ( 2 ) ( 3 ) ).
|
||||||
|
DATA(dref_d) = REF #( int_tab[ 2 ] ).
|
||||||
|
DATA(dref_e) = REF #( int_tab[ 6 ] OPTIONAL ). "Initial reference variable
|
||||||
|
DATA(dref_f) = REF #( int_tab[ 7 ] DEFAULT NEW #( 123 ) ). "Providing a default value
|
||||||
|
|
||||||
"Object references
|
"Object references
|
||||||
DATA(oref_a) = NEW some_class( ).
|
DATA(oref_a) = NEW zcl_demo_abap_objects( ).
|
||||||
DATA(oref_b) = REF #( oref_a ).
|
DATA(oref_b) = REF #( oref_a ).
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -892,17 +931,70 @@ DATA(oref_b) = REF #( oref_a ).
|
|||||||
functional method calls are possible, too. See more information
|
functional method calls are possible, too. See more information
|
||||||
[here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenconstructor_expression_cast.htm).
|
[here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenconstructor_expression_cast.htm).
|
||||||
|
|
||||||
[Run Time Type Identification
|
Examples:
|
||||||
(RTTI)](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_identific_glosry.htm "Glossary Entry")
|
|
||||||
examples:
|
|
||||||
``` abap
|
``` abap
|
||||||
|
"Performing casts on arguments and creating a reference variable that has the
|
||||||
|
"static type as specified as a result.
|
||||||
|
|
||||||
|
"Declaring data reference variables
|
||||||
|
DATA ref_i TYPE REF TO i.
|
||||||
|
DATA ref_gen TYPE REF TO data. "Generic type
|
||||||
|
|
||||||
|
"Creating an anonymous data object
|
||||||
|
ref_i = NEW #( 789 ).
|
||||||
|
|
||||||
|
"Upcast
|
||||||
|
"Static type of the target is less specific than or the same as the static
|
||||||
|
"type of the source
|
||||||
|
ref_gen = ref_i.
|
||||||
|
"The CAST operator can also be specified for upcasts. In this case, it can but
|
||||||
|
"need not be specified.
|
||||||
|
ref_gen = CAST #( ref_i ).
|
||||||
|
|
||||||
|
"Downcast
|
||||||
|
"Static type of the target is more specific than the static type of the source
|
||||||
|
"A check must be made at runtime before the assignment is done. If you indeed
|
||||||
|
"want to trigger such a downcast, you must do it explicitly in your code, for
|
||||||
|
"example, using the CAST operator (older operator: ?=).
|
||||||
|
|
||||||
|
"A syntax error occurs for the first statement. An explicit casting is required.
|
||||||
|
"ref_i = ref_gen.
|
||||||
|
ref_i = CAST #( ref_gen ).
|
||||||
|
|
||||||
|
"Like a data reference variable, the expressions can be followed by the
|
||||||
|
"dereferencing operator
|
||||||
|
ref_gen = NEW string( `hi` ).
|
||||||
|
CAST string( ref_gen )->* = `abap`.
|
||||||
|
DATA(str) = CAST string( ref_gen )->*.
|
||||||
|
|
||||||
|
"In case of static structured types, you can use the object component
|
||||||
|
"selector (->).
|
||||||
|
ref_gen = NEW zdemo_abap_carr( ).
|
||||||
|
CAST zdemo_abap_carr( ref_gen )->carrid = 'XY'.
|
||||||
|
DATA(comp) = CAST zdemo_abap_carr( ref_gen )->carrid.
|
||||||
|
"Dynamic specifications are possible.
|
||||||
|
CAST zdemo_abap_carr( ref_gen )->('CARRID') = 'ZZ'.
|
||||||
|
DATA(dyncomp) = |{ CAST zdemo_abap_carr( ref_gen )->('CARRID') }|.
|
||||||
|
|
||||||
|
"In the context of RTTS (see the cheat sheet about dynamic programming),
|
||||||
|
"helper variables are often required to perform a downcast of a type description
|
||||||
|
"object to a specialized class. The following examples, show how such helper
|
||||||
|
"variables can be reduced by using statements with CAST.
|
||||||
"Getting component information
|
"Getting component information
|
||||||
DATA(components) = CAST cl_abap_structdescr(
|
DATA st TYPE zdemo_abap_carr.
|
||||||
cl_abap_typedescr=>describe_by_data( some_object ) )->components.
|
DATA(components) = CAST cl_abap_structdescr(
|
||||||
|
cl_abap_typedescr=>describe_by_data( st ) )->components.
|
||||||
|
|
||||||
|
"A constructor expression as above instead of, for example, using helper variables
|
||||||
|
"and the older ?= operator.
|
||||||
|
DATA ref_struc_type TYPE REF TO cl_abap_structdescr.
|
||||||
|
DATA comps TYPE abap_compdescr_tab.
|
||||||
|
ref_struc_type ?= cl_abap_typedescr=>describe_by_data( st ).
|
||||||
|
comps = ref_struc_type->components.
|
||||||
|
|
||||||
"Getting method information
|
"Getting method information
|
||||||
DATA(methods) = CAST cl_abap_objectdescr(
|
DATA(methods) = CAST cl_abap_objectdescr(
|
||||||
cl_abap_objectdescr=>describe_by_name( 'LOCAL_CLASS' ) )->methods.
|
cl_abap_objectdescr=>describe_by_name( 'ZCL_DEMO_ABAP_OBJECTS' ) )->methods.
|
||||||
```
|
```
|
||||||
|
|
||||||
<p align="right"><a href="#top">⬆️ back to top</a></p>
|
<p align="right"><a href="#top">⬆️ back to top</a></p>
|
||||||
@@ -928,10 +1020,51 @@ DATA(methods) = CAST cl_abap_objectdescr(
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
``` abap
|
``` abap
|
||||||
DATA(b) = COND #( WHEN a BETWEEN 1 AND 3 THEN w
|
DATA(day_or_night) = COND #( WHEN cl_abap_context_info=>get_system_time( ) BETWEEN '050000' AND '220000'
|
||||||
WHEN a > 4 THEN x
|
THEN `day`
|
||||||
WHEN a IS INITIAL THEN y
|
ELSE `night` ).
|
||||||
ELSE z ).
|
|
||||||
|
"A constructor expression as above instead of, for example, an IF statement as follows.
|
||||||
|
IF cl_abap_context_info=>get_system_time( ) BETWEEN '050000' AND '220000'.
|
||||||
|
day_or_night = `day`.
|
||||||
|
ELSE.
|
||||||
|
day_or_night = `night`.
|
||||||
|
ENDIF.
|
||||||
|
|
||||||
|
"Multiple logical expressions initiated by WHEN
|
||||||
|
"Also LET expressions (see details further down) are possible.
|
||||||
|
DATA(time_of_day) = COND #( LET time = cl_abap_context_info=>get_system_time( ) IN
|
||||||
|
WHEN time BETWEEN '050001' AND '120000' THEN |Good morning, it's { time TIME = ISO }.|
|
||||||
|
WHEN time BETWEEN '120001' AND '180000' THEN |Good afternoon, it's { time TIME = ISO }.|
|
||||||
|
WHEN time BETWEEN '180001' AND '220000' THEN |Good evening, it's { time TIME = ISO }.|
|
||||||
|
ELSE |Good night, it's { time TIME = ISO }.| ).
|
||||||
|
|
||||||
|
"THROW addition to raise an exception (working like RAISE EXCEPTION TYPE statements)
|
||||||
|
"by specifying an exception class
|
||||||
|
"Note: It is possible to ...
|
||||||
|
"- specify the THROW addition also after THEN.
|
||||||
|
"- make exceptions resumable using the RESUMABLE addition.
|
||||||
|
DATA(num1) = 0.
|
||||||
|
DATA(num2) = 0.
|
||||||
|
TRY.
|
||||||
|
"The example raises the exception because both operands have the value 0.
|
||||||
|
DATA(div) = COND decfloat34( WHEN num1 <> 0 AND num2 <> 0 THEN num1 / num2
|
||||||
|
WHEN num1 = 0 AND num2 <> 0 THEN num1 / num2
|
||||||
|
ELSE THROW cx_sy_zerodivide( ) ).
|
||||||
|
CATCH cx_sy_zerodivide.
|
||||||
|
DATA(two_zeros) = `Zero division`.
|
||||||
|
ENDTRY.
|
||||||
|
|
||||||
|
"Excursion: The following statement does not result in an error in ABAP (zero
|
||||||
|
"division 'allowed' if the first operand has also the value 0).
|
||||||
|
div = 0 / 0.
|
||||||
|
|
||||||
|
"THROW SHORTDUMP addition to raise a runtime error (working like RAISE SHORTDUMP
|
||||||
|
"TYPE statements) by specifying an exception class; a message can be also passed,
|
||||||
|
"and input parameters can be filled
|
||||||
|
div = COND decfloat34( WHEN num1 <> 0 AND num2 <> 0 THEN num1 / num2
|
||||||
|
WHEN num1 = 0 AND num2 <> 0 THEN num1 / num2
|
||||||
|
ELSE THROW SHORTDUMP cx_sy_zerodivide( ) ).
|
||||||
```
|
```
|
||||||
|
|
||||||
<p align="right"><a href="#top">⬆️ back to top</a></p>
|
<p align="right"><a href="#top">⬆️ back to top</a></p>
|
||||||
@@ -947,11 +1080,34 @@ statements, i. e. it uses the value of only a single variable that is
|
|||||||
checked in the case distinction.
|
checked in the case distinction.
|
||||||
|
|
||||||
``` abap
|
``` abap
|
||||||
DATA(b) = SWITCH #( a
|
"The following example performs a calculation (no error handling implemented)
|
||||||
WHEN 1 THEN w
|
"if a valid operator is passed, and stores the result in a data object of
|
||||||
WHEN 2 THEN x
|
"type string.
|
||||||
WHEN 3 THEN y
|
"Note: Similar to the COND operator, the THROW addition is also possible
|
||||||
ELSE z ).
|
"for the SWITCH operator.
|
||||||
|
DATA(operator) = '*'.
|
||||||
|
DATA(num1) = 5.
|
||||||
|
DATA(num2) = 7.
|
||||||
|
DATA(calc_result) = SWITCH #( operator
|
||||||
|
WHEN '+' THEN |{ num1 + num2 STYLE = SIMPLE }|
|
||||||
|
WHEN '-' THEN |{ num1 - num2 STYLE = SIMPLE }|
|
||||||
|
WHEN '*' THEN |{ num1 * num2 STYLE = SIMPLE }|
|
||||||
|
WHEN '/' THEN |{ CONV decfloat34( num1 / num2 ) STYLE = SIMPLE }|
|
||||||
|
ELSE `Wrong operator.` ).
|
||||||
|
|
||||||
|
"A constructor expression as above instead of, for example, a CASE statement as follows.
|
||||||
|
CASE operator.
|
||||||
|
WHEN '+'.
|
||||||
|
calc_result = |{ num1 + num2 STYLE = SIMPLE }|.
|
||||||
|
WHEN '-'.
|
||||||
|
calc_result = |{ num1 - num2 STYLE = SIMPLE }|.
|
||||||
|
WHEN '*'.
|
||||||
|
calc_result = |{ num1 * num2 STYLE = SIMPLE }|.
|
||||||
|
WHEN '/'.
|
||||||
|
calc_result = |{ CONV decfloat34( num1 / num2 ) STYLE = SIMPLE }|.
|
||||||
|
WHEN OTHERS.
|
||||||
|
calc_result = `Wrong operator.`.
|
||||||
|
ENDCASE.
|
||||||
```
|
```
|
||||||
|
|
||||||
<p align="right"><a href="#top">⬆️ back to top</a></p>
|
<p align="right"><a href="#top">⬆️ back to top</a></p>
|
||||||
|
|||||||
Reference in New Issue
Block a user