Documentation Modifying GOSUB parameters

Apr 13, 2010
223
2
57
The Hague
#1
The manual states that GOSUB parameters "cannot be modified with the SET, ESET, or UNSET commands" (among other things). However, I have been modifying them and subsequently using them without problems for many years.

So? What is the status of this part of the manual?

Regards, DJ
 
Last edited by a moderator:
Dec 2, 2008
212
2
Canada
#2
Code:
@echo off
SET p1="P1"
GOSUB Label1 %p1
echo %p1
GOTO ExitPt

:Label1 [a1]
echo %a1   
SET a1="a1"
echo %a1     
RETURN

:ExitPt
echo Done
Yeilds:

Code:
"P1"
"P1"
"P1"
Done
There is an attempt to change a1 by using a "SET" within the body of the subroutine but the "SET" had no effect on the value a1. That seems to fit with the documentation.
 
Apr 13, 2010
223
2
57
The Hague
#3
From the helpfile:
GOSUB variables are placed in the environment in a special form for the duration of the subroutine, and will "mask" any environment variables of the same name that existed before the subroutine was called. GOSUB variables can be referenced like normal environment variables, but are not stored in the same way, cannot be modified with the SET, ESET, or UNSET commands, and cannot be used with the DEFINED test of IF, IFF, or @IF.

You cannot use SET within a subroutine to change the value of a GOSUB variable. If you attempt to do so, the SET command will set the standard environment variable of the same name, not the GOSUB variable, but this value will be "masked" by the GOSUB variable and will remain inaccessible until the subroutine ends.
I feel this text confuses more than it explains. The "gosub variables" sometimes refers to local stack variables and at other times to the "masked" environment variables.

The second sentence of the second paragraph is especially confusing as it seems to suggest that such a SET operation will be aimed at an environment variable and somehow fail. Which is nonsense. What it does is that it will succesfully set the local variable.
 
Dec 2, 2008
212
2
Canada
#4
I changed the original btm file:

Code:
@echo off
@echo ==== Pre-GOSUB ====  
REM ====
REM =  Pre-GOSUB Variables
REM ====
SET P1="Pre-GOSUB P1"
SET A1="Pre-GOSUB A1"
echo %P1  
echo %A1
GOSUB Label1 %P1  
@echo ==== Post-GOSUB ====
REM ====
REM =  Both P1 and A1 were change in the GOSUB
REM ====
echo %P1
echo %A1
GOTO ExitPt

:Label1 [A1]
@echo ==== In-GOSUB ====
echo %A1
REM ====
REM =  These SET calls will only effect the Pre-GOSUB Variables
REM ====
SET P1="In-GOSUB P1"
SET A1="In-GOSUB A1"
REM ====
REM =  The following will echo the Pre-GOSUB P1
REM ====
echo %P1
REM ====
REM =  The following will echo the In-GOSUB A1, the Pre-GOSUB A1 is masked
REM ====
echo %A1
RETURN

:ExitPt
echo Done
Running this yields:

Code:
==== Pre-GOSUB ====
"Pre-GOSUB P1"
"Pre-GOSUB A1"
==== In-GOSUB ====
"Pre-GOSUB P1"
"In-GOSUB P1"
"Pre-GOSUB P1"
==== Post-GOSUB ====
"In-GOSUB P1"
"In-GOSUB A1"
Done
Which based on the documentation is what I expected. Can you give an example that seems to go outside the documentation's description of localized GOSUB variables?
 
Apr 13, 2010
223
2
57
The Hague
#5
Thank you for your reply.

I indicated that my comment is aimed at the documentation. I am not commenting on functionality. In my first post I wrote that I have been using this functionality without problems for many years. I am surprised that you are putting so much effort into producing code, although your effort is appreciated of course. However, I was hoping for alternative wording of the documentation, not code.

I have a clear understanding of "GOSUB variables" personally, but I am concerned that less experienced users might be confused by the documentation. Perhaps this is such a case where people are so familiar with a text that even imagining an other wording seems impossible. As a foreigner I am somewhat apprehensive to offer alternatives but I will try to contribute.

Please look at this sentence.
GOSUB variables are placed in the environment in a special form for the duration of the subroutine, and will "mask" any environment variables of the same name that existed before the subroutine was called.
Here the author speaks of "GOSUB variables" as local variables. Now skip ahead to the first sentence of the next paragraph. The author states:
You cannot use SET within a subroutine to change the value of a GOSUB variable
Because the concept "GOSUB variables" is not clearly defined is seems the author is saying that the local variables cannot be modified, which is probably not what he/she intended to say. If you look at the rest of this piece of documentation in this manner you will find other such quirks.

A replacement text should clarify the difference between "masked" and "normal" environment variables on the one hand and by-value parameters on the other.

I hope at least my explanation was of some help.
DJ
 
Apr 13, 2010
223
2
57
The Hague
#7
No. Sorry, I give up. This is getting out of hand again. It must be a language barrier or something.
Apparently I am unable to express my point clear enough.

Regards, DJ.
 
#8
How about if they were called parameters (or arguments) of the subroutine ... if it were noted that they are read-only ... and that they can be accessed as if they were variables (i.e., with "%")? Would that make more sense?

Although they are in the environment, TCC's SET will not show them to you (but you can see them if you have a way to snoop on another process's environment). They are special in that their names are prefixed with the two characters 0x01 and 0x02. These prefixes change with the subroutine nesting level. So, if you go out of your way (I see no need to do so) you can modify them. Try this:
Code:
set str1=123
gosub xxx foo bar
quit

:xxx [str1 str2]
echo Before: %str1 %str2
set str1
set %@char[1]%@char[2]str1=new
echo After:  %str1 %str2
set str1
pause
return
I see:
Code:
v:\> speed.btm
Before: foo bar
123
After:  new bar
123
Press any key when ready...
 
Dec 10, 2014
63
1
#9
So, if you go out of your way (I see no need to do so) you can modify them.
Thanks, that's interesting.

I always found it somewhat counter-intuitive that tcc protects these parameter variables, as it imho it is bound to create confusion. The very least would be for tcc to return an error when trying to set a "protected" variable in a sub instead of just ignoring it?
 
#10
Thanks, that's interesting.

I always found it somewhat counter-intuitive that tcc protects these parameter variables, as it imho it is bound to create confusion. The very least would be for tcc to return an error when trying to set a "protected" variable in a sub instead of just ignoring it?
One virtue of the way it's done now is that TCC can very easily keep track of the subroutine parameters at every level, even when the same subroutine is called recursively, and it can delete them when they go out of scope (i.e., upon RETURN). With ordinary, visibly-named environment variables, that wouldn't be easy at all, and you definitely couldn't call the same subroutine recursively
 
Dec 10, 2014
63
1
#11
With ordinary, visibly-named environment variables, that wouldn't be easy at all, and you definitely couldn't call the same subroutine recursively
Maybe so, but I'd guess that the amount of people being confused by the immutable sub vars is higher than shell wizards recursively calling a sub ... the latter sounds like high performance computing I'd do in C, or maybe perl/python/..., but not a windows shell script.

My personal issue remains that there is no warning or error message whatsoever on trying to set a protected var, and if it would be up to me I'd like an option to let the user chose if sub vars should be protected or not.