Inherit the Database: Oracle9i's Support for Object Type Inheritance
Pages: 1, 2, 3, 4, 5
Options for Method Definition
You can define or make available methods in object types in the following ways:
Inherit a method: If the method is defined in any supertype in the hierarchy, that method is automatically available for use with the current type. You don't need to write any additional code in the object-type definition.
Create a new method: You can always create an entirely new method in an object type, one that doesn't appear in any supertype. You can, by the way, create
STATICmethods that are associated with the object type and not with any object instantiated from the object type.Overload a supertype method: You can create a method that has the same name as a method in a supertype, but has either a distinct parameter list or a different method type (function vs. procedure, for example). This constitutes an overloading (or static polymorphism) of the supertype method in the subtype.
Override a supertype method: You can also replace or substitute a supertype method in your subtype by specifying
OVERRIDING MEMBERin the header definition.
Overloading has, of course, been available for years in PL/SQL. You can overload multiple programs with the same name in packages (the most common location for overloading) and any declaration section in a block.
The interesting aspect of overloading in object types is that you might be overloading a method from a supertype. In this case, you can't actually tell by looking at the subtype definition that what you've done is an overloading. It's the only program with that name present. You have to be able to examine the entire hierarchy to discover the overloading. Consider the object type for corporation shown in Listing 3.
Listing 3. Object type for corporation.
CREATE OR REPLACE TYPE corporation_ot
UNDER person_ot (
CEOcompensation NUMBER,
layoffs NUMBER,
MEMBER procedure maximizeProfits,
-- Show a corporation
OVERRIDING MEMBER procedure show ,
-- override of generic method.
OVERRIDING MEMBER procedure showPunishment,
-- implementation of non-instantiable method
OVERRIDING MEMBER procedure showPoliticalPower,
MEMBER FUNCTION age (merger_date_in IN DATE)
RETURN INTERVAL YEAR TO MONTH
)
INSTANTIABLE
NOT FINAL;
/
I've added an overloading of the age function (the person_ot contains the "original" age program). For corporations, I allow you to specify a merger date. If NOT NULL, then the computation of the age of the corporation changes from the default person age function.
Here's a comparison of the two implementations, first the person age function:
MEMBER FUNCTION age
RETURN INTERVAL YEAR TO MONTH
IS
retval INTERVAL YEAR TO MONTH;
BEGIN
RETURN (SYSDATE - SELF.dob)
YEAR TO MONTH;
END;
and now the corporation's age function:
MEMBER FUNCTION age (
merger_date_in IN DATE)
RETURN INTERVAL YEAR TO MONTH
IS
retval INTERVAL YEAR TO MONTH;
BEGIN
IF merger_date_in > SELF.dob
THEN
RETURN (SYSDATE - merger_date_in)
YEAR TO MONTH;
ELSE
RETURN (SYSDATE - SELF.dob)
YEAR TO MONTH;
END IF;
END;
In other words, if a merger date is provided, use that to calculate the age of the
corporation. Otherwise, rely on the "date of birth" of the corporation, obtained from the
person-defined attribute. I do not include the OVERRRIDING keyword in my definition of this function since it isn't overriding the person.age function. Instead, corporation.age offers a second, overloaded implementation.
Remember that in my hierarchy, person is a supertype of corporation. I've defined a method in person to return the age of a person.
Interestingly, I can invoke either one of the age functions against a corporation object
as shown here:
DECLARE
oracle corporation_ot :=
corporation_ot (
'Artificial', -- species
'Oracle Corporation',
NULL,
'01-JAN-1979',
NULL,
NULL
);
BEGIN
IF -- person.age
oracle.age
>
-- corporation.age
oracle.age (SYSDATE)
THEN
DBMS_OUTPUT.PUT_LINE (
'Impossible!');
END IF;
END;
A Closer Look at Method Overriding
When you override an inherited method, you define a method in a subtype of the same name and have that method do something different from the supertype's version.
The compensation calculation for a manager will be different, for example, from that of other employees, so a specialized program will be needed in that object-type definition.
When a subtype overrides a method, then instances of the subtype will invoke that method rather than the overridden one. If the subtype itself has subtypes, those more specific types inherit the override of the method instead of the version of the supertype.
You'll only successfully override a method if your subtype's OVERRIDING member
definition contains precisely the same signature (name, parameter list, RETURN clause if
a function) as the supertype method. If the signature is different, then you've defined an
overloading rather than an overriding method.
Keep the following restrictions in mind when you're figuring out when and how to overload methods:
You can override only methods that aren't declared to be final in the supertype.
Order methods (methods used to provide a sense of order or sequence to objects instantiated from the type) may be defined only in the root type of a type hierarchy. You can't override these methods.
You can't define an overridden method as a static method (one that's associated with the type itself and not with an object instantiated from the type).
A member method in a subtype isn't permitted to override a static method in the supertype.
If a method being overridden contains default values for parameters, then the overriding method must provide the same default values for the same parameters. The header of the programs must be entirely identical.
Polymorphism and Dynamic Method Dispatch
Polymorphism is the name given to a language's ability to choose from multiple methods of the same name and execute the appropriate method. There are two kinds of polymorphism:
Static polymorphism: The decision about which method to execute is made at the time the code is compiled. In PL/SQL, static polymorphism is also known as overloading.
Dynamic polymorphism: The decision about which method to execute is made at the time the code is executed, at runtime. This is also known as dynamic method dispatch and is available for the first time in PL/SQL with support for object-type inheritance.
Both types of polymorphism are very powerful features. Static polymorphism or
overloading makes it easy for us to create simple, intuitive APIs or application
programmatic interfaces for developers to use. Rather than having to remember 10
different names for "define a dynamic SQL column," for example, I can simply call the
DBMS_SQL.DEFINE_COLUMN procedure; the PL/SQL compiler automatically figures
out which program I need to run based on the parameter list.
Dynamic polymorphism is dramatically more useful and intriguing because it gives us so much more flexibility in the way we manipulate our objects. Suppose my PL/SQL block invokes a method on a type. The execution engine then uses the type of the object instance that invokes it to determine which implementation of the method to use. There can be multiple implementations due to either overloading or overriding. The call is then dispatched to that type's implementation for execution. This process of selecting a method implementation is called dynamic method dispatch since it's done at runtime, not at compile time.
PL/SQL dispatches a method call to the "nearest" implementation, working up the inheritance hierarchy from the current or specified type to its supertypes, if any.



