[comp.databases] Is this what's happening ?

abcscnuk@csunb.csun.edu (Naoto Kimura (ACM)) (01/31/91)

Right now at work I'm having to deal with some badly written dBASE code.
The original programmer ended up doing just about everything that the
manual specifically warned not to do (like placing EXITs without having
a DO WHILE-ENDDO, placing RETURNs within DO WHILE-ENDDO, inserting ASCII
NULLs into the middle of a parameter string).  Anyway, I've tried to
convince everybody at work that they shouldn't suspect my code whenever
anything goes wrong.  So far, I've had only limited success in
convincing anybody because of the attitude of: "we've (almost) never had
any of these problems before we hired you." (please note the qualifier
that they keep leaving out) I've had to resort to doing a lot of
rewriting of code the past few months (without telling my boss about it)
to fix most of the bugs, and doing a bit of thinking on the mechanics of
how some of the problems were occurring.

The problem that kept occurring was that parameters weren't being passed
back when a subprogram exited, and this problem only manifested itself
only after compling the code under QuickSilver.  The problem never
seemed to appear when run under dBASE or FoxBase.  In investigating the
way dBASE handles memory variables and parameter passing, I discovered
that paramter passing is neither pass-by-value nor pass-by-reference.
Variables passed as parameters apparently get changed at the time the
subprogram returns to the caller.  Anyway, here is what I think is going
on whenever you've got RETURNs within DO WHILE-ENDDOs:

Suppose we've got the following program files:

   yuk.prg:
   -------

	barf = 'this is a test'
	call icky with barf
	? barf

   icky.prg
   --------

	parameters wretch
	wretch = 1
	do while .t.
	    if wretch>=2
		return
	    endif
	    wretch = wretch + 1
	enddo

here's an example session and how I think parameter passing might be
getting screwed up:

. DO YUK
    create new program context
    read 'yuk.prg'

YUK.PRG> barf = 'this is a test'
    create new PRIVATE variable 'barf'
    assign 'barf' the value 'this is a test'

YUK.PRG> call icky with barf
    create new program context

ICKY.PRG> parameters wretch
    create PRIVATE variable 'wretch' (make note that 'wretch' is a
    reference to 'barf' and it needs to be fixed up when we exit.)
    assign 'wretch' the value of 'barf' ('this is a test')

ICKY.PRG> wretch = 1
    assign 'wretch' the value of 1

ICKY.PRG> do while .t.
    create DO WHILE context
    evaluate condition, since true enter loop

ICKY.PRG>     if wretch=>2
    compare wretch to 2
    since expression evaulates to false, fall through to endif

ICKY.PRG>         return
    skip
ICKY.PRG>     endif
    skip

ICKY.PRG>     wretch = wretch + 1
    assign 'wretch' the value of 'wretch' plus 1 (2)

ICKY.PRG> enddo
    go to beginning of DO WHILE loop

ICKY.PRG> do while .t.
    evaluate condition, since true stay in loop context

ICKY.PRG>     if wretch=>2
    compare wretch to 2
    since expression evaluates to true, execute IF clause
ICKY.PRG>         return
    look at current context (context of DO WHILE):
	We don't see anything saying we've got parameters, so we don't
	have to do any fixup.
	Exit to previous context (the context of ICKY.PRG).

YUK.PRG> ? barf
    print value of 'barf', which happens to be 'this is a test'


----------------------------------------------------------------------

Anyway, does anybody have any thoughts about this ?

                //-n-\\			 Naoto Kimura
        _____---=======---_____		 (abcscnuk@csuna.csun.edu)
    ====____\   /.. ..\   /____====
  //         ---\__O__/---         \\	Enterprise... Surrender or we'll
  \_\                             /_/	send back your *&^$% tribbles !!

awd@dbase.A-T.COM (Alastair Dallas) (02/02/91)

Parameter passing in dBASE is always by reference in the case of
simple memvars and always by value in the case of expressions.

In your example:

	a = "this is a test"
	do icky with a
	? a
	return

procedure icky
parameter foo

	foo = 1
return

You will find that the top-level code prints 1, at least in 
dBASE IV.  To pass parameters by value (generally better
programming practice) you can do as little as enclose them
in parentheses:

	a = "this is a test"
	do icky with (a)
	? a		&& will print "this is a test" no matter what
	return

Internally, dBASE creates a local alias which references the 
parameters which are passed by reference when it processes the
PARAMETERS command.  How you return from the procedure does not
affect the operation.  Of course, if you're using any random
xBASE product ... ;-)

/alastair/