A bug in QB? Or is this a feature?

If you have questions about any aspect of QBasic programming, or would like to help fellow programmers solve their problems, check out this board!

Moderators: Pete, Mods

Post Reply
User avatar
RETROQB45
Newbie
Posts: 4
Joined: Wed Jun 03, 2020 2:57 pm

A bug in QB? Or is this a feature?

Post by RETROQB45 »

Here's an interesting bug I've found messing with my old QuickBASIC programs.
I suspect that anyone has spotted it before, but Google doesn't seem to know anything about this :)

Please read carefully the following code and guess what it will print:

Code: Select all

DIM SHARED a(2)
a(1) = 10
PRINT "before the call:"; a(1)
f a(1)
PRINT "after the call:"; a(1)

SUB f (v)
  PRINT "in the sub before modifying:"; a(1)
  v = 2
  PRINT "in the sub after modifying:"; a(1)
END SUB
Then run it in any ORIGINAL DOS QuickBASIC (QBasic/QB4.5/PDS/VBDOS) and be shocked with its "correct" answer (10 10 10 2 :shock:)

The key point here is passing an array element by reference.
Btw this code works as expected in QB64.

And now I wonder how can it be that I've never suffered from this (didn't even know of) in my childhood? :lol:
Erik
Veteran
Posts: 72
Joined: Wed Jun 20, 2007 12:31 pm
Location: LI, NY
Contact:

Re: A bug in QB? Or is this a feature?

Post by Erik »

Interesting! So it basically treats the "v" parameter as a local variable in the SUB and doesn't actually update the value of the array element passed until the code is returning from the SUB.

Passing in the whole array works as expected. The source array is updated when the parameter array gets updated.

Ex:

Code: Select all

DECLARE SUB SetVals (ArrayIn() AS INTEGER)

DIM SHARED test(1) AS INTEGER

test(0) = 500
test(1) = 900

CLS
PRINT "Before sub call"
PRINT "test(0) "; test(0)
PRINT "test(1) "; test(1)
PRINT "--------------------------------------"
CALL SetVals(test())

PRINT "After sub call"
PRINT "test(0) "; test(0)
PRINT "test(1) "; test(1)
PRINT "--------------------------------------"

SUB SetVals (ArrayIn() AS INTEGER)

PRINT "Start sub call"
PRINT "test(0) "; test(0)
PRINT "test(1) "; test(1)
PRINT "ArrayIn(0) "; ArrayIn(0)
PRINT "ArrayIn(1) "; ArrayIn(1)
PRINT "--------------------------------------"

ArrayIn(0) = 400
ArrayIn(1) = 200

PRINT "End sub call"
PRINT "test(0) "; test(0)
PRINT "test(1) "; test(1)
PRINT "ArrayIn(0) "; ArrayIn(0)
PRINT "ArrayIn(1) "; ArrayIn(1)
PRINT "--------------------------------------"

END SUB
Output:

Code: Select all

Before sub call
test(0)  500 
test(1)  900 
--------------------------------------
Start sub call
test(0)  500 
test(1)  900 
ArrayIn(0)  500 
ArrayIn(1)  900 
--------------------------------------
End sub call
test(0)  400 
test(1)  200 
ArrayIn(0)  400 
ArrayIn(1)  200 
--------------------------------------
After sub call
test(0)  400 
test(1)  200 
--------------------------------------
Nice find. I'm sure that's caused headaches to others in the past.
nikomaru
Newbie
Posts: 7
Joined: Wed Nov 28, 2018 7:35 pm

Re: A bug in QB? Or is this a feature?

Post by nikomaru »

Ha! I had this issue as well, creating a Frogger clone, and fixed it with passing BY instead of referencing. Just trying to save memory by not using a stupid amount of globals, sheesh!
angros47
Veteran
Posts: 79
Joined: Mon Sep 08, 2008 12:52 pm
Contact:

Re: A bug in QB? Or is this a feature?

Post by angros47 »

Wow! It's the first time in about 10 years that I see something new about QB, on this forum.
angros47
Veteran
Posts: 79
Joined: Mon Sep 08, 2008 12:52 pm
Contact:

Re: A bug in QB? Or is this a feature?

Post by angros47 »

RETROQB45 wrote: Thu Jun 04, 2020 6:34 am Here's an interesting bug I've found messing with my old QuickBASIC programs.
.....

Then run it in any ORIGINAL DOS QuickBASIC (QBasic/QB4.5/PDS/VBDOS) and be shocked with its "correct" answer (10 10 10 2 :shock:)

Interesting thing: I tried it in QB45, and indeed it happens like you described. Then I tried compiling it (with "make exe file"), and the compiled program returns 10 10 2 2). So, the interpreter is not consistent with the compiler.

Indeed, the "correct" behavior is the most logical one for a compiler (since it works by reference). Looks like the interpreter, on the other hand, works on a copy and tries to adjust the references in the end.
Post Reply