Sei sulla pagina 1di 21

 VOLUME 1

  NUMBER 4, 1999 

Inheritance and Interfaces ­ 
Polymorphism in ABAP Objects
HORST KELLER and HOLGER MEINERT 
Article level:
Advanced
Figure 1
Listing 1
Listing 2
Listing 3
Listing 4
Listing 5
Listing 6
Listing 7
Listing 8
Listing 9
Listing 10
Listing 11
Listing 12
Listing 13
Listing 14
Listing 15
Listing 16
Listing 17
Listing 18

Technology areas discussed :


Custom Development

In the last issue we introduced ABAP Objects, the object­oriented extension of 
the ABAP programming language, using a comprehensive example. However, we 
only briefly introduced the main mechanisms to achieve polymorphic behavior, 
namely inheritance and interfaces.

Polymorphism is one of the most important concepts in object orientation. In 
general, it is the ability of something to appear in multiple forms, depending on 
context, or the ability of different things to appear the same in a certain context. 
In object­oriented programming, it usually means that all objects of a particular 
type can be handled in the same way, independent of the underlying 
implementation. As an example, an object of type circle is also an object of type 
shape, so a circle can be accessed in the same way as a shape. You can write 
code that talks to shapes and automatically handles anything that fits the 
description of a shape, such as circles, squares, and triangles. 

Polymorphism in object­oriented programming has three cardinal facets:

• Subclassing: inheritance of implementation fragments / code 

• Subtyping: support of contract fragments/interfaces 

• Promise of substitutability: ability to use a specialized object where a 
more general object is expected without the need to know the difference. 

Subclassing and subtyping are technical mechanisms ABAP Objects provides via 
inheritance and interfaces. These mechanisms usually carry the promise of 
substitutability but only enforce it on a technical level. However, semantical 
constraints are necessary to ensure true substitutability. For example, objects of 
a class inheriting from a superclass can technically be used in all places where 
objects of the superclass are expected. However, they still have to fulfill the client 
expectation derived from looking solely at the superclass, or the client code will 
break.

In this article we will first examine the concepts of inheritance and interfaces in 
ABAP Objects and then discuss polymorphism. We will show technical details, 
explain design decisions, and briefly compare ABAP Objects concepts to Java. 
Java is a widely known object­oriented language that generates much public 
attention. So it is interesting to see where ABAP Objects is similar to Java, where 
it is different, and why. However, we will not describe how to design with 
inheritance and interfaces. At the end of the article, we will briefly discuss the 
semantic matters of substitutability as well as the advantages, disadvantages, 
and consequences of working with inheritance and interfaces.

INHERITANCE
Inheritance is an implementation relationship between classes that allows a 
class, called a subclass, to inherit all components of another class, called a 
superclass. In ABAP Objects, adding INHERITING FROM to the class definition 
statement enables inheritance (see Listing 1).

In a subclass you define additional components or redefine instance methods 
that were inherited from the superclass, but you can't remove inherited 
components. Therefore, a subclass is strongly coupled to its superclass just by 
containing all of the superclass's components. While a subclass knows its 
superclass, a superclass has no knowledge of its subclasses. Nevertheless, the 
semantic coupling is strong in both directions because changing a superclass 
automatically changes or even invalidates all of its subclasses.

While a subclass specializes a superclass by adding components or redefining 
methods, a superclass is a generalization of its subclasses. In fact, inheritance 
should be used to implement relationships between classes that can be 
described in terms of generalization and specialization. For example, if you 
compare a passenger_airplane class to a cargo_airplane class, you will 
find that many common features can be put into a general superclass, 
airplane.

Single inheritance. ABAP Objects supports single inheritance, which means 
that a class can have only one direct superclass. This rule is enforced by the 
syntax of the INHERITING FROM clause, which specifies the name of only one 
superclass. Note that the superclass can be a direct subclass of another class, 
but a class can never be a subclass or a superclass of itself, even across multiple 
steps of inheriting. Each class can have many subclasses. 

Visualize the single inheritance relationship as a tree. The single root of this tree 
is the predefined, empty pseudo class OBJECT. The definition of a (sub)class is 
distributed among the classes within the branch of the inheritance tree that joins 
the root OBJECT with the given class (see Figure 1).

ABAP Objects does not support multiple inheritance, because one of the main 
design goals for ABAP Objects was to make it as simple as possible. With 
multiple inheritance (available in C++ or Eiffel), a subclass can inherit directly 
from more than one class. This inheritance relationship is a network instead of a 
tree. In multiple inheritance, the rules for the namespace of components become 
much more complicated and may lead to naming collisions. Another problem is 
the so­called diamond inheritance problem: If the classes c2 and c3 inherit from 
a class c1, both contain all the components of c1. Now, if class c4 becomes a 
subclass of both c2 and c3, the problem arises of how to merge the original 
components of c1 into c4. However, ABAP Objects supports most of the benefits 
of multiple inheritance (such as the reuse of common interfaces and a wider 
scope polymorphism) by the separate concept of interfaces, which circumvents 
naming collision and the diamond inheritance problem.

Visibility of components. Each class component has a visibility. In most other 
object­oriented languages, visibility is part of the component declaration. But in 
ABAP Objects the whole class definition is separated into three visibility sections: 
PUBLIC, PROTECTED, and PRIVATE. You can never change component visibility 
via inheritance. Let's take a look at the visibility sections of a subclass in an 
inheritance tree and the results of inheritance. 

• PUBLIC: This section is made up of the subclass' own public components 
together with all public components of all superclasses. There is 
unrestricted access to the public section of the subclass. 

• PROTECTED: This section is made up of the subclass' own protected 
components together with all protected components of all superclasses. 
The protected section of a subclass is accessible only by the subclass 
itself and by all of its subclasses. For the external client, protected 
components are invisible. Hence, protected has the same meaning as 
private when seen from outside the class. 

• PRIVATE: This section is made up of the subclass' own private 
components accessible only in that subclass. Each subclass works with its 
own private components and can't even use the private components of its 
superclasses. But as long as a method inherited from a superclass is not 
redefined, it still uses the private attributes of the superclass, not those of 
the subclass, even if the subclass has private attributes of the same name.

By comparison, Java defines four levels of access protection for class features. 
Public and private in Java have the same meaning as in ABAP Objects. However, 
protected features can be accessed by all subclasses and all classes within the 
same package. Finally, features with none of the described properties are 
accessible for all classes within the same package, by default.

Namespace of components. The ABAP Objects visibility model has the 
following consequence within a class: There is only one common namespace for 
all its own components and all the public and protected components of all its 
superclasses. In other words, all those components must have unique names. 
You can always add private components to a class without disturbing its 
subclasses. However, if you add a public or protected component to a class, 
there is always the danger that you'll invalidate other classes that inherit from 
yours because every subclass containing a component of the very same name 
becomes syntactically incorrect. The only ways to overcome this problem are to 
add only private components or to forbid inheriting from your class by defining it 
as final (as we'll discuss later in the article).

Java's concept of namespace is different from ABAP Objects. The following 
possibilities are allowed in addition to unique names:

• If an attribute is declared with the same name as an attribute in a 
superclass, the latter is simply considered to be shadowed (there are 
mechanisms for accessing the shadowed attribute). 

• If a method is declared with the same name but a different signature as a 
method in a superclass, both methods are available. This is possible 
because Java supports the concept of method name overloading. Method 
name overloading means that if two methods of a class (meaning both 
declared in the same class, both inherited by a class, or one declared and 
one inherited) have the same name but different signatures, then the 
method name is said to be overloaded. When a method is invoked, the 
number of actual arguments and the compile­time types of the arguments 
are used to determine the correct method to be executed. 

• If a method is declared with the same name and signature as a method in 
a superclass, the method in the superclass is considered to be overridden. 
This is the equivalent to method redefinition in ABAP Objects. 

These points describe one of the main differences between ABAP Objects and 
Java. ABAP Objects does not support name overloading and its consequences 
but one single namespace.
Method redefinition. In a subclass, you can redefine the public and protected 
instance methods of all preceding superclasses using the addition 
REDEFINITION of the METHODS statement. This addition allows you to adjust 
those methods to the requested specialization (see Listing 2).

The signature (parameters and exceptions) and the visibility of a redefined 
method can't be changed. The method is merely re­implemented under the same 
name. The method declaration remains with the superclass, and its previous 
implementation is also retained there. The implementation of the redefined 
method is added in the subclass and obscures the implementation in the 
superclass. A redefined method works with the private attributes of the subclass. 
A redefined method m usually uses CALL METHOD super->m to call the 
obscured implementation in the superclass in order to work properly on the 
(private) attributes of the superclass, too. The pseudo reference super is 
predefined especially for that purpose.

Overriding a method in Java works in the same way as redefining a method in 
ABAP Objects, although the syntax is different. Java additionally allows visibility 
changes, making the overridden method more public.

Instance constructors. An instance constructor is a public method with the 
predefined name constructor. The system invokes it automatically as the last 
step in creating a new object with the CREATE OBJECT statement. Its task is it to 
ensure that the new object has a consistent initial state.

Each class can have exactly one instance constructor, an exception to the rule 
that method names must be unique within a branch of the inheritance hierarchy. 
No namespace conflicts can occur because it is not possible to redefine the 
instance constructor or call it directly, with one exception. Recall that private 
attributes can only be accessed in the defining class; therefore, a class' instance 
constructor can never work directly on the private attributes of its superclass. To 
initialize these attributes properly, the instance constructor of the superclass must 
be called.

This brings us to ABAP Objects' three­phase­model for an instance constructor in 
a subclass (see Listing 3). In the first phase, the instance constructor behaves 
like a static method, allowing only static attributes to be accessed. The second 
phase simply consists of the call CALL METHOD super->constructor, the 
only way to call a constructor explicitly. Finally, in the third phase the instance 
constructor behaves like an ordinary instance method. Violating this order leads 
to a syntax error. 

In phase one, the call of the superclass instance constructor should be prepared, 
for example, by determining the required actual values for this call. Following the 
model, the call in the second phase iteratively results in the proper initialization of 
all inherited attributes. In phase three, the (instance) attributes defined in the 
class under onsideration can be initialized.

A little problem remains to be solved. If the direct superclass of the class under 
consideration has its own instance constructor, it will be called in phase two, and 
the appropriate actual parameters have to be passed. If the direct superclass 
does not have an explicit instance constructor, the system ensures that the next 
explicitly available instance constructor up the inheritance tree is invoked. The 
appropriate arguments for the call of this constructor must be provided in phase 
two. If no superclass has an explicit instance constructor, phases one and two 
can be omitted and the constructor behaves like an ordinary instance method. In 
particular, this applies to the direct subclasses of OBJECT (the classes that do not 
have ordinary superclasses).

In Java a class may have several constructors because Java allows method 
name overloading. If a class does not explicitly contain a constructor, Java 
automatically supplies a default constructor with no arguments. Constructors 
always have the same name as their defining class and can't be inherited. Except 
for the constructors in the root class of the inheritance tree, a constructor always 
begins by calling another constructor in the same class or in its direct superclass. 
If the first statement is not an explicit call to another constructor, the compiler 
inserts a call to the constructor of its direct superclass that takes no arguments. If 
the superclass does not have such a constructor, the compiler issues an error 
message. 

Creating objects of subclasses. The CREATE OBJECT statement in ABAP 
Objects requires actual values for the constructor call. If the class of the object to 
be created has the method constructor, at least the mandatory parameters of the 
latter must be provided via CREATE OBJECT ... EXPORTING. Otherwise, 
search up the inheritance tree until you find the first class with an explicit instance 
constructor. Actual values for this method must be passed in the CREATE
OBJECT statement. However, no parameters at all can be passed when creating 
a new object if the class and any of its superclasses lack an explicit instance 
constructor.

A final word of caution: Do not confuse the situation where a class lacks an 
explicit instance constructor with the situation where the method constructor is 
defined but does not take any parameters. In the latter situation you must not 
search up the inheritance hierarchy or pass any parameters to the corresponding 
call.

In Java you create a new object by providing actual values for the parameters (if 
available) of one of the constructors of the corresponding class. 

Static attributes. Like all public or protected components, non­private static 
attributes declared by CLASS-DATA exist only once per branch of the inheritance 
tree. A class can access the content of the public and protected static attributes 
of all superclasses. Also, a class shares its public and protected static attributes 
with all subclasses. Changes can be made from outside using the class 
component selector -> with all class names involved or from inside in all classes 
that know the attribute (see Listing 4). 

When the class component selector accesses a static attribute the class where 
the attribute is declared is always addressed irrespective of the class name used 
in the class component selector. 

Java's concept of combining static attributes and inheritance is the same.
Static methods. Static methods defined by CLASS-METHODS work with the static 
attributes of their own class and all non­private static attributes of all preceding 
superclasses. They can't be redefined in subclasses. This means they can be 
implemented only once in the defining class restricting the possibility of 
polymorphism to the use of objects and their access via reference variables (see 
the section on polymorphism). Accessing a static method via the name of any 
subclass always yields the same result irrespective of the class name used. A 
static method's semantics is fixed to the defining class.

Static events. Static events defined by the statement CLASS-EVENTS are also 
shared across their branch of the inheritance tree. If a class contains a non­
private static event, this single event is shared with all subclasses. This is 
important for event handlers. If a handler method is registered, it doesn't matter 
whether the definition of this method refers to the event in the defining class or in 
a subclass. There's only one event handler queue for this event. Consequently, 
raising this static event, even in a subclass, causes all registered event handler 
methods to be executed ­ not just those defined with respect to the subclass.

Static constructors. With a static constructor, you set the static attributes of a 
class dynamically. Every class has one and only one static constructor: a static 
method called class_ constructor that can't be called directly. The first time 
you address a class in a program, the system automatically calls the static 
constructor. Before this, all static constructors up the entire inheritance tree must 
be executed to properly initialize the class and its superclasses. The system 
searches up the inheritance tree for the highest superclass whose static 
constructor has not yet been called. It then calls this static constructor and those 
of all subclasses down to the class that you addressed.

There is an exception to this rule. When a static component is addressed via the 
name of a subclass, only the static constructors of the declaring class, and 
possibly its superclasses, are executed ­ not the static constructors of its 
subclasses. 

Java does not have special static constructor methods. It ensures that all static 
initialization is done in all superclasses before it starts in a particular class.

Final methods and classes. By coding FINAL to the statements METHODS and 
CLASS, you define final (instance) methods or final classes. Final methods can't 
be redefined in subclasses, and final classes can't have other subclasses. They 
are always leaves of the inheritance tree (see Listing 5). A final class implicitly 
contains only final methods. You can't and don't need to mark any method of a 
final class as final.
By using FINAL, you protect your methods or classes against unpredictable 
specialization. When you design an application, you may define as final each 
method that is not redefined in a subclass or each class that has no subclass. 
This reduces the danger of any unknown application inheriting from your classes 
and getting invalidated when you change your application.
The same concepts exist in Java.

Abstract methods and classes. By adding ABSTRACT to the statements 
METHODS and CLASS, you define abstract (instance) methods or classes. 
Abstract classes can't be instantiated. This means there can never be an object 
belonging to an abstract class. Abstract methods can only be implemented in a 
subclass, never in a defining class. To implement an abstract method in a 
subclass, you must declare it in the subclass with the statement METHODS using 
the addition REDEFINITION (see Listing 6). A class containing an abstract 
method must itself be abstract.

Although an abstract class can't be instantiated, reference variables defined with 
respect to an abstract class make perfect sense. These variables may carry 
pointers to instances of concrete (that is, non­abstract) subclasses (see the 
polymorphism section).
Abstract instance methods can be used to define signatures for subclass 
methods without actually implementing them. Since ABAP Objects does not 
support multiple inheritance, a subclass can't be created from several abstract 
classes. Instead, you use interfaces.

Abstract classes can be used as incomplete templates for several specialized 
classes. For example, you implement general methods in an abstract class and 
force all concrete subclasses to implement certain specialized methods with a 
given signature. 

Again, these concepts also exist in Java.

INTERFACES
Interfaces represent the other main building block of ABAP Objects along with 
classes. They act as a protocol layer or a contract between client and server 
classes and are created with the Interface statement (see Listing 7).

In an interface you declare the same components as in classes: attributes, 
methods, and events. However, no visibility information is provided. Also, 
interfaces are always abstract in the sense that you can't create objects from 
them. To work with the components of an interface, there must always be a class 
that implements that interface in its public section. By implementing an interface, 
the public section of a class is extended by all the interface components. A class 
that implements an interface must also implement the methods of the interface.

There are two reasons for using interfaces:

• In the first scenario a client specifies what kind of services it needs to fulfill 
its task. An archive_manager class, for example, may need a service to 
extract the data from the objects to be archived. There might be an 
interface archiveable containing a method to extract the data to be 
archived. Now several classes may implement this interface, which means 
that they provide exactly the required services. Through the interface view, 
the archive_manager class client is able to work with objects of all 
these classes identically. However, the methods may be implemented 
differently in each class. For example, the implementation may depend 
strongly on the attributes of each class. The main advantage here is the 
polymorphic behavior of the various objects. 

• In the second scenario a class may want to provide some kind of restricted 
view of its services. To this end, it defines an interface that contains only 
the appropriate subset of components rather than all public components. 
In a particular context, clients of the class may now work with this 
restricted access to the class instances. The main advantage here is that 
interfaces can be used to extend or group a class's public interface. This 
type of use will benefit from future additions to ABAP development that will 
let you explicitly publish or hide classes or interfaces. 

Java also provides interfaces. However, in Java only methods and constants are 
allowed as interface components while in ABAP Objects the complete public 
section of a class can be defined by interfaces. Further, the concepts of resolving 
naming conflicts are different: Java uses some kind of merging, whereas ABAP 
Objects tracks which interface a component belongs to by prefixing the name of 
an interface component with the interface name except when you're working with 
the interface directly. This prefixing approach provides an elegant solution to the 
diamond problem mentioned earlier.

Implementing interfaces. By using the INTERFACES statement in a class 
definition, you declare that a class implements one or several interfaces (see 
Listing 8). One interface can be implemented by several classes. An interface 
must always be implemented in the public visibility section of a class. 
Implementing an interface means implementing the methods declared in that 
interface. All the other interface components, including attributes or events, are 
automatically added to the public section of the class. However, interface 
components are not directly visible in the public section. Only the interface name 
can be found there. A component comp of an interface intf implemented in a 
class becomes a fully fledged member of that class, with the name intf~comp. To 
access this component within the class or through a class reference, you must 
always use its full name. 

Classes that implement interfaces must implement all of their methods. After an 
interface is released to the public, you can't add or delete methods without 
invalidating all implementing classes. In the R/3 distributed programming 
environment any problems with global interfaces are identified with special 
warnings and catchable runtime errors.

In interface implementation, the naming of interface components is the main 
difference between Java and ABAP Objects. In Java, interface components are 
not prefixed in any way. They basically work by the mechanisms (shadowing and 
method name overloading) mentioned earlier in the article. Besides this, 
implementing an interface in a class essentially means providing an 
implementation for each of the methods declared in the interface, which is true in 
both ABAP Objects and Java.

Composing interfaces. ABAP Objects has a concept of interface composition 
that allows it to introduce new interfaces containing multiple other interfaces. An 
interface can include one or more interfaces as components, and those 
interfaces, themselves, can also contain interfaces. An interface that includes 
another interface is called a compound interface. An interface contained in 
another interface is called component interface. An interface that does not 
contain any component interfaces is called an elementary interface. You can 
create compound interfaces by using the INTERFACES statement in an interface 
definition. In Listing 9, the interface i3 consists of its own components and the 
interfaces i1 and i2. All interface components of a compound interface have the 
same level. In Listing 9, the compound interface i3 contains another compound 
interface, i2. The component interface i1 of interface i2 becomes component 
interface of i3. A component interface, here i1, exists only once even if it is used 
again as a component of another component interface. Therefore, a compound 
interface includes each interface component exactly once. 

In Java, interfaces can be extended so that one interface inherits from several 
other interfaces. Identical methods from different (super­)interfaces are merged 
into one method.

Implementing compound interfaces. When a compound interface is 
implemented in a class, all components of component interfaces retain their 
original full names. There is no nesting of names such as i1~i2~comp. Instead, a 
component comp originally defined in an interface intf is still addressed with 
intf~comp. All interface components are at the same level. The composition 
hierarchy is not relevant for implementing compound interfaces in classes.

As a result, each interface component exists exactly once in a class. In Listing 10, 
method i1~m is implemented only once, although it is contained in two interfaces, 
i2 and i3. This solves the diamond problem. Note that the name of interface i4 
does not even occur in the implementation of class c1. And although the name of 
the method is the same in each interface, there are three method 
implementations. For each interface, method m is implemented according to its 
individual semantic rules. 

In Java, such problems are mostly resolved by merging. If identical methods are 
merged into one method, a class implementing an extended interface (the analog 
to ABAP Objects' compound interfaces) has to provide only a single 
implementation. Whether this is semantically correct or not is a different question. 
However, if those methods are identical, except the return type, a compile­time 
error results. The remaining cases are resolved via method name overloading. 

Accessing component interfaces. Listing 11 shows how you access the 
interface components of an object when the object's class implements a 
compound interface. 

As we've already mentioned, you always use the original full names intf~comp if 
you're accessing the components of component interfaces via object references. 
However, there is a more preferable means of access: You can use a narrowing 
cast to assign the object reference to a reference variable that refers to the 
component interface. With such a reference variable, the interface components 
are accessed without prefixing. This is appealing because use of the prefix 
should be limited to interface implementation and composition. An external client 
should always access interface components via the respective interface 
reference variable, whose semantics properly describe the interface's behavior.

In Java if an interface extends another interface (in ABAP Objects' terms, the first 
is the compound and the second the component interface), the features of the 
second interface are directly accessible through a reference to the first. This is 
because Java favors the concept of merging.

Aliases. Aliases provide shortcuts to interface components within classes or 
compound interfaces. Within a compound interface you create an alias for a 
component of a component interface. Because there is no nesting of names in 
compound interfaces, you need aliases for those components you want to access 
through an interface reference that refers to the compound interface (see Listing 
12). 

An alias component is part of an interface's namespace. This means that an 
interface component can't have an alias identical to the name of another 
component, such as a method. Thus, naming conflicts are avoided.

The ALIASES statement is also used in classes to create aliases for 
implemented interface components. However, aliases don't influence interface 
implementations; they simply provide shortcuts for accessing the interface 
components.

If you use aliases, compound interface clients don't need to know how an 
interface is composed. The other important application for aliases is refactoring. 
If clients need only parts of existing interfaces, these parts may be extracted to 
new interfaces. The old interfaces then replace the parts by including the new 
interfaces. Old names are used as aliases for the components that now belong to 
the new interfaces. Therefore clients of the old interfaces are not affected. 
Unfortunately, classes that implement the old interfaces must be changed to work 
with the new component names.

Interfaces and inheritance. Interfaces and inheritance are fully compatible. 
Within a branch of an inheritance tree, you can implement any number of 
interfaces. But a given interface may only be implemented once in one branch. 
This ensures that the interface components have unique names throughout each 
branch of the inheritance tree. As fully fledged components of a class, interface 
components are inherited in the usual way. In particular, instance methods 
defined in interfaces can be redefined in the subclasses of the class 
implementing the interface. However, you can't mark interface methods as 
abstract or final. 

POLYMORPHISM
Polymorphism refers to the ability of objects of different classes to behave the 
same in a certain context or the ability of clients to access an object in multiple 
forms, depending on the context. These are the two sides of the polymorphic 
coin. In ABAP Objects a reference variable may contain references to objects of 
many different classes, and an object may be viewed through a superclass or an 
interface reference.

Sometimes polymorphism is said to be the basis for case­less programming. 
Although you should not take this too literally, it is true. In the presence of 
polymorphism you can write client code that uses the appropriate view for objects 
of different classes. Through this view, the client code handles server objects no 
matter which class they belong to, avoiding an explicit case­like type analysis.

Most of these mechanisms are essentially the same in Java. We'll discuss the 
main exception, polymorphism in instance constructors, a little later. 

Non­polymorphic situation. Objects as instances of classes are created with 
the CREATE OBJECT statement and are accessed by reference variables 
declared by adding TYPE REF TO to the DATA statement. Without the concepts 
of inheritance and interfaces, the picture is rather simple. For example, in Listing 
13 the reference variable o1 always contains references to objects of class c1. 
The type of the reference variable and the type of the object it points to are the 
same. 

Polymorphism via inheritance. With inheritance, a reference variable defined 
with respect to a class c1 may not only point to instances of c1 but also to 
instances of subclasses of c1. You can even create subclass objects using a 
reference variable typed with respect to a superclass.

In Listing 14 the type c1 of the reference variable o1 is different from the type c2 
of the object to which the variable points. Consequently, a reference variable is 
said to have a static and a dynamic type. The static type is the class (or interface) 
used in the reference variable definition. The dynamic type is the class of the 
object to which the reference variable is currently pointing. Using inheritance only, 
the static type is either the same as the dynamic type or is a superclass of the 
dynamic type. In other words, instances of a subclass may be used through the 
superclass's interface. When this is done, a client can't access all components 
defined in the subclass, only those inherited from the respective superclass. 
Switching between these two views of instances is possible (see the section on 
assigning reference variables).

Another key issue is the polymorphic method call. When you work with redefined 
instance methods, you usually have several implementations of the same method 
in one branch of an inheritance tree. It is important to know that the most 
specialized implementation is always used for the execution of a method. In the 
example in Listing 15, this is the implementation in class c2. The reference in 
variable o1 points to an object of class c2, which provides its own implementation 
for method m. The system starts by looking at the class given by the reference 
variable's dynamic type or, in other words, at the class of the object to which the 
reference is currently pointing. If this class provides an implementation for the 
method under inspection, this implementation will be executed. Otherwise, the 
system searches up the inheritance hierarchy for the next­highest class that 
provides an implementation for the method and then executes this 
implementation. This procedure ensures that the correct implementation is used.

Polymorphism via interfaces. With interfaces, ABAP Object provides another 
type of reference variable called an interface reference. The static type of an 
interface reference variable is the interface used in the variable's definition. There 
are no instances of interfaces, but an interface reference can point to objects of 
all classes that implement the respective interface. It doesn't matter whether the 
interface is implemented directly or as a component of a compound interface. 
The dynamic type of an interface reference variable is the class of the object to 
which the variable is currently pointing. So, the static and the dynamic type of an 
interface reference variable are always different.
In Listing 16 the static type of the reference variable o1 is the interface i1. This 
interface is implemented via the compound interface i2 in class c1. An object of 
class c1 is created with o1 pointing to it. A client may now work with this 
interface reference without knowing the class of the object to which the variable 
refers. 

An interface reference provides only restricted access to the object it points to. 
So not all components of an objects class are accessible, only those defined in 
the respective interface. 

Because interfaces do not carry any implementations, working with interface 
references always produces polymorphic behavior. When calling a method via an 
interface reference, the system uses the dynamic type to determine the 
implementation to be executed.

Polymorphism via interfaces and inheritance. The concepts of interfaces and 
inheritance fit together nicely to enable a combination of both types of 
polymorphism. When a class implements an interface, the same applies to all 
subclasses. Thus, a corresponding interface reference may also point to 
instances of subclasses, and the rules for finding the appropriate method 
implementation are the same.

Polymorphism and instance constructors. In an instance constructor, the 
methods of subclasses are not visible. Suppose you want to create an object of 
class c2, which in turn is a subclass of c1. Using the ABAP Objects model of 
building instance constructors, the instance constructor of c2 calls the instance 
constructor of c1. If the second constructor calls an instance method of its own 
class c1, the implementation found in c1 (or possibly in a superclass) is used, 
rather than any implementation available in the subclass c2 you are trying to 
instantiate. This is the single exception to the rule that an instance method you 
call is always executed using the implementation in the class to which the 
reference is currently pointing. 

Here ABAP Objects follows the concept of C++. Polymorphic behavior in the 
described situation, as in Java, would lead to a call of an instance method of the 
subclass c2 even before the process of initializing an object of this class is 
completed. This often leads to unexpected behavior.

ASSIGNING REFERENCE VARIABLES


When the static and the dynamic type of a reference variable are different, the 
principle rule is that the static type is always more general than the dynamic type: 
• If the static type is an interface, the dynamic type can be any class 
implementing that interface. 

• If the static type is a class, the dynamic type can be a subclass of that 
class. 

When you assign references between reference variables (or create objects), you 
must obey this rule. For the different types of reference variables in ABAP 
Objects, you distinguish between cases in which the rule can be checked 
statically during the syntax check and cases in which it can be only checked 
dynamically at runtime.

Narrowing cast. It is always possible to assign a reference variable to another 
reference variable when the static type of the target is more general than the 
static type of the source. In ABAP Objects, the following cases are checked 
during the syntax check:

• If the static types of both reference variables are classes, the target 
variable class must be the same or a superclass of the source variable. 
Therefore, the target variable class can always be OBJECT because this is 
a superclass of all classes in ABAP Objects. 

• If the static types of both reference variables are interfaces, the target 
variable interface must be the same as the source variable interface, or 
the source interface must be a compound interface, including the interface 
of the target variable as a component. 

• If the static type of the target variable is an interface and the static type of 
the source variable is a class, the class (or one of its superclasses) must 
implement the interface. 

• If the static type of the target variable is a class and the static type of the 
source variable is an interface, the class must be OBJECT. 

Listing 17 shows examples of possible assignments. Note that you can't directly 
access components of interface i1 via io2, since these components are not 
visible. Nevertheless, you can assign io2 to io1 and then access these 
components.

The assignments progress from specialized reference variables that know more 
details to general reference variables that know fewer details. Such assignments 
are called narrowing casts. Narrowing casts are always appropriate for users who 
want to work with a restricted view of an object as it is provided by a superclass 
or an interface. In the special case of reference variables with the static type 
OBJECT, no part of an object is accessible statically. Such a reference variable 
may serve as a mere container except when components are addressed 
dynamically. 

Widening cast. Widening casts are the counterparts of narrowing casts. They 
are used to switch back to a more detailed view (or type) of an object, which is 
currently accessed through a more general reference variable. However this only 
works if the object the reference variable refers to supports the more detailed 
view. For all cases that are not listed under narrowing cast, a static type check is 
not possible. The type check must be postponed until runtime. This is visualized 
by using a new assignment operator, the casting operator (?=), instead of the 
usual assignment operator (=). The assignment takes place at runtime only if the 
target variable static type is equal to or more general than the source variable 
dynamic type. Otherwise, the system responds with the catchable runtime error 
MOVE_CAST_ERROR. 

Listing 18 shows an interface example. The second assignment leads to an 
exception because the dynamic type of io1, namely c1, is not the same as or a 
subclass of the static type of co2, namely c2.

The widening cast is used to switch back from a superclass view of an object to a 
subclass view, from an interface view to a class view, or from a component 
interface view to a compound interface view. This all works across several levels 
of inheriting or composing interfaces but only if the object in question supports 
the more detailed view.

The rules for reference casting in Java are essentially the same as in ABAP 
Objects. However, Java uses an explicit cast operator (the desired type enclosed 
in parentheses) but no explicit assignment operator for widening casts.

SUBSTITUTABILITY
Polymorphism makes substitutability technically feasible. However, it is important 
to understand that simply establishing technical substitutability is not enough. 
Neither a language nor a compiler can enforce semantical substitutability. Hence, 
developers must follow the (semantical) principle of substitutability (sometimes 
also referred to as the Liskov Substitution Principle), which states that a more 
specific class/interface must be substitutable for a more general class/interface 
without breaking the clients. A more specific class/interface can be substituted for 
a more general class/interface if it respects the contract between the more 
general class/interface and its clients.

Specifically, when a class inherits from a superclass or implements an interface, 
this class must respect the semantics defined in the superclass or interface. Even 
if it adjusts its implementation to its own specific needs, it must not alter the 
expected overall behavior. Imagine a situation in which a client code uses a 
reference variable defined with respect to the superclass or interface. Accessing 
a certain component via that variable, the client code expects exactly the 
behavior as defined in the superclass or interface. The client doesn't know and 
doesn't want to know that at runtime this reference variable may point to an 
object of the class we started with. What an unpleasant surprise if the object 
behaves differently. It is very likely that the client code will not work properly.

Working with inheritance and interfaces will be successful only if classes and 
interfaces, as well as their underlying semantics and their components, are 
described carefully. In addition, subclasses, or implementing classes, must be 
implemented according to this description. This applies to the (re­)implementation 
of methods and to the use of all inherited components.

POWERFUL POSSIBILITIES
In this article we discussed three important ABAP Objects concepts: inheritance, 
interfaces, and polymorphism. By combining single inheritance with composable 
interfaces, ABAP Objects follows the main concept of Java. The central 
difference is handling potential naming conflicts. While Java relies on method 
name overloading and merging, ABAP Objects favors more explicit naming 
mechanisms to resolve naming conflicts. However, ABAP Objects may be a little 
less flexible than Java in this area.

Inheriting implementation fragments or coding offers the powerful possibility of 
code reuse. In particular, subclasses benefit automatically from features 
implemented in superclasses. On the other hand, there's usually a tight coupling 
between a class and all its superclasses. A class depends heavily on its 
superclasses and must have detailed knowledge about their implementation. And 
it is not uncommon for subclasses to influence their superclasses. Inheritance 
provides a kind of whitebox reuse.

The interface concept usually enforces a more blackbox­like style of development 
because interfaces do not carry any implementation. They are a contract or 
specification between clients and providers and are a means of decoupling. The 
interface concept shares most of the strengths of inheritance; for example, 
interfaces are a means to express abstraction, to reduce complexity, and to 
achieve polymorphic behavior. However, the interface concept avoids the main 
weakness of inheritance.

Polymorphism, or technical/syntactical substitutability, as provided by both 
inheritance and interfaces, is one of the most powerful mechanisms of object­
oriented programming. It can significantly simplify modeling and implementing, 
but this is possible only if polymorphism is supported by true, semantical 
substitutability. Because substitutability can't be enforced by the system, it 
depends on the development whether inheritance, interfaces, and polymorphism 
are used profitably or whether they make things worse. o

Horst Keller is senior technical writer in the SAP ABAP & GUI Group. He  
documents the ABAP language with an emphasis on ABAP Objects. He also  
develops and teaches classes on ABAP programming. You can reach him at  
horst.keller@sap.com. 

Holger Meinert is a member of the SAP internal OO Rollout group, providing  
support and training for SAP internal projects that use ABAP Objects. You can  
reach him at holger.meinert@sap.com.

© 2001 CMP Media Inc.
ALL RIGHTS RESERVED
™IntelligentERP is a trademark of CMP Media Inc. 
PRIVACY STATEMENT

LAST MODIFIED:Tuesday, 24-Oct-00 10:38:13

Potrebbero piacerti anche