GetHello: RETURN "hello" GetHi: RETURN "hi"Now suppose that you would like to be able to directly call any particular function (by name) inside of this script from another script. Perhaps you could add some code to the beginning of the script where it expects to be passed the name of the function to call:
SIGNAL VALUE ARG(1) GetHello: RETURN "hello" GetHi: RETURN "hi"Now, from another script, you can directly call the GetHello() function in Greetings.rex as so:
MyVariable = Greetings.rex("GETHELLO")
A REXX Object
Reginald supports a "lightweight" REXX object. For the sake of making this efficient and easy for a novice programmer to understand, Reginald's object doesn't support some features that other more complicated object-oriented implementations do, such as multiple inheritance, private/public functions, etc. Reginald's object is the most basic implementation of an object you can find, and that makes it a bit limited, but very easy to comprehend.
You can think of a REXX object as a REXX script. Any REXX script can become an object in Reginald. In fact, to create an object, you have to put all of the instructions (ie, subroutines and functions of that particular object) into a single REXX script, and nothing but that object's subroutines and functions should be put in that script. (ie, You can't put more than one object in a single script).
By using an object, you can directly call any function/subroutine inside of it, but the "object script" doesn't need that SIGNAL VALUE at the beginning, and you don't have to pass the name of the function you want to call.
Here's a REXX script that could used as an object. We'll name this REXX script "MyObject.rex".
Create: MyVariable = "hello" RETURN GetMyVariable: RETURN MyVariable SetMyVariable: MyVariable = ARG(1) RETURNPretty simple. There's nothing there that you couldn't find in an ordinary script. This object script has three functions/subroutines in it, named Create, GetMyVariable, and SetMyVariable.
In order to use this script as an object, you must call Reginald's CreateObject() function once. You pass the name of the object script, and also pass the name of a variable that you want to represent the object (ie, script). For example, here we specify that we want to use MyObject.rex as an object, and we'll use the variable Object1 to reference it:
CreateObject("MyObject.rex", "Object1")You can create many instances of an object. Here, we create another instance, but use the variable named "Object2" to represent it:
CreateObject("MyObject.rex", "Object2")Whenever an object is created, Reginald will automatically call the Create function in the object script, if that function is found in the script. As you can see, the Create function of MyObject.rex initializes the variable MyVariable to the string "hello". Here's the deal with an object. Each instance of the object has its own copy of MyVariable, and all the other variables used in the object script (just like each REXX script you write has its own set of variables). The only difference here is that both Object1 and Object2 will be using the same copy of MyObject.rex's instructions loaded into memory. It's just that MyObject.rex will have two sets of the same variables - one set for Object1, and one set for Object2.
And an instance's set of variables will remain in memory for as long as the instance is in existance (ie, until you DROP it, or your script ends). So if you initialize some variables in the Create function, then those values will be in effect whenever any other function in the object script is called (unless you explicitly change a variable's value or DROP it).
To call the GetMyVariable() function in MyObject.rex, and tell it to use its set of variables for Object1, you do this:
value = Object1~GetMyVariable()
To call the GetMyVariable() function in MyObject.rex, and tell it to use its set of variables for Object2, you do this:
value = Object2~GetMyVariable()So, you're really returning the value of two different "MyVariable" variables here, even though you're calling the same function in MyObject.rex.
To call the SetMyVariable() function in MyObject.rex, and tell it to operate upon Object1's copy of MyVariable, you do this:
Object1~SetMyVariable(5)We've now set Object1's copy of MyVariable to the value 5.
To call the SetMyVariable() function in MyObject.rex, and tell it to operate upon Object2's copy of MyVariable, you do this:
Object2~SetMyVariable("Some string")We've now set Object2's copy of MyVariable to the value "Some string".
Think of it this way. An object is just a REXX script that can have multiple sets of its variables -- one set for each "instance" you do of CreateObject. And by assigning some variable to represent an instance, that allows you to use the ~ character to directly call a particular function in the object script, and specify which set of variables you want it to use.
And when you want to delete an instance of an object, you just drop it:
DROP Object2Reginald will then automatically call any Destroy function in the object script, if it exists, and tell it to specify the set of variables for Object2. (We don't have a Destroy function in our MyObject.rex example above, because we didn't need one).
Note: The CreateObject() function returns whatever the object script's Create function returns. For example, assume we have an object script (named MyObject.rex) whose Create() function returns the name of the operating system it is running on as so:
Create: PARSE SOURCE OS . RETURN OSTo create an instance of MyObject.rex, use the variable Object1 to represent it, and to get back the value from its Create() function, you do:
OS = CreateObject("MyObject.rex", "Object1") SAY OSNote: If CreateObject() fails to create an instance of an object, perhaps due to low memory, or a SYNTAX error in the object script, or the script can't be located on disk, etc, then a SYNTAX condition may be raised. So too, a SYNTAX condition may be raised if you try to call a function that doesn't exist in the object script, or you reference a variable whose object has been DROP'ed.
Note: An object script can discover what particular object variable name has been referenced to call one of its functions, by using UNAME(1).
If you intend to only ever create one instance of an object, you can use a shortcut. By omitting the name of the variable, CreateObject will automatically use the script name, minus any .REX extension. For example, here we specify that we want to use MyObject.rex as an object, and we access it with a variable of the same name:
CreateObject("MyObject.rex") MyObject~SetMyVariable("Some string")
An object from a Macro DLL
You can also use CreateObject() to load a script within a Macro DLL, and create an object from it. To do this, you pass the name of the DLL containing the script (minus any .DLL extension) as the first arg to CreateObject. You also pass an additional, third arg, which is the script number you desire within the DLL, where 1 is the first script, 2 is the second script, etc.
For example, assume you have a Macro DLL named "MyScripts.dll" and you wish to create an object from the third script inside this DLL, and represent it with the variable "Object1":
CreateObject("MyScripts", "Object1", 3)After the call, you can treat this object just like any other object.
Accessing an object's variables
If your script creates an object that has a stem (instead of a simple) name to represent the object, then your script can directly access the variables in the object. For example, here we create an object from the script "MyScript.rex" and reference it with the variable named "MyObject.":
CreateObject("MyScript.rex", "MyObject.")Now our script can set some variables in the object as so:
/* Set the value of the "MyVariable" variable in "MyObject." to "hello" */ MyObject.MyVariable = "hello" /* Call MyFunction() in "MyObject." and note the dot on the end of "MyObject." */ MyObject.~MyFunction()And assume the object script has this:
MyFunction: SAY MyVariable RETURNThis results in hello being displayed.
Your script can also query the values of variables in an object. For example, here we display the current value of Mystem.MyTail in "MyObject.":
SAY MyObject.Mystem.MyTail
Passing arguments to the object script's Create()
Any additional arguments you pass to CreateObject (after the third arg) will be passed on to the object script's Create() function. For example, here we specify that we want to use MyObject.rex as an object, and we access it with a variable of the same name, and pass its Create() function two args of "Arg 1", and the contents of MyVariable:
CreateObject("MyObject.rex", , , "Arg 1", MyVariable)
Errata
The C_CALL OPTION is always automatically set for any object's functions, so you do not need to use the CALL keyword (although may do so). Also, the LABELCHECK and WINFUNC options are always set.