ABAP Casting: Narrow vs Widening Explained

When we assign the instance of the Subclass back to the instance of the Superclass, than it is called the “Narrow Casting”, because we are switching from a “More Specific view of an object” to “less specific view”.

When we assign the instance of the Superclass to the Subclass, than it is called the Widening Cast, because we are moving to the “More Specific View” from the “Less specific view”.

In ABAP, it is necessary to catch the exception CX_SY_MOVE_CAST_ERROR while doing the widening cast to avoid the short-dump.

What does ‘?=’ mean

This ‘?=’ denotes a widening cast operator. In widening cast we assign reference of superclass to reference of subclass.

Suppose u have a superclass lcl_vehicle

its reference is r_vehicle.

abd you have its subclass lcl_car

with reference r_car.

r_car ?= r_vehicle.

‘?=’ denotes the WIDECASTING Operator in ABAP Object.

For this type of assignment, a check must be carried out at runtime to see whether the class of the instance that the source reference points to also supports the interface that the target reference refers to. If this is the case, the cast is carried out, otherwise the catchable runtime MOVE_CAST_ERROR occurs.

Narrow Casting

REPORT ynarrowcasting.

CLASS a DEFINITION.
  PUBLIC SECTION.
    METHODS: hungry.
ENDCLASS.

CLASS b DEFINITION INHERITING FROM a.
  PUBLIC SECTION.
    METHODS: hungry REDEFINITION,
      fasting.
ENDCLASS.

CLASS a IMPLEMENTATION.
  METHOD hungry.
    WRITE : /'a is hungry'.
  ENDMETHOD.
ENDCLASS.

CLASS b IMPLEMENTATION.
  METHOD hungry.
    WRITE : / 'lion is king of jungle he is hungry'.
  ENDMETHOD.
  METHOD fasting.
    WRITE : /' he is on fst today'.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  DATA : obj_a TYPE REF TO a,
         obj_b TYPE REF TO b.

  WRITE : /'without narrow casting'.
  CREATE OBJECT obj_a.
  CALL METHOD obj_a->hungry( ).
  CLEAR obj_a.

  WRITE : /'with narrow casting'.
  CREATE OBJECT obj_b.
  obj_a = obj_b.
  CALL METHOD obj_a->hungry( ).
*CALL METHOD obj_a->('fasting').

Wide casting

REPORT ywidecasting.

CLASS a DEFINITION.
  PUBLIC SECTION.
    METHODS: hungry.
ENDCLASS.

CLASS b DEFINITION INHERITING FROM a.
  PUBLIC SECTION.
    METHODS: hungry REDEFINITION,
      fasting.
ENDCLASS.

CLASS a IMPLEMENTATION.
  METHOD hungry.
    WRITE : /'a is hungry'.
  ENDMETHOD.
ENDCLASS.

CLASS b IMPLEMENTATION.
  METHOD hungry.
    WRITE : / 'lion is king of jungle he is hungry'.
  ENDMETHOD.
  METHOD fasting.
    WRITE : /' he is on fst today'.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  DATA : obj_a         TYPE REF TO a,
         obj_b         TYPE REF TO b,
         obj_c         TYPE REF TO b,
         lo_cast_error TYPE REF TO cx_sy_move_cast_error.

  WRITE : /'without narrow casting'.
  CREATE OBJECT obj_a.
  CALL METHOD obj_a->hungry( ).
  CLEAR obj_a.
  CREATE OBJECT obj_c.

  WRITE : /'with narrow casting'.
  CREATE OBJECT obj_b.
  obj_a = obj_b.
  CALL METHOD obj_a->hungry( ).
*CALL METHOD obj_a->('fasting').
  CLEAR obj_b.

  WRITE : /' widening cast'. " below is the logic for widening cast
  TRY.
      obj_b ?= obj_a.
    CATCH cx_sy_move_cast_error INTO lo_cast_error.
      WRITE : / 'Failed'.
  ENDTRY.
  IF obj_b IS NOT INITIAL.
    CALL METHOD obj_b->hungry( ).
    CALL METHOD obj_b->fasting( ).
  ENDIF.

Example showing use of casting operator

*&---------------------------------------------------------------------*
*& Report zooabap_3
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zooabap_3.

CLASS lcl_vehicle DEFINITION.
  PUBLIC SECTION.
    METHODS:
      constructor
        IMPORTING
          iv_name        TYPE string
          iv_vehicletype TYPE string,
      display_attributes.
    CLASS-METHODS:
      display_vehicle_num.
  PRIVATE SECTION.
    DATA:
      mv_name        TYPE string,
      mv_vehicletype TYPE string.
    CLASS-DATA:
    no_of_vehicles TYPE i.
ENDCLASS.

CLASS lcl_vehicle IMPLEMENTATION.
  METHOD constructor.
    mv_name = iv_name.
    mv_vehicletype = iv_vehicletype.
    no_of_vehicles = no_of_vehicles + 1.
  ENDMETHOD.

  METHOD display_attributes.
    WRITE: / ‘name of car’, mv_name,
    / ‘type of car’, mv_vehicletype.
  ENDMETHOD.
  METHOD display_vehicle_num.
    WRITE: / ‘number of car:’, no_of_vehicles .
  ENDMETHOD.
ENDCLASS.

CLASS lcl_car DEFINITION INHERITING FROM lcl_vehicle.
  PUBLIC SECTION.
    METHODS:
      constructor
        IMPORTING
          iv_name        TYPE string
          iv_vehicletype TYPE string
          iv_seats       TYPE i,
      display_attributes REDEFINITION.
  PRIVATE SECTION.
    DATA:
    mv_seats TYPE i.
ENDCLASS.

CLASS lcl_car IMPLEMENTATION.
  METHOD constructor.
    super->constructor( iv_name = iv_name iv_vehicletype = iv_vehicletype ).
    mv_seats = iv_seats.
  ENDMETHOD.
  METHOD display_attributes.
    super->display_attributes( ).
    WRITE: / ‘Max persons:’, mv_seats.
  ENDMETHOD.
ENDCLASS.

CLASS lcl_bike DEFINITION INHERITING FROM lcl_vehicle.
  PUBLIC SECTION.
    METHODS:
      constructor
        IMPORTING
          iv_name        TYPE string
          iv_vehicletype TYPE string
          iv_seats       TYPE i,
      display_attributes REDEFINITION.
  PRIVATE SECTION.
    DATA:
    mv_seats TYPE string.
ENDCLASS.

CLASS lcl_bike IMPLEMENTATION.

  METHOD constructor.

    super->constructor( iv_name = iv_name iv_vehicletype = iv_vehicletype ).
    mv_seats = iv_seats.
  ENDMETHOD.

  METHOD display_attributes.
    super->display_attributes( ).
    WRITE: / 'Max seats:', mv_seats.
  ENDMETHOD.

ENDCLASS.

START-OF-SELECTION.
  DATA:
  go_vehicle TYPE REF TO lcl_vehicle,
  go_car TYPE REF TO lcl_car, ” sub-class obj
  go_bike TYPE ref TO lcl_bike,
  gt_vehicle TYPE TABLE OF REF TO lcl_vehicle,
  gv_count TYPE i.

  ” car object
  create object go_car
  exporting
  iv_name = ‘Maruti’
  iv_vehicletype = ‘800’
  iv_seats = 4.
  go_car->display_attributes( ).

  “bike object
  go_bike = new #( iv_name = ‘Bajaj’ iv_vehicletype = ‘Cruiser’ iv_seats = 2 ).
  go_bike->display_attributes( ).
  APPEND go_bike TO gt_vehicle.
  “car object
  go_car = new #( iv_name = ‘Honda’ iv_vehicletype = ‘Sedan’ iv_seats = 5 ).
  go_car->display_attributes( ).
  APPEND go_car TO gt_vehicle.

  LOOP AT gt_vehicle INTO go_vehicle.

    TRY.
        go_bike ?= go_vehicle.
        gv_count = gv_count + 1.
      CATCH cx_sy_move_cast_error.
    ENDTRY.

  ENDLOOP.

  lcl_vehicle=>display_vehicle_num( ).
  WRITE: / ‘Vehicle Count: ‘, gv_count.

Leave a comment