Как добится вызова по цепочке функций объектного типа возвращающие SELF?

Хочу добится вызова функций по цепочке, как например в C++ или Java. То есть, чтобы функции объектного типа вернули SELF. И тогда можно было бы связать эти вызовы по цепочке. Что-то вроде:

result := objType(1).setValue(2).addValue(1).printf();

Пробовал вернуть тот же тип, но так не работает. Самый упрощённый пример:

create or replace type objType as object (
    val int, member function addValue (val int) return objType) 
/    
create or replace type body objType as 
    member function addValue (val int) return objType is
    begin 
        self.val := self.val + val; 
        return self; 
    end;
end;    
/ 

Выводит такую ошибку:

LINE/COL ERROR
-------- -----------------------------------------------------------------
4/14     PLS-00363: expression 'SELF.VAL' cannot be used as an assignment target

Как такое можно реализовать?


Ответы (1 шт):

Автор решения: 0xdb

В функциях первый параметр всегда ссылка на сущность объектного типа SELF. Причём, если она не указана явно, то по умолчанию её режим IN, то есть константная ссылка, о чём и упомянуто в ошибке.

Изменить режим на OUT в этом случае не поможет, так как нельзя изменять сущность объекта пока она не присвоена переменной.

Единственное решение, в функции создать копию на SELF и вернуть её как результат.

Вот результат рабочего примера (код реализации ниже):

select listmaker (tokenList ('abc','def')).pad ('>>','<<').join () result 
from dual
/

RESULT
----------------
>>abc<<; >>def<<

Реализация:

create or replace type listmaker as object (
    tokens tokenList,
    constructor function listmaker (tokens tokenList) return self as result,
    member function pad (lval char, rval char) return listmaker,
    member function join (delimiter char := '; ') return varchar2
    )
/
create or replace type body listmaker as 
    constructor function listmaker (
        self in out listmaker, tokens tokenList) return self as result is 
    begin
        self.tokens := tokens;
        return;
    end;
    member function pad (lval char, rval char) return listmaker is
        my listmaker := self;
    begin
        for i in 1..my.tokens.count loop 
            my.tokens(i) := lval||my.tokens(i)||rval;
        end loop;
        return my; 
    end;
    member function join (delimiter char := '; ') return varchar2 is
        ret varchar2 (32767);
    begin 
        for i in 1..tokens.count loop ret := ret||tokens(i)||delimiter;
        end loop;
        return rtrim (ret, delimiter);
    end;
end;
/
→ Ссылка