When you want to return more than one value from within a function there are several ways to do that, including arrays, memblocks, global variables, encoding the values into individual bytes of an integer and probably much more.
I wanted to find a way to do that in a relatively efficient yet convenient way, so I wrote some stack-functions that allow just that.
Note that the stacks I'm talking about are not 100% equal to what computer scientists usually refer to as stacks - the difference here is that "my" stacks have a fixed capacity and can't run into overflows. This, however, leads to the problem that when you store too many values at once, some of them will be overwritten. However, since you rarely return more than 256 (that's the current capacity, can be changed easily using a constant) values at once, this should not happen usually. The only problem you could still run into is a situation where several nested function calls all access this stack, in this case things could get pretty messed up, so you might want to avoid that in case you are going to use those functions.
First, here's the command set:
stack_init() - has to be called once initially, sets up arrays etc.
stack_pushInt(i) - stores one integer on top of the int-stack
stack_pushFloat(f#) - stores one float on top of the float-stack
stack_pushString(s$) - stores one string on top of the string-stack
stack_popInt() - takes one integer from the int-stack
stack_popFloat() - takes one float from the float-stack
stack_popString() - takes one string from the string-stack
stack_getInt() - returns one integer from the int-stack without removing it
stack_getFloat() - returns one float from the float-stack without removing it
stack_getString() - returns one string from the string-stack without removing it
When using these functions for function return values, one advantage is that the amount of returned arguments does not need to be constant. Consequently you can, for instance, write a simple split string-function that returns string-parts dynamically depending on how many are existing.
Code with examples:
rem START OF EXAMPLE
stack_init()
rem Fraction-Function
for i = 1 to 3
input "Insert a real number>", inp$
a = fraction(val(inp$))
print inp$, " = ", a, " + ", str$(stack_getFloat(),3)
print
next i
cls
rem Sort3-Function
for i = 1 to 10
a = 1 + rnd(8) : b = 1 + rnd(8) : c = 1 + rnd(8)
Sort3(a,b,c)
print a, ",", b, ",", c, " sorted: ", stack_popInt(), ",", stack_popInt(), ",", stack_popInt()
wait key
next i
cls
rem Split String
s$ = "this,is,a,set,of,words,separated,by,single,comma,characters"
count = Split(s$)
print "Original String: ", s$
for i = 1 to count
print i, ". ", stack_popString()
next i
wait key
cls
rem Stability Testing with forced overflow
print "Stability Testing..."
for i = 1 to 1000
a = rnd(100) : b = rnd(100) : c = rnd(100)
Sort3(a,b,c)
next i
print " Test 1 worked"
rem Stability Testing without overflow
for i = 1 to 1000
a = rnd(100) : b = a+1+rnd(100) : c = b+1+rnd(100)
Sort3(a,b,c)
x = stack_popInt() : y = stack_popInt() : z = stack_popInt()
if x > y or y > z then print "Fatal Error: Sorting did not work out well! (", a, ",", b, ",", c, ") -> (", x, ",", y, ",", z, ")"
next i
print " Test 2 worked"
rem Stability Testing with underflow
for i = 1 to 4000
x = stack_popInt()
next i
print " Test 3 worked"
print "Press any key to quit!"
wait key
end
function fraction(a#)
i = floor(a#)
stack_PushFloat(a#-i)
endfunction i
function Sort3(a,b,c)
if a > b
if a > c
stack_pushInt(a) : if b > c : stack_pushInt(b) : stack_pushInt(c) : else : stack_pushInt(c) : stack_pushInt(b) : endif
else
stack_pushInt(c) : stack_pushInt(a) : stack_pushInt(b)
endif
else
if b > c
stack_pushInt(b) : if a > c : stack_pushInt(a) : stack_pushInt(c) : else : stack_pushInt(c) : stack_pushInt(a) : endif
else
stack_pushInt(c) : stack_pushInt(b) : stack_pushInt(a)
endif
endif
endfunction
function split(s$)
s$ = "," + s$
L = len(s$)
cur$ = ""
count = 0
rem Split string up in reverse order (so that the LIFO-stack returns them correctly)
for i = L to 1 step -1
m$ = mid$(s$,i)
if m$ = ","
inc count
stack_pushString(cur$)
cur$ = ""
else
cur$ = m$ + cur$
endif
next i
endfunction count
rem END OF EXAMPLE
rem Size of individual stacks (integer, float, string)
#constant STACK_CAPACITY = 256
rem Has to be equal to STACK_CAPACITY - 1
#constant STACK_CAPACITY1 = 255
function stack_init()
dim stack_int(STACK_CAPACITY1) as integer
dim stack_float(STACK_CAPACITY1) as float
dim stack_string(STACK_CAPACITY1) as string
global stack_intCurrent as integer = 0
global stack_floatCurrent as integer = 0
global stack_stringCurrent as integer = 0
endfunction
remstart
PUSH functions write a new value to the stack
if you push more than STACK_CAPACITY values at once, some will be overwritten!
remend
function stack_pushInt(i)
stack_intCurrent = (stack_intCurrent + 1) mod STACK_CAPACITY
stack_int(stack_intCurrent) = i
endfunction
function stack_PushFloat(f#)
stack_floatCurrent = (stack_floatCurrent + 1) mod STACK_CAPACITY
stack_float(stack_floatCurrent) = f#
endfunction
function stack_pushString(s$)
stack_stringCurrent = (stack_stringCurrent + 1) mod STACK_CAPACITY
stack_string(stack_stringCurrent) = s$
endfunction
remstart
POP functions return a value from the stack and remove it at the same time
remend
function stack_popInt()
i = stack_int(stack_intCurrent)
stack_intCurrent = (stack_intCurrent + STACK_CAPACITY1) mod STACK_CAPACITY
endfunction i
function stack_popFloat()
f# = stack_float(stack_floatCurrent)
stack_floatCurrent = (stack_floatCurrent + STACK_CAPACITY1) mod STACK_CAPACITY
endfunction f#
function stack_popString()
s$ = stack_string(stack_stringCurrent)
stack_stringCurrent = (stack_stringCurrent + STACK_CAPACITY1) mod STACK_CAPACITY
endfunction s$
remstart
GET functions return a value from the stack without removing it
remend
function stack_getInt()
i = stack_int(stack_intCurrent)
endfunction i
function stack_getFloat()
f# = stack_float(stack_floatCurrent)
endfunction f#
function stack_getString()
s$ = stack_string(stack_stringCurrent)
endfunction s$
Stack-Library only:
rem Size of individual stacks (integer, float, string)
#constant STACK_CAPACITY = 256
rem Has to be equal to STACK_CAPACITY - 1
#constant STACK_CAPACITY1 = 255
function stack_init()
dim stack_int(STACK_CAPACITY1) as integer
dim stack_float(STACK_CAPACITY1) as float
dim stack_string(STACK_CAPACITY1) as string
global stack_intCurrent as integer = 0
global stack_floatCurrent as integer = 0
global stack_stringCurrent as integer = 0
endfunction
remstart
PUSH functions write a new value to the stack
if you push more than STACK_CAPACITY values at once, some will be overwritten!
remend
function stack_pushInt(i)
stack_intCurrent = (stack_intCurrent + 1) mod STACK_CAPACITY
stack_int(stack_intCurrent) = i
endfunction
function stack_PushFloat(f#)
stack_floatCurrent = (stack_floatCurrent + 1) mod STACK_CAPACITY
stack_float(stack_floatCurrent) = f#
endfunction
function stack_pushString(s$)
stack_stringCurrent = (stack_stringCurrent + 1) mod STACK_CAPACITY
stack_string(stack_stringCurrent) = s$
endfunction
remstart
POP functions return a value from the stack and remove it at the same time
remend
function stack_popInt()
i = stack_int(stack_intCurrent)
stack_intCurrent = (stack_intCurrent + STACK_CAPACITY1) mod STACK_CAPACITY
endfunction i
function stack_popFloat()
f# = stack_float(stack_floatCurrent)
stack_floatCurrent = (stack_floatCurrent + STACK_CAPACITY1) mod STACK_CAPACITY
endfunction f#
function stack_popString()
s$ = stack_string(stack_stringCurrent)
stack_stringCurrent = (stack_stringCurrent + STACK_CAPACITY1) mod STACK_CAPACITY
endfunction s$
remstart
GET functions return a value from the stack without removing it
remend
function stack_getInt()
i = stack_int(stack_intCurrent)
endfunction i
function stack_getFloat()
f# = stack_float(stack_floatCurrent)
endfunction f#
function stack_getString()
s$ = stack_string(stack_stringCurrent)
endfunction s$
There are, as mentioned before, many other ways to accomplish this, especially if the amount of returned values is known beforehand (e.g. if you want to return exactly two values, you could simply use a global to store the second one). However, using this library provides a simple and unified way to handle it, without producing too much overhead (i.e. the functions should be quite fast, although certainly slower than simply accessing one global variable instead).
On top of that they can be used for any purpose that requires a stack (although DBP provides functions for that, but in this case it is possible that the built in commands are slower (didn't test it) since they probably allocate memory on the fly, which is not the case for the functions above).
Hope it helps, although once again, it does not really provide any functionality that wasn't there before.
greetings,
MrK