reach parent method using Objects type inheritance - oracle

I have Object B child of Object A. In object B I would like to call a method from Object A.
It looks like in Oracle 11 we can use this :
(SELF AS parent_object).parent_method
But I work with Oracle 10 and this does not work. Is there another way ?
Thank you
PS : I want to do that in the CONSTRUCTOR METHOD (maybe it changes something)

You're right, this feature was introduced in 11.1, as mentioned in What's New in Object-Relational Features?.
The 10g manual also talks about this limitation. The best available workaround is to create a static supertype method:
When implementing methods using PL/SQL, you cannot call a supertype
object method with the super keyword or an equivalent method in
derived objects that have overriding methods. However, you can call a
static supertype method as a workaround. See the examples in "Creating
Subtypes With Overriding Methods" for the definition of the supertype
and subtype functions.

With extreme care (it means, that whatever you will do to prevent problems, in future you anyway will get a lot of pain in different parts of your body) you can cast child type to parent type and call its methods.
Extreme care is needed because, of course, you will lose any changes made on member fields by call to this method. So you can use such way only with base methods that does not change member fields of type.
create type type_1 as object (
field1 number(1)
,member procedure init
) not final;
/
create or replace type body type_1 as
member procedure init as
begin
field1 := 0;
dbms_output.put_line('init works! Field1 = ' || field1);
end;
end;
/
create type type_2
under type_1 (
field2 number(1)
,constructor function type_2(self in out type_2, arg number) return self as result
);
/
create or replace type body type_2 as
constructor function type_2(self in out type_2, arg number) return self as result as
parent type_1;
begin
self.field2 := arg;
self.field1 := -1;
select self
into parent
from dual;
parent.init();
dbms_output.put_line('Child''s field1 = ' || self.field1);
return;
end;
end;
/
declare
child type_2 := type_2(2);
begin
return;
end;
/

Related

PLSQL - Check if an object exists in a table of objects - type has no map

I have a procedure that has got this variables of type table of objects:
lsa_final_filter_ports t_modifylink_multicolumnlist;
lsa_initial_filter_ports t_modifylink_multicolumnlist;
Definition of t_modifylink_multicolumnlist is:
CREATE OR REPLACE TYPE "T_MODIFYLINK_MULTICOLUMNLIST" IS TABLE OF o_modifylink_multicolumnlist;
TYPE o_modifylink_multicolumnlist AS OBJECT(some properties);
lsa_final_filter_ports variable is populated like this
SELECT b.name INTO ls_bandwidth_name FROM bandwidth b
WHERE b.bandwidthid = lna_compatible_port_bw(i);
SELECT CAST(MULTISET(SELECT *
FROM TABLE(piosa_all_ports)
WHERE ITEMNAME4 = ls_bandwidth_name)
AS t_modifylink_multicolumnlist)
INTO lsa_final_filter_ports
FROM dual;
Where piosa_all_ports is I/O parameter having same type t_modifylink_multicolumnlist
Second parameter is initialized at the beginig of procedure with a second I/O parameter that the procedure has
lsa_initial_filter_ports := piosa_filtered_ports;
What I want to achieve is to check if an object from lsa_final_filter_ports exists in lsa_initial_filter_ports and if so then skip adding that object in lsa_initial_filter_ports which will be an output parameter used by the outside calling procedure.
What I've tried is iterating through lsa_final_filter_ports objects and checking if that object already exists like this:
FOR i in 1..lsa_final_filter_ports.COUNT LOOP
IF lsa_final_filter_ports(i) MEMBER OF lsa_initial_filter_ports THEN
CONTINUE;
END IF;
lsa_initial_filter_ports.EXTEND();
lsa_initial_filter_ports(lsa_initial_filter_ports.COUNT) := lsa_final_filter_ports(i);
END LOOP;
But with this code I'm getting the following error:
Error: PLS-00801: internal error [*** ASSERT at file pdw4.c, line
2181; Type 0x0x7f991127aef8 has no MAP method.;
NR_WIZARDVALIDATIONS__CUSTOMISATIONS__B__166833[33]
I'm not sure if this kind of comparation can be made, maybe someone can clarify this.
Thank you
Unfortunately, if you have objects in PlSql, which only exist in RAM (that means those, that are NOT stored persistently in a table), assigning them to another variables always causes a (deep) copy of the origin object.
(which is really a problem, if you often assign objects with nested objects to working-variables and back to the collection ...)
Therefore, you´ll never will be able to compare two (copies) of the same object on object-pointer level.
Only thing you can do, is comparing some unique attributes of the objects.
Let´s say, you´ll have an ID in your piosa_all_ports, then you might modify your loop above with the comparison in something similar to this:
v_exists integer;
FOR i in 1..lsa_final_filter_ports.COUNT LOOP
select nvl(max(1),0)
from table(lsa_initial_filter_ports) x
where x.id = lsa_final_filter_ports(i).id;
if (v_exists = 0) then
lsa_initial_filter_ports.EXTEND();
lsa_initial_filter_ports(lsa_initial_filter_ports.COUNT) := lsa_final_filter_ports(i);
end if;
END LOOP;
(rem.: i know, that switching PlSql- and SQL-Context in sample above is time-consuming, but otherwise, you have to write a function that tests the existance of an ID by iterating the whole list)

Pascal passing object of inheritance class to procedure

I have types declared as:
TPlayer = class(TObject)
TBullet = class(TObject)
TEnemy = class(TObject)
and objects:
Player: TPlayer;
PlayerBullets: Array[1..20] of TBullet;
Enemies: Array[1..20] of TEnemy;
EnemyBullets: Array[1..20] of TBullet;
Now I want to create TBullet constructor, which can process informations from both Player and Enemies. In short, I want this constructor to handle both TPlayer and TEnemy objects.
My idea is:
constructor TBullet.Create(const Source: TObject);
Sadly it does not work. How to do this?
EDIT:
My exact problem is: when I pass TPlayer or TEnemy object to this constructor it doesn't see atributes of those objects. For example: TPlayer has attr xPos. If I use Bullet.Create(Player) and in TBullet.Create I use Source.xPos I get an error.
I can think of 3 ways to achieve that.
Have TPlayer and TEnemy both derive from the same base class that have all the information TBullet's constructor need, and have the constructor parameter of that type.
Define an interface contains all the information needed by TBullet and have TPlayer and TEnemy implement that interface
Leave everything "as is" and manage the different class in a "hard coded" manner in TBullet's constructor.
By that I mean:
constructor TBullet.Create(const Source: TObject);
var
vPlayer : TPlayer;
vEnemy : TEnemy;
begin
if Source is TPlayer then
begin
vPlayer := TPlayer(Source);
[Do whatever with vPlayer]
end else if Source is TEnemy then
begin
vEnemy := TEnemy(Source);
[Do Whatever with vEnemy]
end;
end;
Which solution is the best? That could be a debate in itself and largely dependant on your specific situation. Based solely on the name of your class, I'd guess option 1 could be valid. A "TCharacter" class could be created and use as a base calss for both TCharacter and TEnemy. But this is mere speculation at this point.
In windows there is little difference in inheriting from a parent with the common methods (could be abstract in the parent ) or implementing an interface (when again the behavior could be customized ).
If you have an enumeration commonParticipant( cpPlayer, cpEnemy) then Windows allows access to the ultimate parent IUnknown and then down again to a child interface that identifies the methods peculiar to that child, i.e. you can pass an ICommonParticipant including the commonParticipant and then work with either a iPlayer or IEnemy interface

Why use extra procedure to initialize values instead of doing it in constructor?

So i've been going trough types at my new work and they pretty much all look like this
create or replace TYPE BODY T_Some_Type AS
CONSTRUCTOR FUNCTION T_Some_Type
RETURN SELF AS RESULT AS
BEGIN
INTIALIZE();
RETURN;
END T_Some_Type;
MEMBER PROCEDURE INTIALIZE AS
BEGIN
var1 := 0;
var2 := 0;
var3 := 0;
END INTIALIZE;
END;
Being skilled in OOP but new to pl/sql, i keep wondering why use extra procedure to initialize variables, when it can be done directly in constructor making objects interface simpler and lighter on memory.
This is how i would normally do it :
create or replace TYPE BODY T_Some_Type AS
CONSTRUCTOR FUNCTION T_Some_Type
RETURN SELF AS RESULT AS
BEGIN
var1 := 0;
var2 := 0;
var3 := 0;
RETURN;
END T_Some_Type;
END;
Is there any advantage or this is recommended for some reason?
Please advise.
Please bear in mind that the object features in Oracle have evolved slowly since version 8.0, and yet are still pretty limited in some respects. This is because Oracle is a relational database with a structured and procedural programming paradigm: object-orientation is not a good fit.
So. In a language like Java we can override a method in a sub-type but execute the code in the parent's implementation with a super() call.
Before 11g Oracle had no similar mechanism for extending member functions. If we wanted to override a super-type's method we had to duplicate the code in the sub-type, which was pretty naff. There was a workaround which is not much less naff: extract the common code into a separate method in the super-type, and call that method in the super- type and its dependents.
In 11g Oracle introduced "Generalized Invocation". This allows us to call super-type code on a sub-type. Find out more. There is one major limitation with Generalized Invocation, and that is that we cannot use it with Constructor methods. Therefore, in its sub-types' constructors too our only choice is to put that code in a method like the initialize() in your question.

Inheritance in FreePascal Lazarus

I'm learning free pascal using the Lazarus IDE and I don't know how to inheritance methods in the derived form.
I want something like this:
Form base or father:
procedure HelloWorld;
begin
ShowMessage('Hello World from base form or father');
end;
and form derived or child:
procedure HelloWorld;
begin
inherited;
ShowMessage('Hello World from derived form or child');
end;
I want the result shows 2 messages by clicking (e.g Button1)
Thanks!!!
For a better appreciation of the Object Pascal language, i believe you should start by reading the freepascal reference guide. FreePascal is the underlaying compiler below lazarus.
Its important to understand that Forms, Labels, Buttons, etc, are specific incarnations of the concepts of objects, instances, classes etc.
In that regard, a class is a structure binding code and data. What you want to achieve is something like this :
Type
TMyClass = Class(<ancestorclass>)
<fields and methods>
End;
TMyChildClass = Class(TMyClass)
<fields and methods>
End;
This means that TMyChildClass is a class derived from TMyClass. In the event that you have methods in both classes with same name, you can use the keyword "override" to show the compiler that that method was overriden by the child class, like this :
TMyClass = Class /* No parenthesis or ancestor name means the class derives from TObject */
Procedure ParentMethod;
End;
TMyChildClass = Class(TMyClass)
Procedure ParentMethod; Override;
End;
Procedure TMyClass.ParentMethod;
Begin
DoSomething;
End;
Procedure TMyChildClass.ParentMethod; /* Dont repeat the override */
Begin
Inherited; // This will call the parents method
End;
This is the proper way to do method override in object pascal. If the definition of the class where you want to use "inherited" has no parenthesis and the name of the ancestor class, theres no ancestry relation between then and inherited will not do what you are expecting to do.
In Pascal procedure is not an object oriented programming construct.
FreePascal includes objects and objects can include procedures:

Delphi Interface Performance Issue

I have done some really serious refactoring of my text editor. Now there is much less code, and it is much easier to extend the component. I made rather heavy use of OO design, such as abstract classes and interfaces. However, I have noticed a few losses when it comes to performance. The issue is about reading a very large array of records. It is fast when everything happens inside the same object, but slow when done via an interface. I have made the tinyest program to illustrate the details:
unit Unit3;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
const
N = 10000000;
type
TRecord = record
Val1, Val2, Val3, Val4: integer;
end;
TArrayOfRecord = array of TRecord;
IMyInterface = interface
['{C0070757-2376-4A5B-AA4D-CA7EB058501A}']
function GetArray: TArrayOfRecord;
property Arr: TArrayOfRecord read GetArray;
end;
TMyObject = class(TComponent, IMyInterface)
protected
FArr: TArrayOfRecord;
public
procedure InitArr;
function GetArray: TArrayOfRecord;
end;
TForm3 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form3: TForm3;
MyObject: TMyObject;
implementation
{$R *.dfm}
procedure TForm3.FormCreate(Sender: TObject);
var
i: Integer;
v1, v2, f: Int64;
MyInterface: IMyInterface;
begin
MyObject := TMyObject.Create(Self);
try
MyObject.InitArr;
if not MyObject.GetInterface(IMyInterface, MyInterface) then
raise Exception.Create('Note to self: Typo in the code');
QueryPerformanceCounter(v1);
// APPROACH 1: NO INTERFACE (FAST!)
// for i := 0 to high(MyObject.FArr) do
// if (MyObject.FArr[i].Val1 < MyObject.FArr[i].Val2) or
// (MyObject.FArr[i].Val3 < MyObject.FArr[i].Val4) then
// Tag := MyObject.FArr[i].Val1 + MyObject.FArr[i].Val2 - MyObject.FArr[i].Val3
// + MyObject.FArr[i].Val4;
// END OF APPROACH 1
// APPROACH 2: WITH INTERFACE (SLOW!)
for i := 0 to high(MyInterface.Arr) do
if (MyInterface.Arr[i].Val1 < MyInterface.Arr[i].Val2) or
(MyInterface.Arr[i].Val3 < MyInterface.Arr[i].Val4) then
Tag := MyInterface.Arr[i].Val1 + MyInterface.Arr[i].Val2 - MyInterface.Arr[i].Val3
+ MyInterface.Arr[i].Val4;
// END OF APPROACH 2
QueryPerformanceCounter(v2);
QueryPerformanceFrequency(f);
ShowMessage(FloatToStr((v2-v1) / f));
finally
MyInterface := nil;
MyObject.Free;
end;
end;
{ TMyObject }
function TMyObject.GetArray: TArrayOfRecord;
begin
result := FArr;
end;
procedure TMyObject.InitArr;
var
i: Integer;
begin
SetLength(FArr, N);
for i := 0 to N - 1 do
with FArr[i] do
begin
Val1 := Random(high(integer));
Val2 := Random(high(integer));
Val3 := Random(high(integer));
Val4 := Random(high(integer));
end;
end;
end.
When I read the data directly, I get times like 0.14 seconds. But when I go through the interface, it takes 1.06 seconds.
Is there no way to achieve the same performance as before with this new design?
I should mention that I tried to set PArrayOfRecord = ^TArrayOfRecord and redefined IMyInterface.arr: PArrayOfRecord and wrote Arr^ etc in the for loop. This helped a lot; I then got 0.22 seconds. But it is still not good enough. And what makes it so slow to begin with?
Simply assign the array to a local variable before iterating through the elements.
What you're seeing is that the interface methods calls are virtual and have to be called through an indirection. Also, the code has to pass-through a "thunk" that fixes up the "Self" reference to now point to the object instance and not the interface instance.
By making only one virtual method call to get the dynamic array, you can eliminate that overhead from the loop. Now your loop can go through the array items without the extra overhead of the virtual interface method calls.
You're comparing oranges with apples, as the first test reads a field (FArr), while the second test reads a property (Arr) that has a getter assigned with it. Alas, interfaces offer no direct access to their fields, so you really can't do it any other way than like you did.
But as Allen said, this causes a call to the getter method (GetArray), which is classified as 'virtual' without you even writing that because it's part of an interface.
Thus, every access results in a VMT-lookup (indirected via the interface) and a method call.
Also, the fact that you're using a dynamic array means that both the caller and the callee will do a lot of reference-counting (you can see this if you take a look at the generated assembly code).
All this is already enough reasons to explain the measured speed difference, but can indeed easily be overcome using a local variable and read the array only once. When you do that, the call to the getter (and all the ensueing reference counting) is taking place only once. Compared to the rest of the test, this 'overhead' becomes unmeasurable.
But note, that once you go this route, you'll loose encapsulation and any change to the contents of the array will NOT reflect back into the interface, as arrays have copy-on-write behaviour. Just a warning.
Patrick and Allen's answers are both perfectly correct.
However, since your question talks about improved OO design, I feel a particular change in your design that would also improve performance is appropriate to discuss.
Your code to set the Tag is "very controlling". What I mean by this is that you're spending a lot of time "poking around inside another object" (via an interface) in order to calculate your Tag value. This is actually what exposed the "performance problem with interfaces".
Yes, you can simply deference the interface once to a local variable, and get a massive improvement in performance, but you'll still be poking around inside another object. One of the important goals in OO design is to not poke around where you don't belong. This actually violates the Law of Demeter.
Consider the following change which empowers the interface to do more work.
IMyInterface = interface
['{C0070757-2376-4A5B-AA4D-CA7EB058501A}']
function GetArray: TArrayOfRecord;
function GetTagValue: Integer; //<-- Add and implement this
property Arr: TArrayOfRecord read GetArray;
end;
function TMyObject.GetTagValue: Integer;
var
I: Integer;
begin
for i := 0 to High(FArr) do
if (FArr[i].Val1 < FArr[i].Val2) or
(FArr[i].Val3 < FArr[i].Val4) then
begin
Result := FArr[i].Val1 + FArr[i].Val2 -
FArr[i].Val3 + FArr[i].Val4;
end;
end;
Then inside TForm3.FormCreate, //APPROACH 3 becomes:
Tag := MyInterface.GetTagValue;
This will be as fast as Allen's suggestion, and will be a better design.
Yes, I'm fully aware you simply whipped up a quick example to illustrate the performance overhead of repeatedly looking something up via interface. But the point is that if you have code performing sub-optimally because of excessive accesses via interfaces - then you have a code smell that suggests you should consider moving the responsibility for certain work into a different class. In your example TForm3 was highly inappropriate considering everything required for the calculation belonged to TMyObject.
your design use huge memory. Optimize your interface.
IMyInterface = interface
['{C0070757-2376-4A5B-AA4D-CA7EB058501A}']
function GetCount:Integer:
function GetRecord(const Index:Integer):TRecord;
property Record[Index:Integer]:TRecord read GetRecord;
end;

Resources