Task

Take a combined set of elements and apply a function to each element.




-- Let's create a generic class with one method to be used as an interface:
CREATE OR REPLACE
TYPE callback AS OBJECT (
    -- A class needs at least one member even though we don't use it
    -- There's no generic OBJECT type, so let's call it NUMBER
    dummy NUMBER,
    -- Here's our function, and since PL/SQL doesn't have generics,
    -- let's use type NUMBER for our params
    MEMBER FUNCTION exec(n NUMBER) RETURN NUMBER
) NOT FINAL NOT instantiable;
/
 
-- Now let's inherit from that, defining a class with one method. We'll have ours square a number.
-- We can pass this class into any function that takes type callback:
CREATE OR REPLACE TYPE CB_SQUARE under callback (
    OVERRIDING MEMBER FUNCTION exec(n NUMBER) RETURN NUMBER
)
/
CREATE OR REPLACE
TYPE BODY CB_SQUARE AS
    OVERRIDING MEMBER FUNCTION exec(n NUMBER) RETURN NUMBER IS
    BEGIN
        RETURN n * n;
    END exec;
END;
/
 
-- And a package to hold our test
CREATE OR REPLACE 
PACKAGE PKG_CALLBACK AS 
    myCallback cb_square;
    TYPE intTable IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
    ints intTable;
    i PLS_INTEGER;
 
    PROCEDURE test_callback;
END PKG_CALLBACK;
/
 
CREATE OR REPLACE PACKAGE BODY PKG_CALLBACK AS
    -- Our generic mapping function that takes a "method" and a collection
    -- Note that it takes the generic callback type 
    -- that doesn't know anything about squaring
    PROCEDURE do_callback(myCallback IN callback, ints IN OUT intTable) IS
        i PLS_INTEGER;
        myInt NUMBER;
    BEGIN
        FOR i IN 1 .. ints.COUNT LOOP
            myInt := ints(i);
            -- PL/SQL call's the child's method
            ints(i) := myCallback.exec(myInt);
        END LOOP;
    END do_callback;
 
    PROCEDURE test_callback IS
    BEGIN
        myCallback := cb_square(NULL);
        FOR i IN 1..5 LOOP
            ints(i) := i;
        END LOOP;
 
        do_callback(myCallback, ints);
 
        i := ints.FIRST;
        WHILE i IS NOT NULL LOOP
            DBMS_OUTPUT.put_line(ints(i));
            i := ints.next(i);
        END LOOP;
    END test_callback;
END PKG_CALLBACK;
/
 
BEGIN
  PKG_CALLBACK.TEST_CALLBACK();
END;
/