[comp.sys.handhelds] HP-48 programming problem

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."