Posts: 652
Threads: 96
Joined: Apr 2022
Reputation:
22
I read that there is only one difference between Subs and Functions: a function returns a value, while a Sub doesn't. But as far as I see it, you can use Subs everywhere that you could use a Function. If I call a Sub, with variable parameters, I can work on those variables and (as long as they're Common Shared) I get the changes back in the main prog. Is there some other subtle difference? if not, it seems like Functions are an unnecessary item.
Posts: 276
Threads: 14
Joined: Apr 2022
Reputation:
27
08-19-2022, 01:44 AM
(This post was last modified: 08-19-2022, 02:02 AM by OldMoses.)
(08-19-2022, 01:00 AM)PhilOfPerth Wrote: I read that there is only one difference between Subs and Functions: a function returns a value, while a Sub doesn't. But as far as I see it, you can use Subs everywhere that you could use a Function. If I call a Sub, with variable parameters, I can work on those variables and (as long as they're Common Shared) I get the changes back in the main prog. Is there some other subtle difference? if not, it seems like Functions are an unnecessary item.
True that you can change values of parameters provided to SUBs, and I often do, but the main difference would be that a FUNCTION can be used in an expression directly to provide a value for use in the expression. A SUB will not do that.
Example:
Code: (Select All) a% = 2
b% = 4
c% = a% + b% + MultF(a%, b%)
PRINT c%
d%=a%+b%+mults k%,a%,b%
PRINT d%
MultS k%, a%, b%
PRINT k%
FUNCTION MultF (var1%, var2%)
MultF = var1% * var2%
END FUNCTION
SUB MultS (result%, var1%, var2%)
result% = var1% * var2%
END SUB
This simply won't compile. The system doesn't know what to do with it until you comment the offending line out.
DO: LOOP: DO: LOOP
sha_na_na_na_na_na_na_na_na_na:
Posts: 3,978
Threads: 177
Joined: Apr 2022
Reputation:
220
That's funny people at Python say, "Why do you need Subs, we don't!"
b = b + ...
Posts: 276
Threads: 14
Joined: Apr 2022
Reputation:
27
(08-19-2022, 02:05 AM)bplus Wrote: That's funny people at Python say, "Why do you need Subs, we don't!"
Those folks are tossin' too many tuples...
DO: LOOP: DO: LOOP
sha_na_na_na_na_na_na_na_na_na:
Posts: 301
Threads: 16
Joined: Apr 2022
Reputation:
51
I use SUBs in place of FUNCTIONs when I need to return two values, ie complex numbers.
here is an example of my complex math library which is a mixture of SUBs and FUNCTIONs
Code: (Select All) defdbl a-z
const sw = 800
const sh = 600
dim shared pi
pi = 4*atn(1)
zoom = 140
screen _newimage(sw, sh, 32)
_screenmove 100,100
dim as long i, xx, yy
for i=0 to 3
for yy=0 to sh
for xx=0 to sw
x = (xx - sw/2)/zoom
y = (sh/2 - yy)/zoom
select case i
case 0
u = x
v = y
pset (xx, yy), hrgb(u, v)
'pset (xx, yy), checker(u, v)
case 1
cdiv u, v, 1, 0, x, y
'pset (xx, yy), hrgb(u, v)
pset (xx, yy), checker(u, v)
case 2
cmul u, v, 1, 0, x - cos(2*pi/3), y + sin(2*pi/3)
cmul u, v, u, v, x - cos(2*pi/3), y - sin(2*pi/3)
cmul u, v, u, v, x - 1, y
'cdiv u, v, u, v, x - 1, y
pset (xx, yy), hrgb(u, v)
'pset (xx, yy), checker(u, v)
case 3
n = 10
uu = 0
vv = 0
for j=0 to n - 1
p = 1.5*cos(j*2*pi/n)
q = 1.5*sin(j*2*pi/n)
cmul u, v, 1, 0, p - cos(2*pi/3), q + sin(2*pi/3)
cmul u, v, u, v, p - cos(2*pi/3), q - sin(2*pi/3)
cmul u, v, u, v, p - 1, q
cdiv u, v, u, v, p - x, q - y
cmul u, v, u, v, -1.5*sin(j*2*pi/n), 1.5*cos(j*2*pi/n)
if j = 0 or j = n - 1 then
uu = uu + 0.5*u
vv = vv + 0.5*v
else
uu = uu + u
vv = vv + v
end if
next
u = uu*2*pi/n
v = vv*2*pi/n
cmul u, v, u, v, 0, -1/(2*pi)
pset (xx, yy), hrgb(u, v)
'pset (xx, yy), checker(u, v)
end select
next
next
'''diagram
select case i
case 3
a = 0
x = 1.5*cos(a)
y = 1.5*sin(a)
circle (x*zoom + sw/2, sh/2 - y*zoom), 3, _rgb(255,255,0)
for a=0 to 2*pi step 2*pi/n
x = 1.5*cos(a)
y = 1.5*sin(a)
line -(x*zoom + sw/2, sh/2 - y*zoom), _rgb(255,255,0)
circle step(0,0), 3, _rgb(255,255,0)
next
end select
sleep
next
system
function checker~&(xx, yy)
if 1 then
x = xx
y = yy
else 'polar checkerboard
x = _atan2(yy, xx)/(pi/4)
y = sqr(xx*xx + yy*yy)
y = log(1 + 1000*y)
end if
z = abs(x - int(x)) xor abs(y - int(y))
if z then checker = _rgb(0,0,0) else checker = _rgb(255,255,255)
end function
function hrgb~&(x, y)
m = sqr(x*x + y*y)
a = (pi + _atan2(y, x))/(2*pi)
'm = log(1 + 1000*m)
r = 0.5 - 0.5*sin(2*pi*a - pi/2)
g = (0.5 + 0.5*sin(2*pi*a*1.5 - pi/2)) * -(a < 0.66)
b = (0.5 + 0.5*sin(2*pi*a*1.5 + pi/2)) * -(a > 0.33)
'polar contouring
n = 16
mm = m*500 mod 500
p = abs(a*n - int(a*n))
r = r - 0.0005*mm - 0.14*p
g = g - 0.0005*mm - 0.14*p
b = b - 0.0005*mm - 0.14*p
'cartesian shading
if 0 then
t = 0.03 'thickness
xx = abs(x - int(x)) < t or abs(-x - int(-x)) < t
yy = abs(y - int(y)) < t or abs(-y - int(-y)) < t
if xx or yy then
'if m > 1 then 'dont shade origin
r = r - 0.5
g = g - 0.5
b = b - 0.5
'end if
end if
end if
hrgb = _rgb(255*r, 255*g, 255*b)
end function
sub cmul(u, v, xx, yy, aa, bb)
x = xx
y = yy
a = aa
b = bb
u = x*a - y*b
v = x*b + y*a
end sub
sub cdiv(u, v, xx, yy, aa, bb)
x = xx
y = yy
a = aa
b = bb
d = a*a + b*b
u = (x*a + y*b)/d
v = (y*a - x*b)/d
end sub
sub cexp(u, v, xx, yy, aa, bb)
x = xx
y = yy
a = aa
b = bb
lnz = x*x + y*y
if lnz = 0 then
u = 0
v = 0
else
lnz = 0.5*log(lnz)
argz = _atan2(y, x)
m = exp(a*lnz - b*argz)
a = a*argz + b*lnz
u = m*cos(a)
v = m*sin(a)
end if
end sub
sub clog(u, v, xx, yy)
x = xx
y = yy
lnz = x*x + y*y
if lnz=0 then
u = 0
v = 0
else
u = 0.5*log(lnz)
v = _atan2(y, x)
end if
end sub
function cosh(x)
cosh = 0.5*(exp(x) + exp(-x))
end function
function sinh(x)
sinh = 0.5*(exp(x) - exp(-x))
end function
sub csin(u, v, xx, yy)
x = xx
y = yy
u = sin(x)*cosh(y)
v = cos(x)*sinh(y)
end sub
sub ccos(u, v, xx, yy)
x = xx
y = yy
u = cos(x)*cosh(y)
v =-sin(x)*sinh(y)
end sub
function factorial~&(n)
if n = 0 then
factorial = 1
else
factorial = n*factorial(n - 1)
end if
end function
Posts: 652
Threads: 96
Joined: Apr 2022
Reputation:
22
08-19-2022, 05:40 AM
(This post was last modified: 08-19-2022, 05:44 AM by PhilOfPerth.)
@oldmoses: I can see that this can be a way to achieve what you wanted, but it can be done with a Sub as well, with the same result and about the same amount of coding. Why try to ride two ponies when one can take you anywhere?
Posts: 2,697
Threads: 327
Joined: Apr 2022
Reputation:
217
The difference is rather simple:
SUBS **do** something. FUNCTIONS **return** something.
CLS, PRINT, BEEP -- these are all subs as they do something.
_KEYHIT, _MOUSEINPUT, INKEY$ -- these are all functions as they return something.
Now, you talk about returning values via parameter, and this is true -- but only in limited scope as the parameter types must match.
SUB foo (x AS INTEGER) will pass the value of x to the reference variable ONLY if it's an integer. Pass it a byte, long, constant, single, or anything else, and that value won't pass back.
FUNCTION, on the other hand, always returns a given type value.
FUNCTION foo% (x) -- pass it a byte, long, single, const, literal... doesn't matter! You'll still get back an integer value!
**************
As for the biggest difference between the two, I'd say that's obvious with this little example:
PRINT TIMER
Print is a SUB. Timer is a function. Yet, the two are working together here on the same line!! Try that with any two SUBs and see what happens!
PRINT CLS
Posts: 2,697
Threads: 327
Joined: Apr 2022
Reputation:
217
As for SHARED variables be used to pass results, do you *really* want to double up on your words to remember like that??
Right now, if you want the time, you just call the function TIME$. If that function was a SUB, it'd have to look like:
SUB GetTime$
SHARED Time$
Time$ = SystemTime$
END SUB
Then we'd have to code with:
GetTime$ 'call the sub
PRINT Time$ 'use the shared variable
TWO keywords to remember to do one thing.... and add in that complexity to a 100,000 line program like QB64.bas... Would anyone **really** want that??
Posts: 652
Threads: 96
Joined: Apr 2022
Reputation:
22
Ok, thanks Steve. I can see now there are places where one would be preferable to the other.
But in programmes of the (lack of) size of mine, I guess I'll still find it easier to stay with one - even at the expense of having to remember another variable's name.
Posts: 276
Threads: 14
Joined: Apr 2022
Reputation:
27
(08-19-2022, 05:40 AM)PhilOfPerth Wrote: @oldmoses: I can see that this can be a way to achieve what you wanted, but it can be done with a Sub as well, with the same result and about the same amount of coding. Why try to ride two ponies when one can take you anywhere?
My point in my example was that I had to create a proxy variable in order to do the same thing with a SUB. If there's already an existing variable to modify, then that's fine and in many cases even optimal, but often you need a number for a quick IF...THEN check and don't need to keep it, or you need to place conditions on a particular part of an expression. Don't muddle up the code with extraneous variables and multiple lines of unnecessary code that no one is going to want to wade through to look at if you have problems.
It's best to become accustomed to using the right tools for the task before that happens. Clean and concise code will follow naturally.
If you need a number in a computation that you don't need to keep for something else, but you find yourself doing the same thing over and over, you're going to want to use the function.
Even my own example can benefit from additional optimization thanks to function use
Code: (Select All) a% = 2
b% = 4
PRINT a% + b% + MultF(a%, b%) ' don't need the c% variable after all
MultS k%, a%, b%
PRINT k%
FUNCTION MultF (var1%, var2%)
MultF = var1% * var2%
END FUNCTION
SUB MultS (result%, var1%, var2%)
result% = var1% * var2%
END SUB
DO: LOOP: DO: LOOP
sha_na_na_na_na_na_na_na_na_na:
|