Why do we need Functions?
#1
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.  Confused
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, W.A.) Big Grin
Reply
#2
(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.  Confused

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:
Reply
#3
That's funny people at Python say, "Why do you need Subs, we don't!"
b = b + ...
Reply
#4
(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... Big Grin
DO: LOOP: DO: LOOP
sha_na_na_na_na_na_na_na_na_na:
Reply
#5
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
Reply
#6
@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?
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, W.A.) Big Grin
Reply
#7
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
Reply
#8
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??
Reply
#9
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.
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, W.A.) Big Grin
Reply
#10
(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:
Reply




Users browsing this thread: 8 Guest(s)