Avoiding the Pitfalls of Type Conversions

Objective

After completing this lesson, you will be able to Avoid the pitfalls of type conversions.

Successful Assignments

In ABAP, you are allowed to perform value assignments between variables of different data types. When you do so, ABAP attempts to convert the value of the source field into the type of the target field. Whether the conversion is successful depends on whether the value of the source field is compatible with the data type of the target field.

In the first example here, we are attempting to assign the value of a string to an integer field. Since the value of the string 12345 is a valid integer, the assignment is successful. The second assignment is also successful.

Try It Out - Successful Assignments

  1. Create a new class that implements the interface IF_OO_ADT_CLASSRUN.
  2. Copy the following code into the editor between the METHOD if_oo_adt_classrun~main. and ENDMETHOD. statements:
    Code Snippet
    Copy code
    Switch to dark mode
    1234567891011121314151617181920
    DATA var_string TYPE string. DATA var_int TYPE i. DATA var_date TYPE d. data var_pack type p length 3 decimals 2. var_string = `12345`. var_int = var_string. out->write( 'Conversion successful' ). var_string = `20230101`. var_date = var_string. out->write( |String value: { var_string }| ). out->write( |Date Value: { var_date date = user }| ).
  3. Activate the class by pressing Ctrl + F3.
  4. Play around with the code to familiarize yourself with the topic.

Unsuccessful Assignments

Type conversions in value assignments are not always successful. Sometimes the source value is incompatible with the type of the target field. The two assignments shown here both lead to exceptions which, if left uncaught, lead in turn to runtime errors.

When we try to assign the string value ABCDE to an integer field, the system recognizes that the contents of the string cannot be represented as a number and triggers the exception CX_SY_CONVERSION_NO_NUMBER. In the second example, we try to assign the value 1000 to a packed number with length 3 and 2 decimal places. The variable consequently has 5 digits, of which two are decimal places and hence a maximum value of 999.99. The assignment therefore causes an arithmetic overflow and the system responds with the exception CX_SY_CONVERSION_OVERFLOW .

Truncation and Rounding

Some assignments lead to loss of data or accuracy. If, for example, you assign the value of a character field to a shorter field, the value will be truncated. In the example, we attempted to assign 5 characters to a character field with length 3. In this case, the fourth and fifth characters are lost.

If you assign a value to a numeric field and the number of decimal places in the target field is insufficient, the system will use arithmetic rounding. In the two examples here, one quarter can be represented accurately as 0.25, but one eighth - 0.125 - is rounded up to 0.13.

Try It Out - Truncation and Rounding

  1. Create a new class that implements the interface IF_OO_ADT_CLASSRUN.
  2. Copy the following code into the editor between the METHOD if_oo_adt_classrun~main. and ENDMETHOD. statements:
    Code Snippet
    Copy code
    Switch to dark mode
    1234567891011121314151617181920
    DATA long_char TYPE c LENGTH 10. DATA short_char TYPE c LENGTH 5. DATA result TYPE p LENGTH 3 DECIMALS 2. long_char = 'ABCDEFGHIJ'. short_char = long_char. out->write( long_char ). out->write( short_char ). result = 1 / 8. out->write( |1 / 8 is rounded to { result NUMBER = USER }| ).
  3. Activate the class by pressing Ctrl + F3.
  4. Play around with the code to familiarize yourself with the topic.

Unexpected Results of Assignments

Sometimes the result of an assignment between two different data types can seem unexpected. For example, if you assign a date field to an integer field, the value is the number of days since 01.01.0001. Similarly, if you assign a time field to an integer, the result is the number of seconds since midnight.

If you assign a character field or string to a variable with type N, the system discards any characters that are not digits, arranges the remaining digits right-justified in the field, and fills the remaining spaces with leading zeroes.

A date field is, from a technical point of view, a character field. You can therefore assign values to date fields in ABAP that do not correspond to a valid date (note that this cannot happen when the user enters dates via the UI, as the UI layer validates the date).

Pitfalls of Inline Declarations

When you use inline declarations in arithmetic expressions, the system derives the type of the new variable from the right-hand side of the expression. Since the numeric literals 5 and 10 are integers, the variables result1 and result2 are created as integers as well. While the result of the multiplication is correct, the result of the division is rounded up to 1.

Try It Out - Unexpected Results of Assignments

  1. Create a new class that implements the interface IF_OO_ADT_CLASSRUN.
  2. Copy the following code into the editor between the METHOD if_oo_adt_classrun~main. and ENDMETHOD. statements:
    Code Snippet
    Copy code
    Switch to dark mode
    123456789101112131415161718192021
    DATA var_date TYPE d. DATA var_int TYPE i. DATA var_string TYPE string. DATA var_n TYPE n LENGTH 4. var_date = cl_abap_context_info=>get_system_date( ). var_int = var_date. out->write( |Date as date| ). out->write( var_date ). out->write( |Date assigned to integer| ). out->write( var_int ). var_string = `R2D2`. var_n = var_string. out->write( |String| ). out->write( var_string ). out->write( |String assigned to type N| ). out->write( var_n ).
  3. Activate the class by pressing Ctrl + F3.
  4. Play around with the code to familiarize yourself with the topic.

Conversions of Forced Type

Watch this video to learn how to force type conversions explicitly and implicitly.

Try It Out - Conversions of Forced Type

  1. Create a new class that implements the interface IF_OO_ADT_CLASSRUN.
  2. Copy the following code into the editor between the METHOD if_oo_adt_classrun~main. and ENDMETHOD. statements:
    Code Snippet
    Copy code
    Switch to dark mode
    1234567891011121314151617181920212223
    * result has type C. * and is displayed unformatted in the console DATA(result1) = '20230101'. out->write( result1 ). * result2 is forced to have type D * and is displayed with date formatting in the console DATA(result2) = CONV d( '20230101' ). out->write( result2 ). * The method do_something( ) has an importing parameter of type string. * Attempting to pass var results in a syntax error * The CONV #( ) expression converts var into the expected type * Note that CONV #( ) can lead to conversion exceptions * lcl_class=>do_something( var ).
  3. Activate the class by pressing Ctrl + F3.
  4. Play around with the code to familiarize yourself with the topic.

Prevention of Truncation and Rounding

Watch this video to learn how to prevent truncation and rounding.

Try It Out - Prevention of Truncation and Rounding

  1. Create a new class that implements the interface IF_OO_ADT_CLASSRUN.
  2. Copy the following code into the editor between the METHOD if_oo_adt_classrun~main. and ENDMETHOD. statements:
    Code Snippet
    Copy code
    Switch to dark mode
    12345678910111213141516171819202122232425262728293031323334353637383940414243444546
    DATA var_date TYPE d. DATA var_pack TYPE p LENGTH 3 DECIMALS 2. DATA var_string TYPE string. DATA var_char TYPE c LENGTH 3. var_pack = 1 / 8. out->write( |1/8 = { var_pack NUMBER = USER }| ). TRY. var_pack = EXACT #( 1 / 8 ). CATCH cx_sy_conversion_error. out->write( |1/8 has to be rounded. EXACT triggered an exception| ). ENDTRY. var_string = 'ABCDE'. var_char = var_string. out->write( var_char ). TRY. var_char = EXACT #( var_string ). CATCH cx_sy_conversion_error. out->write( 'String has to be truncated. EXACT triggered an exception' ). ENDTRY. var_date = 'ABCDEFGH'. out->write( var_Date ). TRY. var_date = EXACT #( 'ABCDEFGH' ). CATCH cx_sy_conversion_error. out->write( |ABCDEFGH is not a valid date. EXACT triggered an exception| ). ENDTRY. var_date = '20221232'. out->write( var_date ). TRY. var_date = EXACT #( '20221232' ). CATCH cx_sy_conversion_error. out->write( |2022-12-32 is not a valid date. EXACT triggered an exception| ). ENDTRY.
  3. Activate the class by pressing Ctrl + F3.
  4. Play around with the code to familiarize yourself with the topic.

Avoid Problematic Type Conversions

You have a closer look at the console output of your ABAP class and detect that the carrier name is truncated. You also notice that something is wrong with the carrier ID and the connection ID that are displayed for cargo flights. You identify problematic type conversions as the source of these issues and correct your code accordingly.

Template:

  • /LRN/CL_S4D401_ATS_SQL_TRACE (Global Class)

Solution:

  • /LRN/CL_S4D401_TCS_TYPE_CONV (Global Class)

Task 1: Copy Template (Optional)

Copy the template class. If you finished the previous exercise, you can skip this task and continue editing your class ZCL_##_SOLUTION.

Steps

  1. Copy class /LRN/CL_S4D401_ATS_SQL_TRACE to a class in your own package (suggested name: ZCL_##_SOLUTION, where ## stands for your group number).

    1. In the Project Explorer view, right-click class /LRN/CL_S4D401_ATS_SQL_TRACE to open the context menu.

    2. From the context menu, choose Duplicate ....

    3. Enter the name of your package in the Package field. In the Name field, enter the name ZCL_##_SOLUTION, where ## stands for your group number.

    4. Adjust the description and choose Next.

    5. Confirm the transport request and choose Finish.

  2. Activate the copy.

    1. Press Ctrl + F3 to activate the class.

Task 2: Detect Problematic Type Conversions

Execute the class as console app. Inspect the console output, paying particular attention to the carrier name and the carrier ID and connection ID of cargo flights. Locate the code that prepares this output and trace the data back to the source - looking for potentially problematic type conversions. Use the EXACT expression to verify that there are type conversions with data losses.

Steps

  1. Execute your ABAP class ZCL_##_SOLUTION as console app.

    1. Open the class in the editor and press F9.

  2. Inspect the console output.

    1. Scroll down in the ABAP Console view.

    2. Locate the last line starting with Carrier Name.

    3. Scroll further down to the line starting with Found suitable cargo flight and inspect the next line.

  3. Return to the source code of your ABAP class and analyze the implementation of method if_oo_adt_classrun~main.

  4. Navigate into method get_output.

    1. In method call carrier->get_output( ), place the cursor on the method name get_output and press F3. Alternatively, you can hold down the Ctrl key and choose the method name.

    2. In the expression me->name, place the cursor on name and press F2 to display the code element information for attribute name.

    3. Place the cursor on r_result and press F2 to display the code element information for attribute r_result.

    4. In the code element information, choose tt_output to display the code element info for this type.

    5. Choose t_output to navigate to code element info for the row type of the table type.

  5. Change the row type of parameter r_output. Use a character-like row type of variable length.

    1. From the toolbar at the bottom of the element info, choose Open in Editor. Alternatively, you can press F3 to navigate to the definition of type t_output.

    2. In statement TYPES t_output TYPE c LENGTH 40., replace c_LENGTH 40 with string.

  6. Return to the Global Class tab and navigate into method get_details of class lcl_cargo_flight.

    1. In method call cargo_flight->get_description( ), place the cursor on the method name get_description and press F3. Alternatively, you can hold down the Ctrl key and choose the method name.

  7. Use the Where-used list for attribute carrier_id to find the statement where it is filled.

    1. Place the cursor on carrier_id and choose Get Where-used List from the Eclipse toolbar. Alternatively, you can press Ctrl + Shift + G.

    2. On the Search view below the editor, double-click the row that starts with carrier_id =.

    3. In statement carrier_id = i_carrier_id., place the cursor on i_carrier_id and press F2 to display the code element information for parameter i_carrier_id.

    4. In the code element info, choose /dmo/carrier_id to display the technical type of that data element.

    5. Repeat this to analyze the technical type of attribute carrier_id.

  8. Use conversion expression EXACT to test if the type conversion leads to information loss. Activate the code and execute it as a console app.

    1. In the value assignment, surround the source data object i_carrier_id with EXACT #( ... ) like this:

      Code Snippet
      Copy code
      Switch to dark mode
      123
      carrier_id = EXACT #( i_carrier_id ).
    2. Press Ctrl + F3 to activate the class.

    3. Press F9 to execute the class as a console app.

    4. You should see a runtime error CONVT_NO_NUMBER.

  9. Repeat this analysis for the assignment connection_id = i_connection_id..

    1. Analyze the technical types of attribute connection_id and parameter i_connection_id as in the previous step.

    2. Adjust the code as follows:

      Code Snippet
      Copy code
      Switch to dark mode
      123
      connection_id = EXACT #( i_connection_id ).
    3. Press Ctrl + F3 to activate the class.

    4. Press F9 to execute the class as a console app.

  10. Correct the types of attributes carrier_id and connection_id and remove the redundant EXACT expression. Then activate and re-test your code.

    1. In statement carrier_id = i_carrier_id., place the cursor on carrier_id and press F3 to navigate to the definition of that attribute. Alternatively, you can hold down the Ctrl key and choose the attribute name.

    2. In statement DATA carrier_id TYPE /dmo/connection_id READ-ONLY., replace /dmo/connection_id with /dmo/carrier_id.

    3. In statement DATA connection_id TYPE /dmo/carrier_id READ-ONLY., replace /dmo/carrier_id with /dmo/connection_id.

    4. The declaration of the attributes should then look like this:

      Code Snippet
      Copy code
      Switch to dark mode
      12345678
      * wrong: * DATA carrier_id TYPE /dmo/connection_id READ-ONLY. * DATA connection_id TYPE /dmo/carrier_id READ-ONLY. * correct: DATA carrier_id TYPE /dmo/carrier_id READ-ONLY. DATA connection_id TYPE /dmo/connection_id READ-ONLY.
    5. Fix the syntax warnings Redundant conversion for type ... by removing the previously added EXACT expressions.

    6. Press Ctrl + F3 to activate the class.

    7. Press F9 to execute the class as a console app.

Log in to track your progress & complete quizzes