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.
nice one!
i am was looking for a blog on static and dynamic types.also tried sap documentation but got nothing.everything is still blurred.
what is dont get is. in narrow casting is.
see code and comments.
sorry for posting this entire code ,makes your blog messy.
Like I say in the blog the Reference type of o_super is Vehicle so you can only call methods of Vehicle through it. The reference is the API, and Vehicle doesn't have the method (the object does, but not the reference) so you get syntax error.
On the other hand when you call o_super->('m4') you are accessing a method that exists in the Vehicle class, the ->( ) operator. Since the object itself does have the method m4, the call works.
The reference type is all about the syntax, what attributes and methods are available to the programmer. The ->( ) is available but shouldn't be used unless in very specific situations because it obfuscates your code, and can easily lead to runtime errors.
It is very easy to explain this if you think along the line of static & dynamic types. When the compiler compiles the code (read: statically), it finds that M4( ) is not defined for the static type (o_super). Thus, it raises a syntax error.
When you use dynamic token to call the method o_super->('M4'), the compiler doesn't check the existence of the method and leaves it to the ABAP Runtime Environment(RTE) to handle it. Therefore you do not get a syntax error, but may/may not get an RT error depending on your case.
In layman's terms -
Where is the difficulty in understanding this?
- Suhas
OK I am getting this.may be
Suppose I have created a static type variable
Data oref type ref to zcl_fruit.
The above one variable is of static type or object type(joao terms).
How can I convert it into dynamic type....or if I am understanding this right
After casting whether narrow or wide casting... It becomes of dynamic type.
As soon as we assign another instance or another static variable to this.it becomes of dynamic type.
Please correct me if I still misunderstood the concept.
You don't convert it, they are separated things (static and dynamic). That's the problem with using "dynamic type" to label something that never changes, the object type (instance in memory).
I didn't use the term "static type" I used "reference type" and "object type", because the type is attached to a real thing:
OrefApple = new ZCl_APPLE( ).
The left side is the reference, the right side is the object. We assign the object to a reference during the instanciation so we can access it, but the object type will never change, it will always be ZCL_APPLE.
When we do:
Oref ?= OrefApple
We are only changing the type of the reference (the static type according to SAP). Not the object, because the type of the object never changes (the so called dynamic type, that never changes .... worse name ever).
Hello Joao,
I am sure by "reference" & "object" types you mean "dynamic" & "static" type respectively. The whole point of "casting" becomes clear if the developer understands this very important rule -
I don't think of this in the complex way like pointer to the memory et al. I know what my static & dynamic types are and then decide whether i'll be needing the casting operator (?=).
I not sure if the same applies to other programming languages viz., Java, C# etc. But the concept of "static" & "dynamic" types works just fine for ABAP 😎
You can even extend this logic to data reference variables.
BR,
Suhas
PS -Tbh I always forget which is "narrowing" & which is "widening" cast.
The problem is that those (SAP specifc) terms are even more abstract. Dynamic and static in relation to what? I think it is much easier to understand if we use less abstract terms.
The "complex way" as you call it, is understanding what is happening in the background instead of memorizing what 2 terms mean. It's how you learn it in C++, and how you are able to shift easily from ABAP to Java (for example) that uses completely different terminology (always understand the concept instead of memorizing the semantics).
The terms "static" and "dynamic" type aren't used outside SAP in this context, as far as I know.
I am a Mechanical engineer who ended up being a ABAP programmer. So i did not have any C# or Java programming during my engineering.
Actually these are the "terms" which are used by Horst Keller in his book on ABAP Objects. And IMO these terms are just synonyms of what you call the "reference" and "object" types. The underlying concept is the same, it is just his way of explaining the concept.
There is no relation between the two. Because they are totally different.
Reference variables have no type. The are pointers which "point" to the relevant object/data references during runtime. The "ABAP" concept (if you may call it so),says & i quote (ABAP Keyword Documentation) -
The static type doesn't point to anything, it is just an indicator which does the following -
I don't quite see how the "ABAP" concept is different from the concept you have explained, except for the terminology.
The problem is that:
Of course not, and I never said it did. The reference does.
Regardless, what I said stands. Learning the "why" is much better then memorizing terms, that are very specific one programming language.
Maybe you did not understand my point. What i am trying to say is that the concept of casting (or assigning reference variables) is the same, just the terms are different.
It is ambiguous/misleading to you because you have learnt it in a different way (object/reference types). But for me it is not because i learnt it the ABAP (or Horst Keller's) way 😛
Let me confess that i had difficulties to understand the concept initially. But after debugging the RTTS & SALV classes, reading the OO gurus' content on SCN; i finally figured out what those terms really meant.
I think each of us entitled to his/her way of understanding, so let the community decide which one to choose.
Can you please tell me how the "why" is different? Maybe i am too short sighted to see it.
BR,
Suhas
Nothing is misleading after you know exactly what it is. You said it yourself, that you had difficulty understanding the concepts, and you had to debug. That shows the terms are confusing.
Yes I agree, yet you started this discussion by saying "I am sure by "reference" & "object" types you mean "dynamic" & "static" type respectively.", like I was saying something wrong.
No, that shows that i did not have any prior OO knowledge & that my brain has slow processing power.
No. I wanted to ask if i understood the terms correctly, because they were new to me. That's why i even asked if the "static", "dynamic" terms were ABAP-specific.
It was never my intention to correct you. I was just supplementing what you had mentioned.
Hi Joao,
nice and useful blog for many, I am sure. I have just few comments:
lo_mango = new_zcl_mango( ).
lo_fruit = lo_mango.
append lo_fruit to lt_fruit.
Since it's an UpCast, then use "=" instead of "?=" even though using "?=" is technically and syntactically possible. However, it's confusing the reader here.
The object type is intrinsic to the class of which the constructor (new ZCL_MANGO) used to bring it to "life".
instead of
The object type is intrinsic to the type of the constructor (new ZCL_MANGO) used to bring it to "life".
as the constructor has no type... And it's also a factory method here, not a constructor (but this is another story) and this we all understand.
and dynamic, I recommend the readers to simply check the following program in the debugger (definitions and implementations of superclass lcl_fruit and its subclasses lcl_apple and lcl_mango are omitted here to keep it short):
DATA:
lt_fruit TYPE TABLE OF REF TO lcl_fruit,
lo_fruit TYPE REF TO lcl_fruit,
lo_apple TYPE REF TO lcl_apple,
lo_mango TYPE REF TO lcl_mango.
START-OF-SELECTION.
CREATE OBJECT lo_apple.
lo_fruit = lo_apple.
APPEND lo_fruit TO lt_fruit.
CREATE OBJECT lo_mango.
lo_fruit = lo_mango.
APPEND lo_fruit TO lt_fruit.
LOOP AT lt_fruit INTO lo_fruit. "<-- check lo_fruit in debugger in detail
TRY.
lo_apple ?= lo_fruit.
lo_apple->write_fruit_name( ).
CATCH cx_sy_move_cast_error.
lo_mango ?= lo_fruit.
lo_mango->write_fruit_name( ).
ENDTRY.
ENDLOOP.
Static type of lo_fruit is ref to lcl_fruit, but its dynamic type (which is determined in runtime) is either ref to lcl_apple or ref to lcl_mango depending on which record is actually being processed. In the debugger, the dynamic type is displayed as:
{O:3*\PROGRAM=ZCAST\CLASS=LCL_APPLE}
or
{O:4*\PROGRAM=ZCAST\CLASS=LCL_MANGO}
The dynamic type is always more specific than or the same as the static type.
is the key here. That one also explains why the Uwe Fetzer's example in the referred blog http://scn.sap.com/community/abap/blog/2013/09/09/understanding-widening-cast-in-abap-objects did not work.
BR, Michal
Hello,
I left 1 as it is, since I think it brings forward the fact that the two reference types aren't the same. Corrected nº2.
Thanks
Hi Joao,
as the blog is on inheritance topic where the subclass-superclass relation is the core and the direction of the assignment is the main thing, then I don't agree, sorry. I think that using the assignment operators as strictly as they should be would help very much the readers for better understanding of the difference:
lo_superclass = lo_subclass. "UpCast
lo_subclass ?= lo_superclass. "DownCast
This is commonly used convention. Using the ?= operator in both cases makes the difference less visible. If the developer is not sure why exactly is he/she using each of those different operators in specific case, then it could lead to less readable code and future errors.
BR, Michal
Note that SAP says in BC401 that Narrowcasting is the same as Downcasting and that this involves the assignment of a SUPERclass to a SUBclass. e.g. lr_truck ?= lr_vehicle.