rkb@po.CWRU.Edu (Robert K. Brunner) (04/09/91)
I had a problem debugging a program today, and I was wondering if anyone had encountered the same problem before. The problem isn't a bug, but it is annoying behavior. Suppose you have the following variables: P1: \<< \-> a \<< 'a' INC \>> \>> INC: \<< \-> a \<< a INCR DROP \>> \>> Executing 5 P1 gives INCR Error: Bad Argument Type. If you change the local variable in either of the programs to something different, you get 6, as you would expect. Apparently, INC thinks that the 'a' on the stack refers to the innermost local variable, rather than the one belonging to P1. If this behavior is documented in the manuals, I haven't seen it. By the way, I worked around the problem by using pass-by-value in the real program. Unfortunately, the reason I use a sub-program is that I need the routine in three places, so I've got three extra " 'a' STO " 's, one after each call of the routine. I may change the local variable in the routine, but it bothers me that subroutine calls are not transparent. Suppose someone writes a library that uses a local variable which I unwittingly use elsewhere. Robert
stevev@greylady.uoregon.edu (Steve VanDevender) (04/09/91)
In article <1991Apr9.021224.27070@usenet.ins.cwru.edu> rkb@po.CWRU.Edu (Robert K. Brunner) writes:
I had a problem debugging a program today, and I was wondering if anyone
had encountered the same problem before. The problem isn't a bug, but
it is annoying behavior.
Suppose you have the following variables:
P1: \<< \-> a \<< 'a' INC \>> \>>
INC: \<< \-> a \<< a INCR DROP \>> \>>
Executing 5 P1 gives INCR Error: Bad Argument Type.
If you change the local variable in either of the programs to something
different, you get 6, as you would expect. Apparently, INC thinks
that the 'a' on the stack refers to the innermost local variable,
rather than the one belonging to P1. If this behavior is documented
in the manuals, I haven't seen it.
The manuals attempt to document the scope rules of variables in
pages 473 ff., but while they imply that local variables follow
simple static scope rules, they only cite examples where static
and dynamic scope rules are equivalent because none of their
examples pass local names around as you did.
By the way, I worked around the problem by using pass-by-value in
the real program. Unfortunately, the reason I use a sub-program
is that I need the routine in three places, so I've got three
extra " 'a' STO " 's, one after each call of the routine. I may
change the local variable in the routine, but it bothers me that
subroutine calls are not transparent. Suppose someone writes a
library that uses a local variable which I unwittingly use elsewhere.
Robert
You have discovered that RPL has dynamic scoping, not static
scoping, which is important to know because it will definitely
affect the way certain programs will work. Even worse, RPL
doesn't support passing a reference token to a variable, which I
think is what you were thinking it would do.
Dynamic scoping means that you can't tell what variables are in
scope (that is, which names refer to which values in which
active functions) just by inspecting the program visually. A
local name can refer to different local variables depending on
which function is doing the calling.
When you use the same local name 'a' in both P1 and INC, then
when INC is called from P1, INC's local name 'a' is bound to the
local name 'a'. Because RPL represents the local name 'a' the
same in all scopes, when you evaluate the expression "a" to
recall its contents, you get the local name 'a'. When INCR
retrieves the value bound to 'a', it again gets the local name
'a', and generates the "Bad argument type" message because that
isn't a real number.
This isn't as telling as the behavior shown when you use the
local name 'a' in P1 and 'b' in INC. Then, the value of "b" in
INC is the local name 'a', so INCR is passed the local name 'a',
and increments the value bound to local name 'a' _in the calling
function_, P1. This is possible because RPL lets you put a local
name on the stack, and because it clearly will attempt to resolve
a local name which isn't bound in the current scope by looking
for its binding in the function that called the current one, then
the function that called the function that called the current
one, and so on. While dynamic scoping will act like static
scoping for the examples given in the manual, in this case it is
different. In a statically scoped language, the variable would
have to be defined in the current function, or in the environment
that the current function is defined in, or in the environment
global to that, etc., or you would get an error at the time you
entered the statement. The run-time nesting of functions would
not affect the resolution of binding of local names in any way.
RPL therefore has two features that will bite people who are used
to programming in most conventional programming languages.
First, it uses dynamic instead of static scoping, which makes it
far more difficult to predict what a name will refer to, because
that depends on which functions have called which. Second,
unlike most languages which allow you to pass arguments by value
or by reference, RPL only allows you to pass arguments by value
or by _name_, which if I recall correctly hasn't been done much
since Algol faded from popularity.
RPL therefore fully lives up to the name "Reverse Polish LISP",
because the original LISP used dynamic instead of static scoping.
Ironically, Common LISP now uses static scoping (although dynamic
scoping is still available for backwards compatibility) and the
popular LISP dialect Scheme uses static scoping exclusively.
--
Steve VanDevender stevev@greylady.uoregon.edu
"Bipedalism--an unrecognized disease affecting over 99% of the population.
Symptoms include lack of traffic sense, slow rate of travel, and the
classic, easily recognized behavior known as walking."
grue@cs.uq.oz.au (Frobozz) (04/09/91)
In article <1991Apr9.021224.27070@usenet.ins.cwru.edu> rkb@po.CWRU.Edu (Robert K. Brunner) writes: >I had a problem debugging a program today, and I was wondering if anyone >had encountered the same problem before. The problem isn't a bug, but >it is annoying behavior. >Suppose you have the following variables: >P1: \<< \-> a \<< 'a' INC \>> \>> >INC: \<< \-> a \<< a INCR DROP \>> \>> There is a way to do what you desire. My reversi program for the hp28 made extensive use of it. You have to trick the parser into thinking that the variable 'a' is a local variable without including '-> a' in the executable code. Write a Make_INC routine that looks like (I've labeled the double brakcets): Make_INC: \<< \-> a \<< \<< a INCR DROP \>> 'INC' STO \>> \>> A B C C B A Then run this program and you have a version of INC that binds 'a' to a local variable but it doesn't define 'a' itself. The reason that this works is that when the Make_INC routine is parsed 'a' is a local variable, because it is defined at block level A and it is permitted to be used at level B. The parser then processes level C and says that 'a' is local. When this is run, the block C is pushed onto the stack and then stored into the variable INC, without re-evalulating the bindings. This means that 'a' (inside block C) still binds to a local variable. When your program P1 calls INC, the locally bound 'a' refers the the 'a' defined inside of P1 !!! You can now have global, local variables. If you try to run the new INC routine and there is no 'a' defined by any context along the call chain then you get an error message (undefined local?). Try this, it doesn't do any harm. Cute feature isn't it. Pauli seeya Paul Dale | Internet/CSnet: grue@cs.uq.oz.au Dept of Computer Science| Bitnet: grue%cs.uq.oz.au@uunet.uu.net Uni of Qld | JANET: grue%cs.uq.oz.au@uk.ac.ukc Australia, 4072 | EAN: grue@cs.uq.oz | UUCP: uunet!munnari!cs.uq.oz!grue f4e6g4Qh4++ | JUNET: grue@cs.uq.oz.au --
TDSTRONG%MTUS5.BITNET@VM1.NoDak.EDU (Tim Strong) (04/10/91)
> >I had a problem debugging a program today, and I was wondering if anyone >had encountered the same problem before. The problem isn't a bug, but >it is annoying behavior. > >Suppose you have the following variables: > >P1: \<< \-> a \<< 'a' INC \>> \>> >INC: \<< \-> a \<< a INCR DROP \>> \>> > >Executing 5 P1 gives INCR Error: Bad Argument Type. >If you change the local variable in either of the programs to something >different, you get 6, as you would expect. Apparently, INC thinks >that the 'a' on the stack refers to the innermost local variable, >rather than the one belonging to P1. If this behavior is documented >in the manuals, I haven't seen it. It looks like all you are tying to do is pass the current value of 'a' in P1 to the 'a' in INC. If that is what you're doing whats wrong with P1: /<< /-> a /<< a INC />> removing the ''s around the a the 48 recalls the value of a to the stack where the second program picks it up. The problem is not that the machine thinks you are referring to the value of 'a' in P1 it thinks you are referring to the name 'a' you have put on the stack. Thus in the second program the machine sees 1: 'a' -> a thats like saying 'a' 'a' STO. Store 'a' into itself doesn't make much sense. Incidentally if you rename one of the two local variables its fine because the HP sees 1: 'b' -> a So 'b' gets stored into 'a' and the EVAL works down the chain and eventually recalls the value of 'b'. I hope that explains the problem. And I hope I've understood the problem If not (and since I'm kinda dense sometimes I probably haven't) just scream. And I or someone else will give another shot. ====================================================================== ___ I__) _ _I _ _ TIM STRONG <TDSTRONG%MTUS5.BITNET@CUNYVM.EDU> I \ (_I (_I (_I I MICHIGAN TECH. HOUGHTON, MICHIGAN ======================================================================
herman@corpane.uucp (Harry Herman) (04/10/91)
In <1991Apr9.021224.27070@usenet.ins.cwru.edu> rkb@po.CWRU.Edu (Robert K. Brunner) writes: >I had a problem debugging a program today, and I was wondering if anyone >had encountered the same problem before. The problem isn't a bug, but >it is annoying behavior. >Suppose you have the following variables: >P1: \<< \-> a \<< 'a' INC \>> \>> >INC: \<< \-> a \<< a INCR DROP \>> \>> >Executing 5 P1 gives INCR Error: Bad Argument Type. >If you change the local variable in either of the programs to something >different, you get 6, as you would expect. Apparently, INC thinks >that the 'a' on the stack refers to the innermost local variable, >rather than the one belonging to P1. If this behavior is documented >in the manuals, I haven't seen it. >Robert If you re-wrote the procedure as: \<< \-> a \<< 'a' \<< \-> a \<< a INCR DROP \>> \>> \>> \>> then the section on local variables in Volume II of the Owner's Manual states that local variables in inner levels take precedence over variables defined in outer levels that have the same name. From stepping through your original programs with SST\/, I found that when INCR was finally reached inside INC, the value on level 1 was: 'a' I suspect that this is stored as an alphabetic name to be resolved to an address at run-time, it is not stored as the address of a in the routine P1. So, any attempt to look up the value of a inside INC always returns 'a', it never returns the 5 passed to P1 at the beginning. I even varified this by putting 'a' on the stack while in the debugger at the point that the "Bad Argument Type" message appeared, and repeatedly pressing RCL, trying to see if it would work its way back to the original value of 5, and it never did. It always left 'a' on the stack. So, the only solution is to pick a unique local variable name for the called procedure that is not used by any of the routines that call it. For example, if the local variable in INC was lksdjf instead of a, then the procedure would work, and the odds of you ever passing a variable called lksdjf to it would be every slim. When I was progamming in a version of BASIC that supported long names, but did not support multi-line functions, I named all the "local variables" (no such thing in BASIC, unless multi-line functions are supported) after the routine name. For example, I would have called the variabl a inside INC, INC_a, and the variable a inside P1, P1_a. That way I could still think of myself using a as the variable name, but be guaranteed that the names were unique. Harry Herman herman@corpane or ...uunet!ukma!corpane!herman
stevev@greylady.uoregon.edu (Steve VanDevender) (04/10/91)
Unfortunately, the technique you suggest won't do what I thought the original poster really wanted, which was to be able to make a subroutine that would apply INCR to an arbitrary variable. Another poster didn't notice that INCR was being called and thought that the original poster wanted to pass the value of a local name 'a' to the subroutine, not the name itself. You can pass local names into a subroutine to do operations that need a local name and not just its contents, but you cannot make the subroutine completely general because passing a local name which is also used in the subroutine will cause the subroutine to operate on its own local variable, not on the one in the caller. There is no way to pass a reference pointer to a variable so that a subroutine can operate on any variable in any scope in standard RPL. RPL has different scope rules for global names and local names, which I find very interesting. Global names are statically scoped based on the current PATH. Global name references are resolved by searching the current directory, then the parent of the current, then its parent, on up to HOME. The run-time nesting of functions has no effect on the resolution of global name references. Local names are dynamically scoped based on the run-time nesting of functions. A local name reference is resolved by searching the bindings of the current function, then in the function that called it, then in the function that called that, and so on. If a function passes a local name into another function, and the called function doesn't use the same local name, then references to that local name get its value in the calling function. A function that refers to a local name without first creating it, like the one you created with \<< \-> a \<< \<< 'a' INCR \>> 'INC' STO \>> \>> will end up being completely dependent on run-time function nesting to determine its effect. I don't want to say that this kind of dynamic scoping is bad, but it can produce some very counterintuitive behavior and the kinds of problems that the original poster reported. Generally nobody uses dynamic scoping any more in programming languages. I think that knowing it is used in RPL is very important because of the subtle effects it can have. -- Steve VanDevender stevev@greylady.uoregon.edu "Bipedalism--an unrecognized disease affecting over 99% of the population. Symptoms include lack of traffic sense, slow rate of travel, and the classic, easily recognized behavior known as walking."