If you’ve read my previous blogs, you’ll know that I really like working with ABAP Objects. But still there are a few things that are simply missing – for example a decent inheritance / type checking. Perhaps some of the people who are responsible for the language itself are listening in and might want to comment or even add this item to their agenda…
What I would really like to see is an extension to logical expressions that allow me to check whether a certain instance is a subclass of another class or implements a certain interface. For example:
IF lr_foo IS INSTANCE OF cl_bar. IF lr_foo IS INSTANCE OF if_barable.
I’d also suggest that a dynamic variant might be helpful:
l_classname = 'CL_BAR'. " ...however this might be determined IF lr_foo IS INSTANCE OF (l_classname).
I agree to the widespread notion that it’s usually not a good idea to rely on a certain inheritance structure when designing applications and coding generic stuff. Walking an object tree that was passed using generic references and casting stuff around might lead to very fragile applications – what if I relied on some internal class of the framework and that class changes or disappears altogether? Therefore the first example (IS INSTANCE OF some_class) is probably not the cleanest approach to object-orientation – but sometimes, a programmer’s got to do what a programmer’s got to do.
On the other hand, being able to check whether an object implements a certain interface can be really helpful. Think about this:
DATA: lr_displayable TYPE REF TO if_xyz_displayable. IF ir_object IS INSTANCE OF if_xyz_displayable. lr_displayable ?= ir_object. lr_displayable->display( ). ELSE. * perform some generic implementation ENDIF.
Unfortunately, this statement is not (yet?) implemented. So what are the alternatives?
The probably cleanest solution at the current time is to use the run-time type inspection (RTTI). This can be done roughly like this:
DATA: lr_descriptor TYPE REF TO cl_abap_objectdescr, lr_displayable TYPE REF TO if_xyz_displayable. lr_descriptor ?= cl_abap_typedescr=>describe_by_name( 'IF_XYZ_DISPLAYABLE' ). IF lr_descriptor->applies_to( ir_object ) = abap_true. lr_displayable ?= ir_object. lr_displayable->display( ). ELSE. * perform some generic implementation ENDIF.
This is definitely harder to read and to write than an INSTANCE OF operator would be, and the additional variable required doesn’t make things much better.
Another way of dealing with this kind of issue seems to originate from the fans of Demolition Derby. Simply put: Try to cast the instance, and if that fails, it wasn’t one of ours:
DATA: lr_displayable TYPE REF TO if_xyz_displayable. TRY. lr_displayable ?= ir_object. lr_displayable->display( ). CATCH cx_sy_move_cast_error. * perform some generic implementation ENDTRY.
While this implementation does get rid of the additional variable, it also neatly disposes of code legibility. In my opinion, it’s like catching a CX_SY_ZERODIVIDE to check whether a number is zero. But there’s one idea that is so overwhelmingly mind-boggling that I just have to mention it:
Yep, that’s right. Force every programmer in your vincinity to implement that interface and to implement the methods correctly so that your inheritance checking actually works. Waste an unknown amount of time ensuring that GET_TYPE – which actually returns an integer – returns unique values. Even add a customizing table so that customers can ‘reserve’ ‘namespaces’ for their own subclasses of framework classes. And it doesn’t even solve the problem of interface implementation checking. I sincerely hope there was a good reason to choose this design back in 2003 and an even better reason not to remove it in the meantime…