Sei sulla pagina 1di 10

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.
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.

Simple Inheritance Report
CREATE OBJ ECT: lr_parent,lr_child.

lr_parent->parent_method( ).
lr_child->parent_method( ).
lr_child->child_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 OBJ ECT: 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 OBJ ECT: 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 l cl _par ent DEFI NI TI ON.

ENDCLASS. " l cl _par ent DEFI NI TI ON


CLASS l cl _chi l d DEFI NI TI ON I NHERI TI NG FROM l cl _par ent .

ENDCLASS. " l cl _chi l d DEFI NI TI ON


CLASS l cl _par ent I MPLEMENTATI ON.

ENDCLASS. " l cl _par ent I MPLEMENTATI ON


CLASS l cl _chi l d I MPLEMENTATI ON.

ENDCLASS. " l cl _chi l d I MPLEMENTATI ON


START- OF- SELECTI ON.

DATA: l r _par ent TYPE REF TO l cl _par ent ,
l r _chi l d TYPE REF TO l cl _chi l d.

CREATE OBJ ECT: l r _par ent , l r _chi l d.

TRY .
* Wi deni ng Cast
l r _chi l d ?= l r _par ent .
WRI TE / ' Wi deni ng Cast Success! ' .
CATCH cx_sy_move_cast _er r or .
WRI TE / ' Wi deni ng Cast Fai l ed! ' .
ENDTRY.

Now we will see the output which we are all waiting for!



disappointed?

The above example was taken from one of the tweets of Uwe Fetzer and is the motivation for writing this blog.



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 OBJ ECT: 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 OBJ ECT 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 OBJ ECT lr_intf TYPE lcl_myclass.
CREATE OBJ ECT 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 OBJ ECT 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 OBJ ECT 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

Potrebbero piacerti anche