This example is a demo that uses user-defined generics.

The demo consists of the following files:
  • container.cls—A generic class
  • cobject.cls—An abstract class
  • person.cls—A class that inherits from cobject.cls
  • place.cls—A class that inherits from cobject.cls
  • thing.cls— A class that inherits from cobject.cls
  • demo.p—A procedure that runs the demo

First, examine the cobject class which is an abstract class:

cobject.cls
class cobject abstract:

    method abstract public character doSomething().
    
end class.

Note that the cobject class has an abstract method called doSomething().

Next, examine the three classes (person, place, and thing). These classes inherit from cobject and override the doSomething() method:

person.cls
class person inherits cobject:

    method public override character doSomething():
        return "I am person.".
    end method.
    
end class.
place.cls
class place inherits cobject:

    method public override character doSomething():
        return "I am place.".
    end method.

end class.
thing.cls
class thing inherits cobject:

    method public override character doSomething():
        return "I am thing.".
    end method.

end class.

The doSomething() method simply returns what they are (I am person/place/thing).

Next, look at the container class:

container.cls
class container<V as cobject>:

    define public property mValue as class V
        get.
        private set.

    constructor public Container():
        var Progress.Lang.Class[] thisArgs.
        
        thisArgs = this-object:GetClass():GetTypeArguments().
        mValue = cast(thisArgs[1]:new(), cobject).
    end constructor.
    
    method public character doSomething():
        return mValue:doSomething().
    end method.
    
end class.

In the container class, V is the type parameter and cobject is the type constraint. The constructor uses dynamic programming to create an instance of the type that is passed (person, place, or thing). The class also has a method, which calls the appropriate doSomething() method depending on the type.

Next, look at demo.p. Note that there are two parts: Demo 1 and Demo2. They both do the same thing but Demo 2 defines the variables dynamically at runtime.

demo.p
output to demo.out.
/*---------------------------------------------------------------------------*/
/* Demo 1 - Non-dynamic version */

define variable cpersonRef as class container<person>.
define variable cplaceRef  as class container<place>.
define variable cthingRef  as class container<thing>.

cpersonRef = new container<person>().
message cpersonRef:doSomething() view-as alert-box.

cplaceRef = new container<place>().
message cplaceRef:doSomething() view-as alert-box.

cthingRef = new container<thing>().
message cthingRef:doSomething() view-as alert-box.

/*---------------------------------------------------------------------------*/
/* Demo 2 - Dynamic version */

define variable cref      as class Progress.Lang.Object no-undo.
define variable nouns     as character initial "person,place,thing" no-undo.
define variable lcounter  as integer no-undo.

do lcounter = 1 to num-entries(nouns):
    cref = dynamic-new "container<" + entry(lcounter, nouns) + ">" ().
    message dynamic-invoke(cref, "doSomething") view-as alert-box.
end.

/*---------------------------------------------------------------------------*/
output close.
quit.

In Demo 1 (non-dynamic version), three variables are defined: cpersonRef, cplaceRef, and cthingRef and then an instance of each is created. A message statement follows the creation of each instance which calls the doSomething() method for that container type.

In Demo 2 (dynamic version), cref is defined as a Progress.Lang.Object. Nouns is a character list of "person,place,thing". Within the loop, dynamic-new is called on an expression which evaluates to either container<person>, container<place>, or container<thing> and assigns it to cref. Then, dynamic-invoke is called on the doSomthing method of cref.

After running demo.p, you see the following output:

demo.out
I am person.
I am place.
I am thing.
I am person.
I am place.
I am thing.

The first three lines are from the non-dynamic version and the next three are from the dynamic version. As you can see, they produce the same output.