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/