Object Rexx / Passing a stem and receiving it with arg() - REXX
This is a discussion on Object Rexx / Passing a stem and receiving it with arg() - REXX ; Ok, now I'll say it... "Oh Yea With More Knowledge Than I!!" I.E. Rick!!!!!! ;-)
I am covering 101 ground this evening to make sure I know an area inside and out, but something surprised me... I was testing what ...
-
Object Rexx / Passing a stem and receiving it with arg()
Ok, now I'll say it... "Oh Yea With More Knowledge Than I!!" I.E. Rick!!!!!! ;-)
I am covering 101 ground this evening to make sure I know an area inside and out, but something surprised me... I was testing what does and does not work with arg(), use arg, parse arg. Specifically,
if I pass a stem and receive it with arg() I get the stem and it behaves as if I received it with use arg as if I update it, back in main() it is updated.
/* oddly enough my sample code looks much like IBM's in the .HLP file for the keyword USE */
stem.1='Stem One'
number2=11
string3='string arg 3'
say stem.1
rc=Test(stem., number2, string3)
say stem.1
say number2
say string3
exit 0
test: procedure
thestem.=arg(1)
two=arg(2)
three=arg(3)
say thestem.1
thestem.1='trash'
two=2
three='more trash'
say thestem.1
return 1
/* */
Stem One
Stem One
trash
trash
11
string arg 3
Now, I was either (1) not expecting the stem to make it into test() or (2) I sure was not expecting 'trash' to make it out of test()
The docs say that arg() will parse the data, sure seems like a stem and not a string to me! Then I went back to see if the simple vars did the same, they did not.
OK, swap the three arg() lines out for this use arg line...
use arg thestem., two, three
Now, since use arg has that "pointer" behavior I would expect I could update the two simple vars and have the update make it back to main() but it does not. So is it only "complex" objects which get
the pointer magic done for them (stems, arrays, user defined classes) and simple ones like a string var do not get the pointer magic. I am having a hard time understanding the bounds of each behavior
I guess.
TIA!
--
Michael Lueck
Lueck Data Systems
Remove the upper case letters NOSPAM to contact me directly.
-
Re: Object Rexx / Passing a stem and receiving it with arg()
Sigh, ok, long explanation time. Just remember you said you "I am
covering 101 ground this evening to make sure I know an area inside and
out".
Ok, the first thing you need to understand is a variable in Object Rexx
is really just a pointer to an object. So when I do this
a = 1
b = a
When you use a variable, the value of that variable is evaluated to
generate a reference to the variable. When you assign a variable, the
object reference is assigned to the variable. Variable A points to an
instance of a Rexx string with the value "1", and the variable B points
to the exact same instance. In fact, the Classic Rexx interpreter
implemented its internal storage the same way. Now since Rexx strings
are "immutable", there is nothing I can do to change the value of that
string to anything other than "1".
Now consider this.
a = .array~new
b = a
The same principle applies as above. Variables A and B now point to the
same instance of a Rexx array. Arrays are not immutable. They have
internal state that can be changed. Thus
a[1] = "Fred"
say b[1] -- displays "Fred"
The assignment to a[1] does not change the value of A. It still points
to the same array created above. The assignment does change the
internal state of the array. Since B points to the same array instance,
the change is reflected in the Say statement. Neither variable A nor B
was changed in this process, only the array they both point to.
ok, now lets extend this to calls.
c = 1
call fred a, c
say a[1] c b[1] -- displays "George 1 George"
....
fred: procedure
use arg x, y
x[1] = "George"
y = 2
When you make a call (included method calls), the argument expressions
are evaluated from left to right, creating a list of object references
that are passed to the call target. So in my example above the array
contains two elements, the value of the variable A and value of the
variable C. The target routine has no knowledge of where these values
came from, it only receives the references.
The use arg instruction is very simple, it merely assigns each listed
variable to it's corresponding object reference. So X points to the
same array A and B point to, and Y points to the same string "1" that C
points to. USE ARG is functionally equivalent to "x = arg(1)", except
for the special behavior that USE ARG has for omitted arguments.
When I do x[1] = "George", this is just like my example above. The
variable X is unchanged, but the internal state of the array it points
to is, and this change is seen in the calling routine.
However, when I make the assignment "y = 2", this replaces the Y's
object reference to "1" with a new reference to the string "2". C back
in the caller has not been touched, it still points to the string "1",
which is reflected in the value that shows up on the Say statement.
Ok, your question was about stems, and I'm getting there! I wanted to
give you the basics of how object references work without cluttering the
discussion up with stem variables yet.
Now let's look at stems. A stem VARIABLE is just like a normal
variable. It also contains a reference to a Rexx object. Stem
VARIABLEs are special, however, as there is only a single type of object
that can be assigned to a stem VARIABLE. This single type is a STEM
object. Please try to keep in mind there is a difference between the
stem OBJECT and the stem VARIABLE you use access to the object.
You can actually use stem OBJECTS without using stem VARIABLES. For
example:
a = .stem~new("A.")
a[1] = "Fred"
say a[1] a[2] -- Displays "Fred A.2"
is functionally equivalent to
a.1 = "Fred"
say a.1 a.2
Any time you use either a stem variable or a compound variable, the stem
part is evaluated to return the reference to its referenced stem object.
If this is the first time you've ever used this stem VARIABLE, then a
STEM object is created and assigned to the variable first. Once the
stem OBJECT reference has been returned it is then used are the target
for compound variable tail lookups.
INTERMISSION: Handy little tip. A frequent topic of discussion on this
newsgroup is the question of constant values within a compound variable.
Uses such as this
x.i.name = "Rick"
x.i.address = "Boston"
a frequent convention tacks a digit on the front to prevent accidental
uses of those variables. ie,
x.i.0name = "Rick"
x.i.0address = "Boston"
In Object Rexx, you can use literal strings by using the "[]" notation
x.[i, "NAME"] = "Rick"
x.[i, "ADDRESS"] = "Rick"
note that this functions the same way Rexx arrays work. The stem
VARIABLE is evaluated, and the "[]=" method of the resulting stem OBJECT
is invoked to do the assignment.
You can also see this reference effect by using the following assignment":
x = x. -- TWO different variables here..."X" and "X."
say x[i, "NAME"] x.i.name -- displays "Rick Rick"
Here we have a simple Rexx variable and a stem Rexx variable referencing
the same stem OBJECT.
END INTERMISSION
Stem variable assignment also functions slightly differently from normal
variable assignments.
If you assign a stem variable to another stem variable
a.1 = "Fred"
a. = b.
say b.1 b.2 -- displays "Fred A.2"
The stem variable reference for A. is assigned to a second stem variable
B. And you can see this when I referenced the uninitialized stem
element B...it displayed the value "A." because the original stem OBJECT
was created with a name value of "A." originally.
If you assign anything other than a stem OBJECT to a stem VARIABLE, then
a new stem OBJECT is created and given that value as its default value.
This assignment will sever the link to the original stem object. So
given the above.
say a.1 b.1 -- displays "Fred Fred"
a. = "George"
say a.1 b.1 -- displays "George Fred"
Hang in there, I'm actually getting close to your original question!
Now, how does use arg work with stem variables.
a.1 = "Fred"
c = 1
call fred a., c
say a1 c -- displays "George 1"
....
fred: procedure
use arg x., y
x.1 = "George"
y = 2
This is the same as the example above. The stem variable A. in the call
evaluates to a reference to a stem OBJECT, which is passed to the target
routine. USE ARG accesses that argument list, and assigns the
references to each variable in turn. So the local variable X. is
assigned the value of the first argument, which is a reference to a stem
object. If you recall from the discussion above, a stem object assigned
to a stem variable just copies the reference into the variable.
Variables X. and A. now point to the same stem OBJECT. Stem objects
have updatable internal state, so the assignment
x.1 = "George" is visible back in the calling routine.
Interestingly, you can do the same thing without even using a stem
variable! Try the following:
fred: procedure
use arg x, y -- X is a simple variable, not a stem!
x[1] = "George"
y = 2
Ok, thus concluded Rick's Friday night Object Rexx tutorial :-)
-
Re: Object Rexx / Passing a stem and receiving it with arg()
Thank you, Rick! I will of course be keeping that great explanation.
So possibly the text in the .HLP file for "use" is not quite correct?
>>
USE ARG also allows access to both string and non-string argument objects; ARG and PARSE ARG parse the string values of the arguments.
<<
As you said use arg and arg are the same other than how they handle missing args (which I will have to tinker with that now to see what you mean! ;-)
Also least anyone get confused with a mission period in one of your examples, I provide the patched source:
a.1 = "Fred"
c = 1
call fred a., c
say a.1 c -- displays "George 1"
exit
fred: procedure
use arg x., y
x.1 = "George"
y = 2
return
One last thought... If I wanted to create a simple mutable var, then I would just implement my own class which acts like a simple var, and since it is not Object Rexx's built-in string class it would
be mutable? ;-)
Thanks again... back to my code!
--
Michael Lueck
Lueck Data Systems
Remove the upper case letters NOSPAM to contact me directly.
-
Re: Object Rexx / Passing a stem and receiving it with arg()
Well, based on your return questions, I don't think you still have it yet.
Michael Lueck wrote:
> Thank you, Rick! I will of course be keeping that great explanation.
>
> So possibly the text in the .HLP file for "use" is not quite correct?
>
> >>
> USE ARG also allows access to both string and non-string argument
> objects; ARG and PARSE ARG parse the string values of the arguments.
> <<
>
This is exactly correct. If you want to access an object that's not a
string as an argument, you must use USE ARG. ARG and PARSE ARG both
convert the argument objects into their string values. What about this
do you not think is correct?
> As you said use arg and arg are the same other than how they handle
> missing args (which I will have to tinker with that now to see what you
> mean! ;-)
USE ARG for missing arguments makes the variable uninitialized. The
ARG() bif must return a value and doesn't have the capability for
uninitializing a variable.
>
> Also least anyone get confused with a mission period in one of your
> examples, I provide the patched source:
>
> a.1 = "Fred"
> c = 1
> call fred a., c
> say a.1 c -- displays "George 1"
> exit
>
> fred: procedure
> use arg x., y
>
> x.1 = "George"
> y = 2
> return
>
> One last thought... If I wanted to create a simple mutable var, then I
> would just implement my own class which acts like a simple var, and
> since it is not Object Rexx's built-in string class it would be mutable?
> ;-)
>
You cannot create a class that acts like a simple var. The variables
are internal Rexx constructs, not something you can replace. That was
my point for trying to emphasize the difference between stem VARIABLE
and stem OBJECT. You can do something like this:
::class refString public
::method "[]" class
return self~new(arg(1))
::method init
expose value
use arg value
::method "[]="
expose value
use arg value
::method unknown
expose value
forward to (value)
::method string
expose value
return value
Then you can do something like this:
arg = .refstring~new("Hello")
call fred arg
say arg -- displays "Goodbye"
.....
fred: procedure
use arg x
x[]="Goodbye" -- NOTE: NOT "x="...that would assign X to a
-- different object
As a bonus, I threw in one of my favorite tricks for classes, that of
adding a "[]" on the class object that returns a new instance for me. I
can also make a reference now using
arg = .refstring["Hello"]
for classes I want to create lots of instances, I find this saves
typing. Usually I give the class a shorter name if that's the case too.
> Thanks again... back to my code!
>
-
Re: Object Rexx / Passing a stem and receiving it with arg()
I've enhanced my example a tiny bit to make it a little more useful.
::class ref public
::method "[]" class
return self~new(arg(1))
::method init
expose value
use arg value
::method "[]="
expose value
use arg value
::method "[]" -- retrieve the indirectly referenced object
expose value
return value
::method unknown
expose value
forward to (value)
::method string
expose value
forward to (value)
::method "="
expose value
forward to (value)
::method "=="
expose value
forward to (value)
::method "\="
expose value
forward to (value)
::method "\=="
expose value
forward to (value)
-
Re: Object Rexx / Passing a stem and receiving it with arg()
Rick McGuire wrote:
>> >>
>> USE ARG also allows access to both string and non-string argument
>> objects; ARG and PARSE ARG parse the string values of the arguments.
>> <<
>>
>
> What about this
> do you not think is correct?
It (arg) allowed the stem to pass through. That seems "more powerful" than simply the "string value of the argument" as the HLP file called the functionality. Thus I did not expect to get "use arg"
functionality when passing in a stem and receiving it with "arg".
Since it said "ARG and PARSE ARG parse the string values of the arguments" I expected either of them to produce the same result. "parse arg" with a stem being passed in results as follows...
Stem One --say in the main()
STEM. --say in the procedure
Thus PARSE ARG attempted to reduce the stem to a string, and place it in the stem place holder I provided in the parse template.
> USE ARG for missing arguments makes the variable uninitialized. The
> ARG() bif must return a value and doesn't have the capability for
> uninitializing a variable.
Thanks for the details... I'll still code up some examples to see the actual results.
> You cannot create a class that acts like a simple var. The variables
> are internal Rexx constructs, not something you can replace.
I didn't mean so much replace, but make a class as you did, and use instances of that class when I want a mutable single value containing object... I guess that is the best way to describe it.
--
Michael Lueck
Lueck Data Systems
Remove the upper case letters NOSPAM to contact me directly.
-
Re: Object Rexx / Passing a stem and receiving it with arg()
ARG in that context refers to the ARG builtin instruction (which is a
synonym for PARSE UPPER ARG). The ARG() builtin function does return
the object argument directly, as you discovered.
Michael Lueck wrote:
> Rick McGuire wrote:
>
>>> >>
>>> USE ARG also allows access to both string and non-string argument
>>> objects; ARG and PARSE ARG parse the string values of the arguments.
>>> <<
>>>
>>
>> What about this do you not think is correct?
>
>
> It (arg) allowed the stem to pass through. That seems "more powerful"
> than simply the "string value of the argument" as the HLP file called
> the functionality. Thus I did not expect to get "use arg" functionality
> when passing in a stem and receiving it with "arg".
>
> Since it said "ARG and PARSE ARG parse the string values of the
> arguments" I expected either of them to produce the same result. "parse
> arg" with a stem being passed in results as follows...
>
> Stem One --say in the main()
> STEM. --say in the procedure
>
> Thus PARSE ARG attempted to reduce the stem to a string, and place it in
> the stem place holder I provided in the parse template.
>
>> USE ARG for missing arguments makes the variable uninitialized. The
>> ARG() bif must return a value and doesn't have the capability for
>> uninitializing a variable.
>
>
> Thanks for the details... I'll still code up some examples to see the
> actual results.
>
>> You cannot create a class that acts like a simple var. The variables
>> are internal Rexx constructs, not something you can replace.
>
>
> I didn't mean so much replace, but make a class as you did, and use
> instances of that class when I want a mutable single value containing
> object... I guess that is the best way to describe it.
>
-
Re: Object Rexx / Passing a stem and receiving it with arg()
On Sat, 29 Jan 2005 07:27:18 -0500, Michael Lueck
<NmlueckO@SlueckPdataAsystemsM.com> wrote:
>So possibly the text in the .HLP file for "use" is not quite correct?
> >>
>USE ARG also allows access to both string and non-string argument
>objects; ARG and PARSE ARG parse the string values of the arguments.
><<
>As you said use arg and arg are the same other than how they handle
>missing args (which I will have to tinker with that now to see what you
>mean! ;-)
I think you are encountering confusion between the ARG instruction
and the ARG() built-in function.
The ARG instruction is the same as PARSE UPPER ARG and it converts
everything to a string before parsing it. The ARG() function can
give you access to the non-string objects in the arguments.
--
---- Ian Collier : imc@comlab.ox.ac.uk : WWW page (including REXX section):
------ http://users.comlab.ox.ac.uk/ian.collier/imc.shtml
New to this group? Answers to frequently-asked questions can be had from
http://rexx.hursley.ibm.com/rexx/ .
Similar Threads
-
By Application Development in forum DOTNET
Replies: 0
Last Post: 12-26-2006, 05:00 PM
-
By Application Development in forum REXX
Replies: 2
Last Post: 12-04-2006, 09:02 PM
-
By Application Development in forum REXX
Replies: 3
Last Post: 05-06-2006, 12:57 PM
-
By Application Development in forum REXX
Replies: 1
Last Post: 07-20-2005, 11:53 PM
-
By Application Development in forum REXX
Replies: 3
Last Post: 01-14-2005, 05:01 AM