BBC BASIC: DEFPROC "promotes" local integer variables?

Discuss all aspects of programming here. From 8-bit through to modern architectures.
Post Reply
User avatar
lurkio
Posts: 2147
Joined: Tue Apr 09, 2013 11:30 pm
Location: Doomawangara
Contact:

BBC BASIC: DEFPROC "promotes" local integer variables?

Post by lurkio » Thu Jul 11, 2019 11:33 pm

I was rummaging around in the listings for To Hell In A Hamper when I noticed what I thought was a surprising way of passing integer values between BASIC programs on the Beeb when a program CHAINs another program.

It seems that if the parameter to a procedure has the name of one of the resident integer variables -- say J% -- and if that procedure then CHAINs another program, then the value of J% inside the procedure in the first program -- where I presume J% is implicitly a LOCAL variable -- seems to be transferred to the "global" resident integer variable J% and is available to the CHAINed program.

Here's Example Program 1:

Code: Select all

 10 J%=0
 20 PRINT J%
 30 PROCa(10)
 40 PRINT J%
 50 PROCb(10)
 60 END
 70 DEFPROCa(J%)
 80 J%=J%+1
 90 ENDPROC
100 DEFPROCb(J%)
110 CHAIN"2"
120 ENDPROC
And here's Example Program 2, which is CHAINed by Example Program 1:

Code: Select all

10 PRINT'J%
The output on screen when you run program 1 (which CHAINs program 2) is as follows:

Code: Select all

0
0

10
Is this behaviour well known and/or documented? I've never come across it before, and I wouldn't have expected it to work because I wouldn't expect the value of the implicit LOCAL variable J% in DEFPROCb in program 1 to be transferred to program 2 at all.

:?:

User avatar
jgharston
Posts: 3596
Joined: Thu Sep 24, 2009 11:22 am
Location: Whitby/Sheffield
Contact:

Re: BBC BASIC: DEFPROC "promotes" local integer variables?

Post by jgharston » Thu Jul 11, 2019 11:55 pm

Yep, it's documented. CHAIN does not change any of A%-Z% regardless of how A%-Z% have been set at the point of the CHAIN.

The only thing that restores local variables to their previous value is ENDPROC or =returnval. There's really no such thing as "local" variables in BBC BASIC, there are only "current" variables and "saved" variables.

Code: Select all

$ bbcbasic
PDP11 BBC BASIC IV Version 0.25
(C) Copyright J.G.Harston 1989,2005-2015
>_

User avatar
Richard Russell
Posts: 877
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: BBC BASIC: DEFPROC "promotes" local integer variables?

Post by Richard Russell » Fri Jul 12, 2019 8:26 pm

jgharston wrote:
Thu Jul 11, 2019 11:55 pm
There's really no such thing as "local" variables in BBC BASIC, there are only "current" variables and "saved" variables.
Yes. Understanding that BBC BASIC doesn't have 'local' variables in the traditional sense can be important, such as what happens if you exit from a FN or PROC via any mechanism other than the = or ENDPROC (e.g. an ON ERROR); in that case the 'saved' variables never get restored and the 'local' variables suddenly become 'global'!

What would be really useful is a statement that restores those saved variables without exiting from the FN/PROC, so that in the event of a trappable error being detected you could restore them before activating the error handler. So useful in fact that I have added exactly that to BBC BASIC for Windows and BBC BASIC for SDL 2.0: RESTORE LOCAL. I suspect this could easily be added to any BBC BASIC interpreter, since it doesn't need any new keywords and is activating a mechanism that must already exist.

User avatar
Rich Talbot-Watkins
Posts: 1509
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: BBC BASIC: DEFPROC "promotes" local integer variables?

Post by Rich Talbot-Watkins » Mon Jul 15, 2019 10:28 am

Also, consider the following:

Code: Select all

10 PROCp(23)
20 PRINT a%
30 END
40 DEF PROCp(a%)
50 PRINT a%
60 ENDPROC
a% continues to exist outside PROCp after it's called (albeit with a default value) - which is something you wouldn't expect if it was genuinely a local variable. Acorn BBC BASIC has no way of deleting a variable which has been defined (other than the nuclear option, CLEAR!) - don't know if that's also true of Richard's BASICs, but I don't imagine there to be much reason to support it because of the way BBC BASIC works.

User avatar
Richard Russell
Posts: 877
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: BBC BASIC: DEFPROC "promotes" local integer variables?

Post by Richard Russell » Mon Jul 15, 2019 11:52 am

Rich Talbot-Watkins wrote:
Mon Jul 15, 2019 10:28 am
Acorn BBC BASIC has no way of deleting a variable which has been defined (other than the nuclear option, CLEAR!) - don't know if that's also true of Richard's BASICs, but I don't imagine there to be much reason to support it because of the way BBC BASIC works.
The way the heap is managed means that you cannot 'delete' a local object (other than via CLEAR as you say), all you can do is to set it to zero or some other special value. The effect of that differs depending on the kind of object it is: if it's a scalar variable then afterwards the variable 'exists' but has the value zero (and is thus indistinguishable from an ordinary global variable). However if it's a local array (or in the case of my BASICs a local structure) then what's stored in the heap is a pointer, and setting that pointer to zero does establish a state different from an ordinary global object of the same type.

Contrast the program you listed with this one:

Code: Select all

   10 PROCp
   20 PRINT a(5)
   30 END
   40 DEF PROCp
   50 LOCAL a()
   60 DIM a(9)
   70 a(5) = 23
   80 PRINT a(5)
   90 ENDPROC
Now the PRINT statement at line 20 reports an error ("Bad use of array" in BB4W/BBCSDL and "Undimensioned array" in ARM BASIC V) so although it hasn't been 'deleted' it is distinguishable from a global array.

User avatar
Rich Talbot-Watkins
Posts: 1509
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: BBC BASIC: DEFPROC "promotes" local integer variables?

Post by Rich Talbot-Watkins » Mon Jul 15, 2019 12:43 pm

Can you redimension it outside the PROC in this case? Normally that's not allowed, but is there special dispensation given to arrays which have been nullified in this way? (I would assume it works, otherwise it wouldn't be possible to call PROCp more than once!)

User avatar
lurkio
Posts: 2147
Joined: Tue Apr 09, 2013 11:30 pm
Location: Doomawangara
Contact:

Re: BBC BASIC: DEFPROC "promotes" local integer variables?

Post by lurkio » Mon Jul 15, 2019 3:13 pm

Richard Russell wrote:
Fri Jul 12, 2019 8:26 pm
Understanding that BBC BASIC doesn't have 'local' variables in the traditional sense can be important, such as what happens if you exit from a FN or PROC via any mechanism other than the = or ENDPROC (e.g. an ON ERROR); in that case the 'saved' variables never get restored and the 'local' variables suddenly become 'global'!
Never knew that. How curious.

Code: Select all

>LIST
   10 ON ERROR PRINT a$:END
   20 a$="hello"
   30 PROCa
   40 END
   50 DEFPROCa:LOCAL a$
   60  a$="goodbye"
   70  thisIsAnError
   80 ENDPROC
>RUN
goodbye
>PRINT a$
goodbye
>_
EDITED to add this:
Rich Talbot-Watkins wrote:
Mon Jul 15, 2019 10:28 am

Code: Select all

10 PROCp(23)
20 PRINT a%
30 END
40 DEF PROCp(a%)
50 PRINT a%
60 ENDPROC
a% continues to exist outside PROCp after it's called (albeit with a default value) - which is something you wouldn't expect if it was genuinely a local variable. Acorn BBC BASIC has no way of deleting a variable which has been defined (other than the nuclear option, CLEAR!)
This is quite an eye-opener. Here's the effect demonstrated in greater detail:

Code: Select all

>LIST
   10 ON ERROR PRINT "Error: a% doesn't 'exist'.":GOTO 30
   20 PRINT a%
   30 PROCa
   40 PRINT "Suddenly a% exists and its value is ";a%;"."
   50 END
   60 DEFPROCa:LOCAL a%
   70 PRINT "PROCa has been called."
   80 ENDPROC
>RUN
Error: a% doesn't 'exist'.
PROCa has been called.
Suddenly a% exists and its value is 0. 
>_
:shock:
Last edited by lurkio on Mon Jul 22, 2019 8:40 pm, edited 1 time in total.

User avatar
Richard Russell
Posts: 877
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: BBC BASIC: DEFPROC "promotes" local integer variables?

Post by Richard Russell » Mon Jul 15, 2019 4:12 pm

Rich Talbot-Watkins wrote:
Mon Jul 15, 2019 12:43 pm
Can you redimension it outside the PROC in this case?
Yes. The array wouldn't be 'local' in any meaningful sense if you couldn't.

Mind you ARM BASIC V has some quirks. For example by my reckoning this ought to work; it does in my BASICs but for some reason it doesn't in ARM BASIC:

Code: Select all

   10 PROCp(a())
   20 a(5) = 23
   30 PRINT a(5)
   40 END
   50
   60 DEF PROCp(RETURN a())
   70 DIM a(10)
   80 ENDPROC
ARM BASIC reports 'Undimensioned array at line 20', but it isn't undimensioned (it was dimensioned in line 70 and I've specified that it be RETURNed from the procedure). I have made use of that feature many times and I wouldn't want to be without it, so why it doesn't work in Acorn's versions I have no idea.

User avatar
Richard Russell
Posts: 877
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: BBC BASIC: DEFPROC "promotes" local integer variables?

Post by Richard Russell » Mon Jul 15, 2019 4:24 pm

lurkio wrote:
Mon Jul 15, 2019 3:13 pm
Never knew that. How curious.
I wouldn't exactly say "curious", it's what you would expect given the way BBC BASIC works, but it's a significant limitation that Acorn versions provide no way to work around it. RESTORE LOCAL allows an error to be passed back down the 'call chain', with local variables being restored at each level, so that each function is given the opportunity to do something in that event:

Code: Select all

        ON ERROR PRINT "Error: " REPORT$ : END
        PROC1
        END
 
        DEF PROC1
        ON ERROR LOCAL RESTORE LOCAL : PRINT "Error handled in PROC1" : ERROR ERR,REPORT$
        PROC2
        ENDPROC
 
        DEF PROC2
        LOCAL A
        ON ERROR LOCAL RESTORE LOCAL : PRINT "Error handled in PROC2" : ERROR ERR,REPORT$
        A = 1/0
        ENDPROC
which reports:

Code: Select all

Error handled in PROC2
Error handled in PROC1
Error: Division by zero
>
This is functionality I couldn't live without.

Post Reply