Understanding Widening Cast in ABAP Objects
There are many discussions about Widening cast in SCN. some say, it is Up casting while other say it is Down casting. I remember in a way as depicted below and still following the same.
Let’s take a simple inheritance tree.
Narrowing Cast:
Assigning/copying the instance of sub class to super class instance is called Narrowing Cast.
As shown in the figure, assigning sub class to super class is going up wards. From sub class(es) to super class while moving Up the path becomes narrow as shown in the left image. So I simply remember this. Narrowing cast = Up cast 🙂 .
Widening Cast:
Assigning/coping the instance of super class to the sub class instance is called Widening Cast.
This is the reverse of Narrowing cast. As shown in the figure, assigning super class to sub class is going down wards. From super class to sub class while moving Down the path becomes wider as shown in the left image. So I simply remember this – Widening cast = Down cast.
I will still remember the above inheritance tree while referring casting and refer Widening cast as Down casting ( though is is referred as up casting from release 7.0).
Coming to the topic, I use Widening cast in this blog (instead of up/down casting ) .
To understand the Widening cast, I will just explain with the simple program.
Simple Inheritance Report |
---|
REPORT zkk_widening_cast_demo.
CLASS lcl_parent DEFINITION. ENDCLASS. “lcl_parent DEFINITION CLASS lcl_child DEFINITION INHERITING FROM lcl_parent. ENDCLASS. “lcl_child DEFINITION CLASS lcl_parent IMPLEMENTATION. METHOD parent_method. CLASS lcl_child IMPLEMENTATION. METHOD parent_method. ENDCLASS. “lcl_child IMPLEMENTATION START-OF-SELECTION. DATA: lr_parent TYPE REF TO lcl_parent, CREATE OBJECT: lr_parent,lr_child. lr_parent->parent_method( ). |
Now after executing this I got the below output:
Now I am interested in child(sub) class method in my parent(super) class. Which mean when I call the ‘parent_method’ of parent class in the above report then it should call the ‘parent_method’ of child class( Redefined method call instead of original method call). So I do a Narrowing cast.
continuing the above report.
CREATE OBJECT: lr_parent,lr_child.
WRITE / 'Before Narrowing Cast:'.
lr_parent->parent_method( ).
lr_child->parent_method( ).
lr_child->child_method( ).
* Narrowing cast
lr_parent = lr_child.
WRITE / 'After Narrowing Cast:'.
lr_parent->parent_method( ).
lr_child->parent_method( ).
lr_child->child_method( ).
Now when I execute the above report, I get the below output, which is as expected.
Now I am interested in parent(super) class method in my child(sub) class. Which mean when I call the ‘parent_method’ of child class in the above report then it should call the ‘parent_method’ of super class( Super class method call instead of redefined sub class method call). So I do a Widening cast.
CREATE OBJECT: lr_parent,lr_child.
WRITE / 'Before Widening Cast:'.
lr_parent->parent_method( ).
lr_child->parent_method( ).
lr_child->child_method( ).
TRY .
* Widening Cast
lr_child ?= lr_parent.
WRITE / 'After Widening Cast:'.
lr_parent->parent_method( ).
lr_child->parent_method( ).
lr_child->child_method( ).
CATCH cx_sy_move_cast_error.
WRITE / 'Widening Cast Failed!'.
ENDTRY.
The output is as below:
After seeing the above output, we remember that ” It is always not possible to do Widening cast as the sub class will have more functionality compared to super class” .
So, I removed the method definition ‘child_method’ in the child class and tried Widening cast. I got the same output!
I created an empty class definitions and tried widening cast to see the widening cast success message 😛 .
CLASS lcl_parent DEFINITION.
ENDCLASS. "lcl_parent DEFINITION
CLASS lcl_child DEFINITION INHERITING FROM lcl_parent.
ENDCLASS. "lcl_child DEFINITION
CLASS lcl_parent IMPLEMENTATION.
ENDCLASS. "lcl_parent IMPLEMENTATION
CLASS lcl_child IMPLEMENTATION.
ENDCLASS. "lcl_child IMPLEMENTATION
START-OF-SELECTION.
DATA: lr_parent TYPE REF TO lcl_parent,
lr_child TYPE REF TO lcl_child.
CREATE OBJECT: lr_parent,lr_child.
TRY .
* Widening Cast
lr_child ?= lr_parent.
WRITE / 'Widening Cast Success!'.
CATCH cx_sy_move_cast_error.
WRITE / 'Widening Cast Failed!'.
ENDTRY.
Now we will see the output which we are all waiting for!
The Widening cast will always fail unless the assigning instance has the same type of instance to which we are assigning.
So people used to tell do Narrowing cast before Widening Cast!, to have the assigning instance same reference.
I will take the main report and do a narrowing cast before widening cast.
REPORT zkk_widening_cast_demo.
CLASS lcl_parent DEFINITION.
PUBLIC SECTION.
METHODS parent_method.
ENDCLASS. "lcl_parent DEFINITION
CLASS lcl_child DEFINITION INHERITING FROM lcl_parent.
PUBLIC SECTION.
METHODS parent_method REDEFINITION.
METHODS child_method.
ENDCLASS. "lcl_child DEFINITION
CLASS lcl_parent IMPLEMENTATION.
METHOD parent_method.
WRITE / 'Called -> parent method in Parent Class!'.
ENDMETHOD. "parent_method
ENDCLASS. "lcl_parent IMPLEMENTATION
CLASS lcl_child IMPLEMENTATION.
METHOD parent_method.
WRITE / 'Called -> parent redifinition method in Child Class!'.
ENDMETHOD. "parent_method
METHOD child_method.
WRITE / 'Called -> child method in Child Class!'.
ENDMETHOD. "child_method
ENDCLASS. "lcl_child IMPLEMENTATION
START-OF-SELECTION.
DATA: lr_parent TYPE REF TO lcl_parent,
lr_child TYPE REF TO lcl_child.
CREATE OBJECT: lr_parent,lr_child.
WRITE / 'Before Widening Cast:'.
lr_parent->parent_method( ).
lr_child->parent_method( ).
lr_child->child_method( ).
lr_parent = lr_child. " Narrowing cast
TRY .
* Widening Cast
lr_child ?= lr_parent.
WRITE / 'After Widening Cast:'.
lr_parent->parent_method( ).
lr_child->parent_method( ).
lr_child->child_method( ).
CATCH cx_sy_move_cast_error.
WRITE / 'Widening Cast Failed!'.
ENDTRY.
Now lr_parent has same type of lr_child as we did Narrowing cast. We will see the output:
Wow! widening cast is successful this time. But we can see that this output is same as the output of Narrowing cast shown above (which is not what we required).
Because, we have copied the lr_child instance to lr_parent ( lr_parent = lr_child ” Narrow cast) before widening cast. Now lr_parent has same type of lr_child and we assign lr_child ?= lr_parent which is noting but copying child class instance to child class instance!
So, when this Widening cast is actually useful?
To explain this, I will take a simple example using interfaces:
REPORT zkk_widening_cast_demo.
INTERFACE lif_test.
METHODS interface_method.
ENDINTERFACE. "lif_test
CLASS lcl_myclass DEFINITION.
PUBLIC SECTION.
INTERFACES lif_test.
ENDCLASS. "lcl_class1 DEFINITION
CLASS lcl_myclass IMPLEMENTATION.
METHOD lif_test~interface_method.
WRITE / 'Interface method call in My Class'.
ENDMETHOD. "lif_test~interface_method
ENDCLASS. "lcl_class1 IMPLEMENTATION
START-OF-SELECTION.
DATA: lr_intf TYPE REF TO lif_test,
lr_mine TYPE REF TO lcl_myclass.
CREATE OBJECT lr_intf TYPE lcl_myclass.
TRY .
* Widening Cast
lr_mine ?= lr_intf.
WRITE /'Widening Cast Successful!'.
CATCH cx_sy_move_cast_error.
WRITE / 'Widening Cast Failed!'.
ENDTRY.
Output:
Since we cannot directly assign the interface reference to class reference,
As using, lr_mine = lr_intf ” will give syntax error because lr_intf is not the same type of lr_mine.
So we do a Widening cast, lr_mine ?= lr_intf , which won’t give syntax check and at run time if lr_intf contains the same reference of lr_mine, the reference will be copied else the exception will be thrown.
Now lets take one more class to understand better.
REPORT zkk_widening_cast_demo.
INTERFACE lif_test.
METHODS interface_method.
ENDINTERFACE. "lif_test
CLASS lcl_myclass DEFINITION.
PUBLIC SECTION.
INTERFACES lif_test.
ENDCLASS. "lcl_class1 DEFINITION
CLASS lcl_yourclass DEFINITION.
PUBLIC SECTION.
INTERFACES lif_test.
ENDCLASS. "lcl_class2 DEFINITION
CLASS lcl_myclass IMPLEMENTATION.
METHOD lif_test~interface_method.
WRITE / 'Interface method call in My Class'.
ENDMETHOD. "lif_test~interface_method
ENDCLASS. "lcl_class1 IMPLEMENTATION
CLASS lcl_yourclass IMPLEMENTATION.
METHOD lif_test~interface_method.
WRITE / 'Interface method call in Your class'.
ENDMETHOD. "lif_test~interface_method
ENDCLASS. "lcl_class2 IMPLEMENTATION
START-OF-SELECTION.
DATA: lr_intf TYPE REF TO lif_test,
lr_mine TYPE REF TO lcl_myclass,
lr_your TYPE REF TO lcl_yourclass.
* CREATE OBJECT lr_intf TYPE lcl_myclass.
CREATE OBJECT lr_intf TYPE lcl_yourclass.
TRY .
* Widening Cast
lr_mine ?= lr_intf.
WRITE /'Widening Cast Successful!'.
CATCH cx_sy_move_cast_error.
WRITE / 'Widening Cast Failed!'.
ENDTRY.
In this case the widening cast will be failed since lr_intf is not of same type as lr_mine.
We use widening cast mainly while dealing with interfaces and in case of dynamic programming.
Now, If we look at the below statement
CREATE OBJECT lr_intf TYPE lcl_yourclass.
TRY .
* Widening Cast
lr_mine ?= lr_intf.
WRITE /'Widening Cast Successful!'.
CATCH cx_sy_move_cast_error.
WRITE / 'Widening Cast Failed!'.
ENDTRY.
is nothing but Narrowing cast before widening cast,
DATA lr_mine1 TYPE REF TO lcl_myclass.
CREATE OBJECT lr_mine1.
lr_intf = lr_mine1. " Narrowing Cast
TRY .
* Widening Cast
lr_mine ?= lr_intf.
WRITE /'Widening Cast Successful!'.
CATCH cx_sy_move_cast_error.
WRITE / 'Widening Cast Failed!'.
ENDTRY.
So in this context, “Do Narrowing cast before Widening cast” makes sense without confusion!
Hope I tried to explain Widening cast to some extent!. Comments are welcome 🙂
Hello Kiran,
I find a few points missing/wrongly stated in the blog -
If i rephrase your statement it'll look something like this -
BR,
Suhas
Hi Suhas,
Thanks for the correction. Yes, It's same/more specific (dynamic) type
And I think I have mentioned about compiler instruction..
may be not in more detail!. Thanks for mentioning about it 🙂
Regards,
Kiran
Hi Kiran,
Nice explanation. It refreshed the concepts in my mind. Would be good if you can give a real world example where narrow and wide casting are used.
BR,
Shankar..
Hi Kiran,
Very nice explanation.got more clarity.
regards,
Vasu
Hi
nice blog 🙂
Nice blog! 🙂
Well Explained.
Regards,
Anoop
Hello Kiran,
Its a great blog and a refreshing read.
There is one thing that I wanted to say.
The diagrams that you are using to refer casting is a bit misleading:
The explanation that you made for the diagram makes sense only if you thing in terms of program lines.
e.g: Narrowing Cast: lo_parent ?= lo_child..
The flow of content in this statement is accordance with the diagram. (i.e. It goes from down to up).
But what happens actually is, The Parent object sits in the shoes of The Child object.
i.e. The specificity of the object is increased. The object refernce is now more specific (Audi) from being generic(Car). That is why it's called a Narrowing cast.
When the object is Wide casted, its meaning becomes more generic (more wide).
Just my 2 cents...
hi kiran ....
gud info
This was the best example one could find for narrow and wide casting. Just amazing. You have explained it in detail with all the screen shots. Great job man. 🙂
Hi! No, you are not correct and article not correct lo_child ?= lo_parent - it is Down Cast(Narrowing Cast) (see course BC401. page 150),
and Yuvaraj S wrote right.
Well explained.. Very nice document. Thanks for sharing!
regards,
Sachin
I think this blog is a bit too long, and not to the point.
For one, I don't like term widening cast as it is a bit misleading, since you are not actually widening something, you are regaining access to what is already there. You are widening the reference type, not the object itself.
This phrase is again a bit misleading because you are not copying "from a subclass to a super class". You are assigning an instance to a different reference type, the object doesn't change.
The conclusion is simple: The reference must of the exact same type, or a parent, of the object's type.
EDIT: As I think this is very important, I wrote Object Casting - Reference type vs Object Type
Hi ,
i am bit confused ,because in your post you explained like Narrowing cast = Up cast and
Widening cast = Down cast. But,in sap keyword Documentation .this description is given like
Up Cast
If the static type of the target variable is less specific or the same as the static type of the source variable, assignment is always possible. The name up cast arises from the fact that you are moving upwards within the inheritance space. As the target variable can accept more dynamic types in comparison to the source variable, this assignment is also know as a widening cast. An up cast is possible in all ABAP statements in which the content of a data object is assigned to another data object. This includes, for example, assignments with the normal assignment operator (=), the insertion of rows in internal tables, or passes from actual to formal parameters.
Down Cast
If the static type of the target variable is more specific than the static type of the source variable, you must check at runtime before the assignment is executed, whether it is less specific or the same as the dynamic type of the source variable. The name down cast arises from the fact that you are moving downwards in the inheritance space. Because the target variable can accept fewer dynamic types in comparison to the source variable, this assignment is also known as a narrowing cast. A down cast is only possible using the special assignment operator ?= (casting operator) or the statement MOVE ... ?TO .... If this prerequisite is not met, a handleable exception is raised.
FYI.
http://help.sap.com/abapdocu_702/en/abenconversion_references.htm
please clarify.
Regards,
Krishna,
Hi,
Yes, It's Up casting. It was already mentioned in the blog. Please check again!
( You may also check the first line of the blog if you haven't read it)
For understanding purpose(or to remember) I used the old terms. The names/terms (Up/down) was vice-versed/interchanged from release version 7 or higher!
The SAP Help links for release 6.40 is not available. If you see in the F1 help for ?= operator in 6.40 version you can see the old term. You may check this discussion for reference: Change Narrowing and Widening Cast
I hope you understood the concept of casting and for the Naming/terms I advise to follow according to your course material or the latest help doc.
Regards,
Kiran
Hello Kiran,
Nice document, Well explained, newbies like me can easily understand! got more clarity.
Thanks,
KK
Note that SAP in BC401 says 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.
acording to the SAP taw12 part one down-cast = narrowing-cast and up-cast = widening cast.... 😛
Looked many discussions. This is very informative, Nice Blog, Thanks for sharing. 🙂
Cheers,
Alfred