I want to make an oracle object return itself and be able to chain these calls. How do I do that?
I have tried returning the same type, but it doesnt work, I also tried adding a procedure that is invoqued by the funcition but it doesn't work either. Always complains about modifying the value of the width member. Looks like functions wont admit side effects?, are they modelled after a more mathematical function principle? Is this achievable?. I guess I could write the function so it builds a new rectangle with SELF, but that is so much work.
My goal is to be able to chain calls like jQuery or some java classes (a singleton?). Something like:
r := r.setWidth(0).setWidth(1).setWidth(2);
Of course, it would have more methods and it wouldn't be a rectangle. This is the error:
Error: PLS-00363: expression 'SELF' cannot be used as an assignment target
Line: 18
Text: stWidth(w);
-
CREATE OR REPLACE TYPE rectangle AS OBJECT
(
-- The type has 3 attributes.
length NUMBER,
width NUMBER,
area NUMBER,
-- Define a constructor that has only 2 parameters.
CONSTRUCTOR FUNCTION rectangle(length NUMBER, width NUMBER)
RETURN SELF AS RESULT,
MEMBER FUNCTION setWidth(w NUMBER) RETURN rectangle,
MEMBER PROCEDURE stWidth(w NUMBER)
)
-
CREATE OR REPLACE TYPE BODY rectangle AS
CONSTRUCTOR FUNCTION rectangle(length NUMBER, width NUMBER)
RETURN SELF AS RESULT
AS
BEGIN
SELF.length := length;
SELF.width := width;
-- We compute the area rather than accepting it as a parameter.
SELF.area := length * width;
RETURN;
END;
MEMBER PROCEDURE stWidth(w NUMBER) IS
BEGIN
self.width := w;
END;
MEMBER FUNCTION setWidth(w NUMBER) RETURN rectangle IS
BEGIN
stWidth(w);
RETURN SELF;
END;
END;
Thanks in advance.
You can't return SELF from a member function. You can create a copy, but I'm not sure why a setwidth function would return a rectangle object. I know this basic example probably came from some old Oracle docs, but I would not put a computed field (area) as an attribute. If its computed, it should be a member function (or procedure). Reason is that unless you want to always remember to update area in functions that affect area, you'll shoot yourself in the foot. Your example is broken (aside from the setWidth returning self), since only the constructor calculates area.
Output:
Obviously this is incorrect. I would do something like:
And this way you'd have:
Output:
You cannot both change the object and assign to it at the same time. You already know the solution, "build a new rectangle with SELF". But it won't be a lot of work.
Replace this:
with this:
You were actually getting a compilation error. By default,
SELF
is anIN
parameter. The call tostWidth
failed because it was modifying anIN
parameter withself.width := w;
.See: http://docs.oracle.com/cd/B28359_01/appdev.111/b28371/adobjbas.htm#CHDCFEEE
I have run into the same problem, and since the top answers disagree, I had to experiment myself.
I have the following code that won't work despite what Antonio's answer says:
The following code will not run no matter whether you the
self
parameter is defined withnocopy
or not.If
print_value
is redefined to bemember procedure print_value(self in tst)
, thentst().print_value;
becomes a valid statement.The constructor scannot be chained if the self parameter is
in out
orin out nocopy
, no matter if you return a copy orself
, you'll always get aPLS-00363
. The only way to run nested calls off a constructor is to useself in
parameters everywhere and make a copy, which is disappointing:Then this prints
TEST
as expected:If you can split the statement into
t := tst(); t.update_value('TEST').print_value;
, then it works even within out nocopy
self
parameters.Sorry, I am a bit late, but the other answers are incorrect, at least using Oracle 11gR2, and what you are trying to achieve is entirely possible indeed.
I just have recently stumbled upon the problem and I see one can definitively return a reference to
SELF
exactly as you were trying to, without yielding to any trade-off or applying workarounds.The only thing one needs is to redefine the method by (explicitly) setting the (implicit)
SELF
parameter asSELF IN OUT rectangle
.The
SELF
is the leading parameter that is silently passed to every object method, and for functions is defined asIN
(immutable; this is what presumably makes the compiler complain). This is sort of established at compile time, but the good part is that when invoking the method you can omit it.In the example at the end of the post (slightly rewritten from yours), we define a
and we execute it omitting the
SELF
reference:Note that there are two warnings to be aware of.
warning 1
Every method call will temporarily create a fresh copy of the object.
But just temporarily, the new instance is short lived, just between the start and the end of the method. This is inherent to using
IN OUT
parameters on all functions or procedures, and is not specific to object types. If you want to prevent this behaviour, you may want to redefine the signature of your function using theNOCOPY
hint:See ORACLE-BASE - NOCOPY for more details. Note it is a hint however, that doesn't assure you are finally using the same object reference and not a newly created object, so use with caution.
warning 2
Given you have raised this question, chances are that you have a OOP background, and you may get a surprise when trying to invoke the method without using the returned reference like this
The compiler will return an error:
So what is happening here? Well, the so called "static polymorfism" (i.e. the selection of the method overload during compilation) in pl/sql is slightly different than in other OOP languages, because it takes into account even the usage of the RETURNed type. To solve this, add a companion procedure with a signature whose difference is just in the lack of a returned type:
Reasonably, if you don't want to duplicate the same code in the function and the procedure, the procedure will internally delegate the function; and depending on the version of Oracle you are using you may want to play with code inlining (see OCP: More New PL/SQL Features) to achieve the same speed as a copy-pasted implementation (hardly you'll notice a real difference). Explicit "inlining" points at a method by name, however it works also in this case where the method name is overloaded.
In the example below you will see that either the function or procedure is alternatively invoked depending on the usage of the returned/not_returned parameter.
so finally...
The code one may want to write is the following (I have not used the
NOCOPY
not to pollute the relevant stuff, but it is straightforward to do)Upon execution of...
you get