CAST, CONV and EXACT — changing what the compiler thinks it has¶
Level: 201 · working knowledge
One line: CAST changes the static type of a reference and checks the claim at runtime, CONV converts a value to a type ABAP would not convert to on its own, and EXACT performs the same conversion but raises instead of quietly losing information.
CAST — down the hierarchy, with a runtime check¶
DATA(lo_shape) = CAST lif_shape( NEW lcl_square( 3 ) ). " up: always fine
DATA(lo_square) = CAST lcl_square( lo_shape ). " down: checked
Going up — treating a square as a shape — needs no check, because it is true by construction. Going down is a claim about what the object really is, and when the claim is false the result is CX_SY_MOVE_CAST_ERROR, not a compile error. Catch it, or make the claim safe with IS INSTANCE OF:
A hierarchy where downcasts are common is usually a hierarchy whose interface is missing a method. The cast is the symptom.
CONV — converting a value¶
ABAP converts between many types implicitly on assignment, but a parameter is not an assignment: a method expecting string will not take a c field on its own. CONV performs the conversion where the compiler will not.
It also changes what an expression means. CONV decfloat34( lv_i ) / 2 is a decimal division; lv_i / 2 is an integer one. See DATA for how easily that happens by accident.
Converting c to string is worth its own note: trailing blanks are removed. A c LENGTH 10 holding 'ABAP' is ten characters long; the same value converted to a string is four. That single rule accounts for a large share of "the length changed and I did not touch it" bugs. How long is a string? is the recorded-run page next door.
EXACT — refusing to lose information¶
DATA(lv_ok) = EXACT i( '42' ). " fine
DATA(lv_lossy) = EXACT i( '42.7' ). " raises CX_SY_CONVERSION_ERROR
Ordinary conversion would round 42.7 to 43 and say nothing. EXACT raises instead. For a length check it does the same job — a value that does not fit the target is an exception rather than a truncation. It is the right default anywhere the data came from outside: a file, an interface, a user.
REF¶
REF #( lv_x ) takes a reference to an existing variable — the expression form of GET REFERENCE OF. It appears mostly when passing something to a parameter typed REF TO data, and it does not copy: change the original and the reference sees it.
z_kw_cast_conv.prog.abap — pasted here by tools/check_examples.py. Syntax-checked, never run: abaplint parses and type-checks it against the release in abaplint.json, but no system has produced output for it, so this page shows none.
REPORT z_kw_cast_conv.
INTERFACE lif_shape.
METHODS area RETURNING VALUE(rv_area) TYPE i.
ENDINTERFACE.
CLASS lcl_square DEFINITION.
PUBLIC SECTION.
INTERFACES lif_shape.
METHODS constructor IMPORTING iv_side TYPE i.
METHODS side RETURNING VALUE(rv_side) TYPE i.
PRIVATE SECTION.
DATA mv_side TYPE i.
ENDCLASS.
CLASS lcl_square IMPLEMENTATION.
METHOD constructor.
mv_side = iv_side.
ENDMETHOD.
METHOD side.
rv_side = mv_side.
ENDMETHOD.
METHOD lif_shape~area.
rv_area = mv_side * mv_side.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
" Up the hierarchy is free: a square is a shape.
DATA(lo_shape) = CAST lif_shape( NEW lcl_square( 3 ) ).
WRITE: / 'area', lo_shape->area( ).
" Down it is a claim, and CAST checks it at runtime.
TRY.
DATA(lo_square) = CAST lcl_square( lo_shape ).
WRITE: / 'side', lo_square->side( ).
CATCH cx_sy_move_cast_error.
WRITE: / 'that object was not a square'.
ENDTRY.
" CONV converts a VALUE where ABAP would not convert on its own.
DATA lv_chars TYPE c LENGTH 10 VALUE 'ABAP'.
WRITE: / 'c len ', strlen( lv_chars ).
WRITE: / 'string len', strlen( CONV string( lv_chars ) ).
" EXACT refuses a conversion that would lose something, instead of rounding.
TRY.
DATA(lv_ok) = EXACT i( '42' ).
WRITE: / 'exact', lv_ok.
DATA(lv_lossy) = EXACT i( '42.7' ).
WRITE: / 'never reached', lv_lossy.
CATCH cx_sy_conversion_error.
WRITE: / '42.7 does not fit in an integer without losing something'.
ENDTRY.
If you are coming from another language¶
- Java.
(Square) shapeisCAST,ClassCastExceptionisCX_SY_MOVE_CAST_ERROR, andinstanceofisIS INSTANCE OF. The mapping is almost exact. - Rust.
CONVisinto()/as, andEXACTistry_into()— the version that returns an error instead of wrapping or rounding. Rust makes the fallible one the default; ABAP makes the silent one the default. - Python.
int("42")raises on"42.7", so Python's built-in conversion behaves likeEXACTrather than likeCONV.
See also¶
NEW— where the reference being cast usually comes fromDATA— andDATA( )— the inferred type thatCONVis often fixing- How long is a string? —
c,stringand what counts as a character - Numbers and currency — which numeric conversions lose what
CASE TYPE OF— branching on an object's class, and when not to- Conversion and comparison rules — what happens between two types