Object Casting – Reference type vs Object Type
I’m writing this blog after reading Understanding Widening Cast in ABAP Objects since it became clear to me that the difference between reference types and object type is not clear for many SCN users who are not used to Object Oriented Programming. Knowing the difference between the two is critical to understanding what you can do with casting and how powerful the concept of inheritance is.
I’ll start by giving an example of why narrowing cast is so important. Imagine the following scenario, where the specific fruits are children of the super class Fruit:
You want to create a table of fruit, then loop at it, and write the name of the fruit to the screen. The required data should can be declared as:
DATA: lt_fruits TYPE TABLE OF REF TO ZCL_FRUIT, lo_fruit TYPE REF TO ZCL_FRUIT, lo_mango TYPE REF TO ZCL_MANGO, lo_apple TYPE REF TO ZCL_APPLE, lo_orange TYPE REF TO ZCL_ORANGE.
And then you do something like:
lo_mango = new ZCL_MANGO( ). lo_fruit ?= lo_mango. append lo_fruit to lt_fruit.
This is where the difference between reference type and object type becomes critical.
- The object type is intrinsic to the class of the constructor (new ZCL_MANGO) used to bring it to “life”. Think of the object as memory space that contains information, whose type never changes after it is instantiated.
- The reference type is the type of the pointer (in this case lo_mango and lo_fruit) to the memory space. It’s your gateway, your “API”, only through them can you access the memory (the intrinsic object, whose type was determined by the constructor).
When I make a cast from lo_mango to lo_fruit, the object itself and therefore its type remains the same. Same variables, same type, nothing changes except the type of the pointer, the reference. As long as we use a reference of the super class type we only have access in the code to the attributes and methods of the superclass, but that doesn’t mean the attributes of the original object were lost. They are still there waiting!
This dichotomy is very important, because it allows us to keep similar objects together, in the same table for example, while keeping their intrinsic properties intact. For example lets assume that for the very specific case of the Apple we want to output the apple’s type besides the name of the fruit, the code would be something like:
Loop at lt_fruit into lo_fruit. write lo_fruit->get_name( ). if cl_abap_classdescr=>get_class_name( lo_fruit ) = 'ZCL_APPLE'. lo_apple ?= lo_fruit. write lo_apple->get_type_of_apple( ). endif. Endloop.
It should be become even clearer by the usage of cl_abap_classdescr=>get_class_name( lo_fruit ) and the fact that it returns ZCL_APPLE (instead of ZCL_FRUIT), that indeed the object retains all the attributes that were given to him by the constructor, even if the reference is of the super class type.
Now imagine a scenario where casting didn’t exist, and the code you would need. You would need 3 tables, 3 loops. Now expand this to a real program, inheritance allow much more elegant coding.