Oracle Objects, Types and Collections: Part 3
In Part 1 of this series, we talked about how Oracle objects compare to Java and how to create Oracle Objects. In Part 2, I covered we covered object comparison and type inheritance. Today, we’ll talk about polymorphism and type evolution.
Like parts 1 and 2, this will be a technical discussion.
First a definition. What is Polymorphism and why is it important? One of the best definitions I have found is this link at OnJava. You can skip the part about object serialization. Not really that important to Oracle’s OO as you’re already in the database.
Let’s go back to our (most basic) calculator example.
CREATE OR REPLACE TYPE Calculator AS OBJECT ( value NUMBER, MEMBER PROCEDURE print, MEMBER PROCEDURE add1( p_amt IN NUMBER ), MEMBER PROCEDURE subtract( p_amt IN NUMBER ) ) NOT FINAL; / CREATE OR REPLACE TYPE BODY Calculator AS MEMBER PROCEDURE print IS BEGIN DBMS_OUTPUT.PUT_LINE( TO_CHAR( value ) ); END; MEMBER PROCEDURE add1( p_amt IN NUMBER ) IS BEGIN value := value + p_amt; END; MEMBER PROCEDURE subtract( p_amt IN NUMBER ) IS BEGIN value := value - p_amt; END; END; /
And our Advanced Calculator:
CREATE OR REPLACE TYPE AdvancedCalculator UNDER Calculator ( pi FLOAT, CONSTRUCTOR FUNCTION AdvancedCalculator RETURN SELF AS RESULT , MEMBER PROCEDURE multiply( p_amt IN NUMBER ), MEMBER PROCEDURE divide( p_amt IN NUMBER ), OVERRIDING MEMBER PROCEDURE print ) NOT FINAL; /
This isn’t exactly the same AdvancedCalculator. Notice the OVERRIDING keyword. I’m overriding the print method in the subtype AdvancedCalculator.
And let’s create a new body for our subtype and change the print method to include data about the attribute pi:
CREATE OR REPLACE TYPE BODY AdvancedCalculator AS CONSTRUCTOR FUNCTION AdvancedCalculator RETURN SELF AS RESULT IS BEGIN SELF.value := 0; self.pi := 3.14159; RETURN; END; MEMBER PROCEDURE multiply( p_amt IN NUMBER ) IS BEGIN value := value * p_amt; END; MEMBER PROCEDURE divide( p_amt IN NUMBER ) IS BEGIN value := value / p_amt; END; OVERRIDING MEMBER PROCEDURE print IS BEGIN DBMS_OUTPUT.PUT_LINE( 'Value: ' || TO_CHAR( value ) || ', Pi: ' || TO_CHAR( pi ) ); END; END; /
And a demo script:
DECLARE calc Calculator; calc1 AdvancedCalculator; calc2 AdvancedCalculator; BEGIN calc := Calculator(1); calc1 := AdvancedCalculator(); calc2 := AdvancedCalculator(); calc.print; calc1.print; calc2.print; calc.add1(5); calc1.add1(5); calc2.add1(5); calc.print; calc1.print; calc2.print; END; /
At it’s most basic, that is polymorphism. We defined a base type and some basic functionality. We then defined a subtype and while most of its functionality applied, we needed to make a minor change to the print method. We did this by OVERRIDING the print method.
Like most examples, this one is somewhat pointless except to describe how to implement polymorphism. If you look back at the link above, they mentioned the standard Shape example and calculating area. In a business process, you might have different types of transactions with different billing calculations. Polymorphism doesn’t look useful until you need it.
This could have been implemented by implementing a new method in the subtype, print1 or printAdvanced or something along those lines but if you did that, you would defeat the whole purpose of using objects. You, the programmer, would have to keep track of each type and decide programmatically which kind of print method to call. In this example, that would be pretty easy but in the real world with thousands of lines of code and multiple sub-types, it would get messy.
I’m going to leave the definition of polymorphism here for now. In Part 4, I will show some of the power of this when I get into using object views.
I wanted to talk about this because it has important aspects for maintenance of an application. In Oracle 8i, the first version I used OO in Oracle, you had to drop and recreate your types to make changes. What a PITA that was. It was particularly annoying when you used a type in an AQ queue and then wanted to change it. Arghh!
Well, in 10g, you can change a type within some limitations.
Using our calculator examples, let’s change some items.
alter type advancedcalculator drop member procedure print /
Note: If you get an ORA-21700, just disconnect and reconnect. I’m not sure why that happens but reconnecting fixes it for me. Metalink gives a few possibilities but it seems to be a caching issue for me.
When you alter the type, you have to recompile the body. Since we’re dropping a method, we need to modify the code to not include the print method:
CREATE OR REPLACE TYPE BODY AdvancedCalculator AS CONSTRUCTOR FUNCTION AdvancedCalculator RETURN SELF AS RESULT IS BEGIN SELF.value := 0; self.pi := 3.14159; RETURN; END; MEMBER PROCEDURE multiply( p_amt IN NUMBER ) IS BEGIN value := value * p_amt; END; MEMBER PROCEDURE divide( p_amt IN NUMBER ) IS BEGIN value := value / p_amt; END; END; /
This removes the print procedure from the subtype. Do a desc on AdvancedCalculator.
Whoa! It’s still there. But is it? Run our demo script from the polymorphism example above.
Remember, we had overridden the print method from its supertype. By removing it from the sub-type, it still exists in the supertype and is still available to the subtype.
Let’s remove the subtract method from the supertype:
alter type calculator drop member procedure subtract( p_amt IN NUMBER ) CASCADE /
Recompile the body without the subtract procedure:
CREATE OR REPLACE TYPE BODY Calculator AS MEMBER PROCEDURE print IS BEGIN DBMS_OUTPUT.PUT_LINE( TO_CHAR( value ) ); END; MEMBER PROCEDURE add1( p_amt IN NUMBER ) IS BEGIN value := value + p_amt; END; END; /
Do a desc on advancedcalculator. On my system, I could still see the method subtract and had to disconnect and reconnect to get rid of it. It definitely looks like there are caching issues with types.
Anyway, the CASCADE option alters the subtype in addition to the supertype. By changing the supertype, the subtype evolved. Compared to 8i this is awesome.
Again, I’m going to stop here but in Part 4 I will cover object views and object tables and you will see in greater detail how polymorphism and type evolution works.
Just to clarify: Polymorphism is the ability of a subtype to change, or morph, its behavior without changing the supertype or other subtypes of the supertype and type evolution is the ability to evolve a type that has dependencies.
I tried to be brief but hopefully I wasn’t so brief that this isn’t useful. The two topics today are really intros to part 4 where we can finally get into the meat of OO. Object Views are useful in everyday development. Object Tables are less so but like I say, I’d rather have it available and not use it than need it and not have it.
You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings are currently closed.