abap objects

43
ABAP OBJECTS ABAP Objects, the object-oriented (OO) extension to the ABAP language, is available with releases 4.5 and 4.6. Release 4.6 adds inheritance, nested interfaces, and dynamic method invocation. In this article, as two of the developers of this new extension, we’ll take you through an introduction to ABAP Objects and give you a comprehensive example (The code for the example can be tested and debugged in DEMO_ABAP_OBJECTS in R/3 release 4.6 or higher). ABAP Objects is a nearly 100 percent upward-compatible extension of ABAP that includes a full set of OO features. We left out some obsolete language elements in the OO context within classes (so it is not truly 100 percent compatible), but you can use objects in all contexts without any restrictions. We created ABAP Objects because: 1. The business object repository (BOR) already presented an OO view of the system to the outside, and we wanted a common programming model for both outside and inside. 2. We wanted the potential benefits of objects within R/3, including better control of complexity, a better means for encapsulation, extensibility, and reuse, and a language basis for patterns and frameworks. 3. We wanted seamless integration with external object models (DCOM and CORBA). 4. We needed objects to be the foundation for a new GUI programming model (to be completed in release 5.0). At the beginning of the ABAP Objects project, we faced a fundamental question: Should we add OO features to the existing ABAP language, invent a completely new language, or integrate an existing OO language into R/3? We opted to integrate OO features into the existing ABAP language to create ABAP Objects for several reasons: It meant we would immediately inherit all the other features of the R/3 infrastructure such as software logistics, portable database access, TP monitor capabilities, and all database buffering and scalability. Certain features, such as persistence, transactions, events, and GUI frameworks, are hard to add on top of a language. This results in lots of generated code. To support these concepts,

Upload: navinsap

Post on 25-Nov-2014

333 views

Category:

Documents


6 download

TRANSCRIPT

ABAP OBJECTS

ABAP Objects, the object-oriented (OO) extension to the ABAP language, is available with releases 4.5 and 4.6.

Release 4.6 adds inheritance, nested interfaces, and dynamic method invocation. In this article, as two of the developers of

this new extension, we’ll take you through an introduction to ABAP Objects and give you a comprehensive example (The

code for the example can be tested and debugged in DEMO_ABAP_OBJECTS in R/3 release 4.6 or higher).

ABAP Objects is a nearly 100 percent upward-compatible extension of ABAP that includes a full set of OO

features. We left out some obsolete language elements in the OO context within classes (so it is not truly 100 percent

compatible), but you can use objects in all contexts without any restrictions.

We created ABAP Objects because:

1. The business object repository (BOR) already presented an OO view of the system to the outside, and we wanted

a common programming model for both outside and inside.

2. We wanted the potential benefits of objects within R/3, including better control of complexity, a better means for

encapsulation, extensibility, and reuse, and a language basis for patterns and frameworks.

3. We wanted seamless integration with external object models (DCOM and CORBA).

4. We needed objects to be the foundation for a new GUI programming model (to be completed in release 5.0).

At the beginning of the ABAP Objects project, we faced a fundamental question: Should we add OO features to

the existing ABAP language, invent a completely new language, or integrate an existing OO language into R/3? We opted

to integrate OO features into the existing ABAP language to create ABAP Objects for several reasons:

It meant we would immediately inherit all the other features of the R/3 infrastructure such as software logistics, portable

database access, TP monitor capabilities, and all database buffering and scalability. Certain features, such as persistence,

transactions, events, and GUI frameworks, are hard to add on top of a language. This results in lots of generated code. To

support these concepts, you must have your own compiler or interpreter and runtime, ruling out most off-the-shelf

languages.Our target was a language for business applications. We wanted it to be simpler than Java and C++ and to leave

out complex concepts lacking in benefits.

By integrating the concepts of OO languages—as opposed to using a specific OO language—into ABAP, we were

able to combine the best concepts from these languages and adapt them, when needed, to our specific needs.

Our main design goals were:

1. To make ABAP Objects as simple as possible

2. To use only proven OO concepts

3. To comply with external standards whenever possible (for example, to allow mapping to COM, CORBA,

and UML)

4. To require much stronger typing (type checking) than traditional ABAP, where type specification is almost

always optional.

The Design Environment

When designing ABAP Objects, we faced some special R/3-specific challenges:

1. Extreme variability—R/3 is a meta-application that is massively configurable and extendable by five layers.

2. R/3 is an interpretive system, so there is never a shutdown-change-recompile-restart cycle.

3. Software development logistics allow hundreds of developers to work on the same system parts, and logistics

must not be hindered by the language. The change process must be considered and supported by certain language

features (mostly resulting in some deliberate deviations from the general strong typing policy). You cannot

assume that developers can always perform synchronous global changes in the system.

Some of ABAP Objects’ key design elements include:

1. Classes are not structures with methods (as in C++) but a new kind of type.

Reference semantics for objects. ABAP is completely value-based. There are no references in the language, and a

MOVE always copies its values (even with field-symbols). Objects, on the other hand, can only be accessed by

references (there are no embedded objects). This results in a clear separation of values and references. An object

reference always has reference semantics. This is the only place in ABAP where objects are shared and never

copied. Values (the traditional data) are always copied.

2. Single inheritance with a separate concept of interfaces. Here we follow a path similar to Java. Most multiple

inheritance applications are actually interface cases, and the few extra capabilities of multiple inheritance

definitely don’t warrant the complexity this introduces into the language.

3. ABAP Objects integrates complex concepts, most notably events and dynamic method invocation. Events are

introduced similarly to how they exist in Visual Basic. They are outbound methods that can have parameters. This

is a natural model for GUI applications. We also separated the event registration into a separate statement ( SET

HANDLER), which gives you the flexibility to define all kinds of topologies of sender-to-handler connections

(1:1, 1:n, n:1, n:m).

4. Of course, ABAP Objects has its own storage management (garbage collection) and a suite of tools such as the

Class Builder, Class Browser, and debugger support.

With release 4.6, the ABAP language is pretty much complete with all object components, inheritance, and nested

interfaces. Two main areas of ABAP Objects are still under development: A new GUI programming model and GUI

design tool, and the Object Services framework that covers persistence, transaction control, and locking. These should be

completed by release 5.0.

ABAP Objects Basics:

ABAP Objects is based on classes. Classes are pieces of program code that describe objects by defining their

components. Typical object components are attributes (data), which describe an object’s state, and methods (functions),

which describe an object’s behavior. Objects are instances of classes. Many objects can be created from one class, but

each object has its own attributes. ABAP Objects provides a set of new statements that defines classes and handles

objects. These statements can be used in any kind of ABAP program.

Classes, and therefore objects, consist of at least two layers—an inner and an outer layer. The externally visible

layer of an object is made up of public components. Public components can be accessed directly by all users and form an

object’s external point of contact. Private components are only visible within objects of the same class. The public section

usually contains few attributes. The state of an object is generally kept in private attributes and manipulated by public

methods. This way an object can ensure its own consistency.

Outside ABAP Objects, the only instances in ABAP are instances of whole ABAP programs such as reports,

module pools, or function groups. Each time a program is executed, a program instance is implicitly created, which then

runs in a separate ABAP process. Calling an external procedure (a subroutine or a function module) also creates an ABAP

program instance, which contains the procedure. However, repeated calls always use the same one instance. Such program

instances live as long as the application program is running and cannot be handled explicitly.

With ABAP Objects, it is now possible to explicitly handle instances. The instances of classes, namely objects,

are created explicitly with ABAP statements. They have a unique identity (independent of their attribute values) and are

addressed by references. They live only as long as they are needed.

Classes: Classes are templates for objects. You can either define a class locally in an ABAP program, or globally in the

class library using the Class Builder tool in the ABAP Workbench. The class library is part of the R/3 repository. Class

library classes are stored in special programs called class pools. A class pool is automatically generated for each global

class that you create with the Class Builder. The Class Builder also generates the coding frame that defines the classes in

the class pool. Global classes are visible to all ABAP programs of the R/3 System.

To define local classes in an ABAP program, such as a report or a function group, you must type the

corresponding statements manually into the program. A local class is visible only inside the program in which it is

defined. Classes are defined between the CLASS and ENDCLASS statements. A class definition consists of a declaration

part, in which the components are defined, and an implementation part, in which the methods are implemented.

Component visibility: Each component must be declared in one of three possible visibility sections. All components

declared in the PUBLIC SECTION can be accessed by all clients of the class. All components declared in the

PROTECTED SECTION can be accessed in the methods of the class and its subclasses (see inheritance). All components

declared in the PRIVATE SECTION can only be accessed in the methods of the class. The public section forms the outer

layer, or external interface, of the class. The protected and the private sections form the inner layer. Their components

cannot be accessed by external users.

Class components: Possible class components are attributes, methods and events. Events will be explained later in this

article.

Attributes: are the internal data variables within a class. They can have any ABAP data type. We distinguish

between instance attributes and static attributes. Instance attributes are declared by DATA and determine the state of an

instance. You cannot work with instance attributes without creating an object first. Static attributes are declared by

CLASS-DATA and determine the state of a class, which in a way applies to all instances. Static attributes form a data set

that is shared by the whole class and all of its objects. You do not need to create an object to work with static attributes.

Methods: are the class’ procedures. They can access all class attributes and can therefore change the state of an

object. They have a parameter interface similar to the interface of function modules. They can have named IMPORTING,

EXPORTING, and CHANGING parameters, which can be optional or required and can be passed either by reference or

by value. As with attributes, we distinguish between instance methods and static methods. Instance methods are declared

by METHODS and can access all the attributes of a class. Static methods are declared by CLASS-METHODS and can

only access the static attributes of a class.

Listing 1, defines a class vessel. The components of class vessel are the attributes speed, max_speed, object_count, and id,

and the methods constructor, drive, and get_id.

CLASS vessel DEFINITION.

PUBLIC SECTION.

METHODS:

constructor,

drive IMPORTING speed_up TYPE i,

get_id RETURNING value(id) TYPE i.

PROTECTED SECTION.

DATA: speed TYPE i,

max_speed TYPE i VALUE 100.

PRIVATE SECTION.

CLASS-DATA object_count TYPE i.

DATA id TYPE i.

ENDCLASS.

CLASS vessel IMPLEMENTATION.

METHOD constructor.

object_count = object_count + 1.

id = object_count.

ENDMETHOD.

METHOD drive.

speed = speed + speed_up.

IF speed > max_speed.

speed = max_speed.

ENDIF.

ENDMETHOD.

METHOD get_id.

id = me->id.

ENDMETHOD.

ENDCLASS.

Listing 1. Statements for defining a class.

Figure 1, page 34, shows how the class vessel is composed by its visibility sections.

Figure 1 Visibility sections of a class.

Method implementation: Each method declared in the declaration part of a class must be implemented in its

implementation part. Each implementation is enclosed between the METHOD and ENDMETHOD statements. You can

use almost all ABAP statements available in subroutines or function modules to implement the method, but ABAP

Objects does use a stricter syntax in some places to avoid obsolete features. Methods may contain declarations of local

data and data type.

Constructors: Implicitly, each class has an instance constructor method with the reserved name constructor and a static

constructor method with the reserved name class_constructor. The instance constructor is executed each time you create

an object (instance) with the CREATE OBJECT statement, while the class constructor is executed exactly once before

you first access a class. The constructors are always present. However, to implement a constructor you must declare it

explicitly with the METHODS or CLASS-METHODS statements. An instance constructor can have IMPORTING

parameters and exceptions. You must pass all non-optional parameters when creating an object. Static constructors have

no parameters.

Objects and object references: Objects are instances of classes. From the user’s point of view, there is almost no

difference between creating objects based on global classes and creating them on local classes. The statements for creating

and handling objects are exactly the same for both types of classes. Visibility distinguishes between global and local

classes. While any program can create objects from classes in the class library, only the defining program can create

objects from its own local classes.

Reference variables: Objects live in the internal session of an ABAP program and are accessed only via reference

variables. Object reference variables contain references (pointers) to objects and must be declared before creating an

object and accessing its components.

To declare a reference variable, you use the new data type REF TO class. Like other variables, reference variables

can be components of structures or internal tables. You initialize a reference variable with the CLEAR statement. The

initial value of a reference variable is a reference that does not point to an object.

Instances: Once you have declared a reference variable oref with the type of a class, you can create a class instance. Use

the statement CREATE OBJECT oref, which creates an instance of the class with the type of oref and places a reference

to the new instance into oref. Each CREATE OBJECT statement creates a new object.

You can create any number of instances of the same class in a program. Those instances are fully independent of

each other, and they have their own identity and attributes within the program. You can assign references between

reference variables using the MOVE statement or pass them as parameters. ABAP Objects’ reference variables are always

type-safe in the sense that they can only contain pointers to objects that conform to the interface given by the reference

variable’s declaration type. If that check is not possible statically, you can cast reference variables at run time.

Listing 2 declares two reference variables, vessel1 and vessel2, and creates two instances of class vessel with the two

reference variables pointing to them. Methods of the objects are then called.

DATA: vessel1 TYPE REF TO vessel,

vessel2 TYPE REF TO vessel.

DATA vessel_id TYPE i.

CREATE OBJECT: vessel1, vessel2.

CALL METHOD: vessel1->drive( 50 ),

vessel2->drive( 80 ).

vessel_id = vessel1->get_id( ).

WRITE: / 'Vessel ID is', vessel_id.

vessel_id = vessel2->get_id( ).

WRITE: / 'Vessel ID is', vessel_id.

Listing 2. Using objects and their components.

Figure 2, page 34, shows the two reference variables, each pointing to an instance of class vessel. The names of the

objects are shown in the same format (id<classname>) as the contents of reference variables in the ABAP Debugger.

These names cannot be used directly in the program.

Figure 2 Reference variables and objects.

Garbage collection: An object is in use as long as there is at least one reference pointing to it. When there are no more

references pointing to an object, the memory space occupied by that object can be released. ABAP Objects provides a

garbage collector, which ensures that the memory is collected automatically.

Accessing the components of objects: To access an instance component from outside the defining class, you use the

object component selector ->, which combines the object (reference) with the component name. Similarly, the class

component selector => combines the class with the component name when you access a static component.

To access attributes, you write oref->attr for instance attributes and class=>attr for static attributes. To call a method, you

write CALL METHOD oref->meth for an instance method and CALL METHOD class=>meth for a static method. CALL

METHOD has almost the same syntax as CALL FUNCTION, but ABAP Objects adds functional methods. These are

characterized by the fact that besides IMPORTING parameters, they have exactly one RETURNING parameter. This is an

advantage because they can be used like an ordinary variable directly in certain expressions. Instead of entering a variable

name, you simply write oref->meth(...) or class=>meth(...) specifying the required IMPORTING parameters within the

parentheses. During the execution of the expression the method is evaluated, and the value of the RETURNING parameter

is used in the expression. Inside methods, components of the same class can be addressed directly by their names, where

the compiler prepends the self reference ME implicitly. Only in special cases—for example, when an attribute is hidden

by a local data object or parameter with the same name—are you required to use just the ME->attr notation to explicitly

select the attribute (see an example in the constructor in Listing 3, page 33). ME can also be used when a method wants to

pass a reference that points to its own object.

CLASS ship DEFINITION

INHERITING FROM vessel.

PUBLIC SECTION.

DATA name TYPE string READ-ONLY.

METHODS: constructor

IMPORTING name TYPE string,

write,

drive REDEFINITION.

ENDCLASS.

CLASS ship IMPLEMENTATION.

METHOD constructor.

CALL METHOD super->constructor.

max_speed = 30.

me->name = name.

ENDMETHOD.

METHOD write.

DATA id.

id = me->get_id( ).

WRITE: / name,

'is vessel', id,

'and has speed', speed.

ENDMETHOD.

METHOD drive.

speed = speed + speed_up.

IF speed > max_speed.

max_speed = 0.

speed = 0.

ENDIF.

ENDMETHOD.

ENDCLASS.

Listing 3. Statements for deriving a subclass.

Inheritance: Inheritance allows you to derive new classes from an existing one. The new class inherits all components of

the existing class and is known as the subclass. The existing class is known as the superclass. A subclass reuses the code

of its superclass, but only the public and protected components of the superclass are visible in its subclasses. You can

define additional components in the subclass, making it more specialized than the superclass. A subclass itself can become

a superclass of additional new classes. This allows you to introduce several degrees of specialization.

Subclasses. To define a subclass, you use the INHERITING FROM clause in the CLASS statement of the declaration

part. ABAP Objects supports single inheritance. Classes can have several direct subclasses, but only a single superclass. A

special kind of multiple inheritance in ABAP Objects is provided by interfaces (which we will get to shortly).

When a subclass inherits from a superclass that is itself a subclass of another class, the classes involved form an

inheritance tree, which becomes more specialized moving from top to bottom. The components of a superclass are passed

on to all subclasses within the tree. The implicit root node of all ABAP Objects inheritance trees is the predefined class

OBJECT.

In Listing 3, a subclass ship is derived from superclass vessel. The subclass ship specializes its superclass by

adding a new attribute name and a new method write. Furthermore, class ship has its own constructor and redefines the

method drive.

Redefinition. In subclasses, you can make the public and protected instance methods of all preceding superclasses

specialized by redefining them using the REDEFINITION clause of the METHODS statement. You cannot change the

interface of a redefined method. Redefined methods are merely implemented differently under the same name. Within a

redefined method, you can use the pseudoreference SUPER to access the method with the same name in the superclass. It

is always a good idea to call the superclass method that you are redefining before specializing it.

If you define an instance constructor in a subclass, you must call the instance constructor of the superclass by

using CALL METHOD super->constructor in its implementation. Before the call, the subclass constructor behaves like a

static method. It can access only static attributes in that part of the constructor. After the call, it behaves like an instance

method and can also access instance attributes. This is to ensure that the superclass is completely initialized before the

subclass accesses its attributes.

Abstract and final: ABAP Objects also provides ABSTRACT and FINAL clauses like other OO languages. With the

ABSTRACT and FINAL clauses for the METHODS and CLASS statements, you can define abstract and final methods or

classes. When a method is declared abstract, it doesn’t have an implementation in this class, but it expects a subclass to

provide its (specialized) implementation. When a class has one or more abstract methods, the class as a whole becomes

abstract or incomplete. Therefore, you cannot create abstract class objects. The FINAL clause allows you to restrict

inheritance. Final methods cannot be redefined in a subclass, and final classes cannot have any further subclasses.

Polymorphism: Polymorphism is a very important OO concept. Inheritance provides one means of polymorphism. Its

effect is best seen when we consider using objects via a reference variable. Polymorphism means that a reference variable

with the type REF TO vessel can always contain references to instances of any subclass of that class vessel, such as to an

instance of ship or boat. Since a subclass has at least all the components of all its superclasses, you can access all the

components of vessel in any subclass. By using a higher level reference, you simply ignore the components added in

subclasses.

However, the most important part of polymorphism in terms of inheritance is the methods. Consider the example

above: A class ship is inherited from class vessel and has redefined the method drive. When we now have a pointer to an

instance of ship in a reference variable of type REF TO vessel, and we call the method drive, the drive method of the class

ship is executed, even though the reference to that instance is of type REF TO vessel.

The general rule is: When calling a method, the most specialized redefinition (in a subclass) gets called. This method can

then directly call its superclass implementation. Thus, with inheritance, a method call goes as far down as possible, and

your own code must call the implementations of this method upwards. In ABAP Objects, you are only allowed to call a

method’s direct predecessor implementation. You can only go one level up with CALL METHOD SUPER->m, and you

can only call your own method and not other methods of your superclass. (These restrictions are not for technical reasons

but to guide the users of ABAP Objects towards proper use of inheritance.) . Reference variables can always hold

reference to subclass instances. In particular, the root class OBJECT can hold references to any object.

Using the normal method call or attribute access notation, you can only access components of the class that was

used to define the reference variable. Only a dynamic invoke allows the user to access statically unknown methods. For

example, if a subclass ship had an additional method sink, you could not call it statically through a reference of type REF

TO vessel, but you could call it using the dynamic method call.

Listing 4 declares two reference variables, one of type vessel and one of type ship. A class ship object is created.

The IMPORT parameter of its constructor is filled. The object can be accessed by both reference variables. In both cases,

the method drive that is declared in class vessel is called. But you cannot call the method write with reference variable

vessel.

DATA: vessel TYPE REF TO vessel,

ship TYPE REF TO ship.

CREATE OBJECT ship EXPORTING name = 'Titanic'.

CALL METHOD ship->drive( 20 ).

MOVE ship TO vessel.

CALL METHOD vessel->drive( 10 ).

CALL METHOD ship->write.

Listing 4. Using an objects of a subclass.

The implicit calling of methods that are redefined in subclasses means that, with the superclass’s interface, a

method call accesses different method implementations in different subclasses. This has an important consequence: A

subclass should never change the semantics of a method via redefinition. A subclass must always do more than the

superclass but never take anything away.

Interfaces: The public components of a class define the external point of contact for the class. They define the semantic

interface specific to this class. As an illustration, a Customer class would have a CustomerId, and an Order class would

have an OrderId as well as lots of specific methods. However, there are many cases when we want another kind of

polymorphism, one that is independent of inheritance. Consider the following examples:

The ArchiveManager class wants to define what it needs in order to archive a class in a special interface and then

access all different classes uniformly through that interface. It doesn’t care what specific class it is accessing. It only cares

about the archiving aspect. All classes that want to be archived must implement the IF_Archive interface. In the same

way, a WorkflowManager class would define an IF_Workflow interface, and all classes that want to participate in the

workflow must implement this interface.

The general concept of interfaces is this: An interface is a separate language construct that is allowed to define

components (such as in the public section of a class) but without implementation. Classes can implement one or more

interfaces in their public section, thereby extending this section.

Interfaces can also be used to define reference variables of type REF TO interface. These interface references only show

those components that are defined in the interface, regardless of the implementing class. When a class implements an

interface, we can get a reference to any implemented interface by way of simple assignment of the form iref = oref.

Interfaces in ABAP Objects: Like classes, you can define interfaces globally in the class library or locally within an

ABAP program. Interfaces are defined between the INTERFACE and ENDINTERFACE statements. They can contain

the same components as classes. An interface’s methods are not implemented in the interface itself, but must be

implemented in the classes that implement the interface. You do not have to assign the interface components to a visibility

area. Instead, all components automatically belong to the public section of the class implementing the interface.

You implement an interface in a class by using the statement INTERFACES in the public section, which causes

the components of the interface to be added to the public components of that class, all with names of the form intf~comp.

All components of an implemented interface appear within the class with the name prefix intf~. To access a component

comp of an interface within a class or when using a class reference, you must use the name intf~comp. However, when

using an interface reference, you can specify the interface components directly, since the interface reference only shows

the components of that interface. While we use the names intf~comp inside the implementing class, the users of the

interface just write iref->comp.

Implemented interface components are fully equivalent to normal class components. They extend the outer layer

(public section) of the class. All users can access both the class-specific public components as well as the components of

the interface.

One class can implement several interfaces, and each interface can be implemented by many classes. When a

class implements an interface, it immediately has its attributes and events (see Listing 5, page 36), but it must implement

all methods of the implemented interfaces in its implementation part. The interface’s methods can be implemented

differently in each implementing class. Therefore, in addition to inheritance, interfaces provide another means of

polymorphism in ABAP Objects. As for redefined methods with inheritance, the implementation of an interface method

should confirm to the semantics defined in the interface.

INTERFACE status.

METHODS write.

ENDINTERFACE.

CLASS ship DEFINITION

INHERITING FROM vessel.

PUBLIC SECTION.

INTERFACES status.

...

ENDCLASS.

CLASS ship IMPLEMENTATION.

...

METHOD status~write.

DATA id.

id = me->get_id( ).

WRITE: / name,

'is vessel', id,

'and has speed', speed.

ENDMETHOD.

...

ENDCLASS.

CLASS coast_guard DEFINITION.

PUBLIC SECTION.

INTERFACES status.

ALIASES write FOR status~write.

PRIVATE SECTION.

DATA caller TYPE string.

ENDCLASS.

CLASS coast_guard IMPLEMENTATION.

METHOD status~write.

IF caller IS INITIAL.

WRITE:

/ 'Coast guard received no call'.

ELSE.

WRITE:

/ 'Coast guard received a call from',

caller.

ENDIF.

ENDMETHOD.

ENDCLASS.

Listing 5. Defining and implementing interfaces.

Listing 5 defines an interface status. It contains one method, write. The class ship replaces its own method write by

implementing the interface status. Another class, coast_guard, is defined that also implements status. Both classes

implement the interface method status~write.

Nested interfaces: By using the INTERFACES statement within the interface definition, you can define nested interfaces.

When an interface contains a nested component interface, this inner interface appears as one component. The components

of the contained interface are not automatically visible in the enclosing interface. To make a component of a contained

interface component visible on the higher (enclosing) level, you can use the ALIASES statement.

Interface references: Besides reference variables declared with respect to a class, ABAP Objects also provides reference

variables declared with respect to an interface. Those interface reference variables expose only the components defined in

the interface, regardless of the implementing class.

Listing 6, page 36, declares a variable status and an internal table status_tab as interface reference variables. The contents

of two class reference variables, pointing to objects of ship and coast_guard, are appended to that internal table. By

looping on the internal table, the interface method write is accessed in both objects. Listing 6 shows how objects of two

different classes are accessed by reference variables of one kind. Although ships and coast guards do not have much else

in common, the user can expect the same semantics from the interface method write.

DATA: status TYPE REF TO status,

status_tab TYPE TABLE OF REF TO status.

DATA ship TYPE REF TO ship.

DATA station TYPE REF TO coast_guard.

CREATE OBJECT ship

EXPORTING name = 'Titanic'.

APPEND ship TO status_tab.

CREATE OBJECT station.

APPEND station TO status_tab.

LOOP AT status_tab INTO status.

CALL METHOD status->write.

ENDLOOP.

Listing 6. Using Interfaces.

Figure 3, page 34, shows the internal table of interface references pointing to objects of different classes that implement a

common interface.

Figure 3 Using interface references.

Events: Events generally announce that an object’s state has changed or that something happened that may be of interest

to others. They are like outbound method calls and enable a different kind of coupling between objects. They are

especially useful in a GUI environment, but are also good for loosely coupling subsystems and for workflow.

The basic concept of methods is: When one object A calls a method of another object B, A must know B. A must have an

attribute that is a reference to B.

With events, the situation is different: They work by publish and subscribe. One class A defines an event e that

may be of interest to other classes/objects. When class B wants to react to the event e of A, it defines a handler method h

for that event. At run time, an object of B registers its method h as a handler for that event of a sender object of class A.

When the object A now raises event e, all registered handlers for that event are notified or called. The key issue is that a

handler can be attached to do more without changing the sender’s code.

Events in ABAP Objects: Events are another kind of component in classes. They are declared in the declaration part of a

class and raised in its methods. You declare events by using the statements EVENTS for instance events and CLASS-

EVENTS for static events. Events can have EXPORTING parameters to pass parameters from the triggering object to the

handler. Each instance event has an additional implicit parameter called SENDER. The SENDER data type is a reference

variable to the respective sender class.

Static events can be raised in any method of the declaring class, whereas instance events can only be raised in

instance methods. You raise an event in a method using the RAISE EVENT statement, and you pass arguments using the

EXPORTING clause. For instance events, the system automatically passes the implicit parameter SENDER,which is a

reference pointing to the object raising the event.

Any class may contain event handler methods for events of other classes. The event handler method signature

(names and types of parameters) is not repeated but is taken from the event to be handled. However, the event handler

method does not have to accept and use all of the parameters that the event defines. An event handler method can accept

the implicit parameter SENDER like any other IMPORTING parameter, allowing it to access the triggering instance. The

declaration of events and respective event handler methods in classes constitutes the static part of publish and subscribe.

Listing 7, page 38 declares an event emergency_call in class ship. If the attribute speed becomes higher than max_speed

in method drive, the event is raised. A method receive is declared as an event handler in class coast_guard.

CLASS ship DEFINITION

INHERITING FROM vessel.

PUBLIC SECTION.

...

EVENTS emergency_call.

...

ENDCLASS.

CLASS ship IMPLEMENTATION.

...

METHOD drive.

...

IF speed > max_speed.

...

RAISE EVENT emergency_call.

ENDIF.

ENDMETHOD.

...

ENDCLASS.

CLASS coast_guard DEFINITION.

PUBLIC SECTION.

...

METHODS receive

FOR EVENT emergency_call

OF ship IMPORTING sender.

...

ENDCLASS.

CLASS coast_guard IMPLEMENTATION.

...

METHOD receive.

caller = sender->name.

CALL METHOD write.

ENDMETHOD.

...

ENDCLASS.

Listing 7. Declaring raising, and handling events.

Handling events: If you declare an event handler method in a class, the instances of the class, or the class itself, are then

capable of handling the event. If you want an event handler method to react to an event, you must define at run time the

trigger to which you want it to respond with the SET HANDLER statement. It links a list of handler methods to

corresponding event triggers—either instance events or static events. The SET HANDLER statement also has an addition

ACTIVATION, which allows you to register and deregister handlers dynamically. Triggering events in methods and

registering event handler methods at run time constitutes the dynamic part of publish and subscribe.

Listing 8 registers the method receive in an instance of class coast_guard as a handler for the event emergency_call in an

instance of class ship.

DATA: ship TYPE REF TO ship,

station TYPE REF TO coast_guard.

CREATE OBJECT: ship

EXPORTING name = 'Titanic'.

station.

SET HANDLER station->receive FOR ship.

DO 5 TIMES.

CALL METHOD ship->drive( 10 ).

ENNDO.

Listing 8. Registering handler methods for events.

For each SET HANDLER statement, the system creates an entry in an event handler table (see Figure 4, page 38), where a

handler table belongs to each instance or class that can trigger instance or static events. It is invisible to the user and

contains the names of the handler methods and references to the registered handling instances. When an event is triggered,

the system searches the event handler table of the corresponding object or class and executes the listed methods in their

instances in the case of instance handler methods, or classes in the case of static handler methods. You can delete single

entries from the handler table using the ACTIVATION addition of the SET HANDLER statement. If the triggering

instance is deleted by the garbage collector, the entire handler table, including all its references, is deleted.

Figure 4 Event handler table of an object.

A reference to an instance in a handler table counts as a use of the instance, just as a reference in a reference

variable does. Handler table entries, therefore, affect the lifetime of objects. This means that in our example, the instance

j<coast_guard> is not deleted by the garbage collector as long as it is registered for event handling, even if the reference

variable station is cleared.

Finally, events, as well as their handler methods, can also be defined in interfaces. Additionally, there are some

powerful mass registration variants to register a handler for all instances of a class and all classes implementing a certain

interface.

Jùrgen Heymann is senior developer in the SAP ABAP Language Group. He is a key architect in the ABAP

Objects project. You can reach him at [email protected].

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

[email protected].

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

Polymorphism: 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).

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

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

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

[email protected].

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 [email protected].