Page 1 of 2 12>
Topic Options
#37511 - 2003-03-07 05:04 AM GOSUB vs. FUNCTION
JohnQ Offline
Starting to like KiXtart

Registered: 2003-03-04
Posts: 171
This is kind of a stupid question, but I don't mean for it to be...

What is the difference (or benefit) between using GOSUB or creating multiple functions and calling the functions when needed? You can easily make any chunk of code a function and use it the same as a subroutine. Does one execute faster than the other? It seems to me that you can acomplish the same tasks using either - I just wondered which was better and you guys are the experts.

Top
#37512 - 2003-03-07 05:06 AM Re: GOSUB vs. FUNCTION
Les Offline
KiX Master
*****

Registered: 2001-06-11
Posts: 12734
Loc: fortfrances.on.ca
Functions are better!
_________________________
Give a man a fish and he will be back for more. Slap him with a fish and he will go away forever.

Top
#37513 - 2003-03-07 05:11 AM Re: GOSUB vs. FUNCTION
Les Offline
KiX Master
*****

Registered: 2001-06-11
Posts: 12734
Loc: fortfrances.on.ca
Suppose you want to know why eh? You can package them up as 'include' libraries that you can then CALL from any script.

Unlike GOSUBs, you don't need to be concerned about falling into the script. The parser will never execute it regardless of where you place it. No need for GOTOs to step over them.
_________________________
Give a man a fish and he will be back for more. Slap him with a fish and he will go away forever.

Top
#37514 - 2003-03-07 05:11 AM Re: GOSUB vs. FUNCTION
JohnQ Offline
Starting to like KiXtart

Registered: 2003-03-04
Posts: 171
I have no problem taking your word for it, but would you mind briefly explaining why. For all of us wannabees out here.
Top
#37515 - 2003-03-07 05:13 AM Re: GOSUB vs. FUNCTION
Les Offline
KiX Master
*****

Registered: 2001-06-11
Posts: 12734
Loc: fortfrances.on.ca
Saw the error of my ways...
Look up.
_________________________
Give a man a fish and he will be back for more. Slap him with a fish and he will go away forever.

Top
#37516 - 2003-03-07 05:13 AM Re: GOSUB vs. FUNCTION
JohnQ Offline
Starting to like KiXtart

Registered: 2003-03-04
Posts: 171
Can you give a brief example of an "include library" like you mentioned?
Top
#37517 - 2003-03-07 05:14 AM Re: GOSUB vs. FUNCTION
Radimus Moderator Offline
Moderator
*****

Registered: 2000-01-06
Posts: 5187
Loc: Tampa, FL
Don't lay it on too thick now...

they are basically the same concept, except for an important distinction.

A function can accept values and can return a value. but basicaly think of it as building your own custom command, You pass a parameter(s) to it, and it performs a specific action based on/utilizing that value(s). what happens on the inside of the function is isolated (sort of) from the main body of the script.

If you tried hard enough you could make a gosub/return subroutine do the same sort of thing, but functions are much more efficient about it.

Consider it like this: In the great big book of everything, Gosubs are subroutines version 2. While Functions are subroutines Version 3 (goto is version 1, but no one wants to talk about those)
_________________________
How to ask questions the smart way <-----------> Before you ask

Top
#37518 - 2003-03-07 05:18 AM Re: GOSUB vs. FUNCTION
Les Offline
KiX Master
*****

Registered: 2001-06-11
Posts: 12734
Loc: fortfrances.on.ca
Any time you want to use code as a GOSUB routine, you need to have it in your script. If you have many scripts, you need many copies of the same subroutine. Later, if you want to revise it, you need to find and update all the copies.

With UDFs, you can put as many of them as are practical in one file and the just CALL it.

See the FAQ:
Topic: How to use UDFs
_________________________
Give a man a fish and he will be back for more. Slap him with a fish and he will go away forever.

Top
#37519 - 2003-03-07 09:22 AM Re: GOSUB vs. FUNCTION
Lonkero Administrator Offline
KiX Master Guru
*****

Registered: 2001-06-05
Posts: 22346
Loc: OK
uhm...

you can also call script-file (which is the actual meaning of the call)

I think UDF is good if it's made an UDF but making all your sub-scripts UDFs is blashemy.

I've seen even here on our UDF-library UDFs that have nothing to do with UDF but the "function" and "endfunction" keywords. [Mad]

if you don't want to use gosub or you want to have different pieces in different files, you can always use call to execute scriptlets.

the real benefit of UDF is that it's simple to use and it does not need modification after it's done.

and once optimized, it is speedy.
_________________________
!

download KiXnet

Top
#37520 - 2003-03-07 09:29 AM Re: GOSUB vs. FUNCTION
Jochen Administrator Offline
KiX Supporter
*****

Registered: 2000-03-17
Posts: 6380
Loc: Stuttgart, Germany
hmmm ... can you show me one Lonk ?

I for myself tend to pack all fragments that may be needed more than once into functions residing in the main script (These are then pretty specific and not worth to post here)

On the other side my scripts are then much smaller and can be better maintained (Function list available in Uedit [Wink] )
_________________________



Top
#37521 - 2003-03-07 10:30 AM Re: GOSUB vs. FUNCTION
Richard H. Administrator Offline
Administrator
*****

Registered: 2000-01-24
Posts: 4946
Loc: Leatherhead, Surrey, UK
An example might help.

Say you write an application that uses a database to store records. You want the very basic facilities like add a record, delete a record, find a record, list all records.

You could write these as subroutines in your application but there are two problems with that.
1) The code may be useful in other applications - using subroutines means that you need to cut and past the code - a big overhead in script size and maintenance.
2) You have to pass variables to/from the subroutine using global variables. This means that to use the subroutines you have to know what the variables are called, and your subroutine is in danger of overwriting variables that you are using in the main script.

You can solve "1" by simply putting each of your subroutines in a file on it's own, and CALLing the file. This will execute the script in the file as if it was in your main script. For example, you would place your add record routine in a file called "AddRecord.kix", and when you want to add a record you use the script command
code:
CALL "AddRecord.kix"

In this case your variables may be local, but you still need to know what they are, and you still need to be careful about overwriting variable in the main script.

Also there is the overhead of reading and parsing the file every time you make the CALL.

So, we come to the best all round option - libraries of functions.

Functions can be designed as black-boxes in almost all cases - there are a couple of exceptions which I'll note later.

The benefit of this is that you only ever have to know the function name and expected parameters. You don't need to know how it works, and you don't need to know what it is using as variables internally.

An additional but often overlooked benefit of functions is that you can set @ERROR on exiting the function. You use this in your main script to determine whether the function call worked or not.

For your database routines, you create a file called "SQLroutines.kix". In this file you create all of your functions:
code:
Function fnAddRecord($sKey,$asRecord)
... Add Record Code ...
$fnAddRecord=$iSuccess
Exit $iSuccess
EndFunction

Function fnDeleteRecord($sKey)
... Delete Record Code ...
$fnDeleteRecord=$iSuccess
Exit $iSuccess
EndFunction

Function fnFindRecord($sSearchString)
... Find Record Code ...
$fnFindRecord=$sKey
Exit $iSuccess
EndFunction

Function fnGetRecord($sKey)
... Get Record Cose ...
$fnGetRecord=$asData
Exit $iSuccess
EndFunction

and so-on ...

To use these functions you call the script file once at the start of the script. This has the effect of loading the functions into memory, where they will stay until you exit your main script. You can now call the functions as often as you like, without the overhead of reading and parsing the script file.

You call the function in the same way as internal KiXtart functions, so the following are all valid:
code:
$UserLogin="jdoe"
$UserData[0]="John"
$UserData[1]="Doe"
$UserData[2]="Trainee Clown"

If fnAddRecord($UserLogin,$UserData)
"ERROR: Could not add record for " $UserLogin ?
@ERROR ": " @SERROR ?
Else
"Record added OK." ?
EndIf

If fnDelRecord("jdoe")
"ERROR: Could not delete record" ?
EndIf

$UserLogin=fnFindRecord("Clown")
If @ERROR
"No clowns in this organisation." ?
Else
$UserData=fnGetRecord($UserLogin)
If @ERROR
"ERRROR: Invalid key " + $UserData ?
Else
$UserData[1] " " $UserData[2] " is a clown." ?
EndIf
EndIf

Neat, huh?

For advanced usage the library method has another major advantage.

Say you want to deploy your database applications to many sites. Some are very small sites which use flat text files for storing data, some are medium sized sites which use Access for storing data and some are large sites which use LDAP or SQL for storing data.

Now you could write applications for each, but wouldn't it be easier to do something like this at the start of your script:
code:
$DATABASETYPE=fnGetDBType()
Select
Case $DATABASETYPE="TXT"
CALL "TXTroutines.kix"
Case $DATABASETYPE="SQL"
CALL "SQLroutines.kix"
Case $DATABASETYPE="ODBC"
CALL "ODBCroutines.kix"
Case $DATABASETTYPE="LDAP"
CALL "LDAProutines.kix"
EndSelect

or more simply:
code:
CALL fnGetDBType + "routines.kix"

Each of these files will have a "fnAddRecord()" defined. Your script doesn't need to know which database method is being used when you add a record. The correct version will have been loaded by the "CALL" at the starte of your script.

You may remember that I mentioned that there are some cases when you cannot make a routine in a "black-box" fashion.

The first problem is when you want to keep some information and re-use it in your function. These types of variables are known as "static" variables in some languages.
For example, you may only want to set up a connection to your database once as it is an expensive thing to do in computer terms. At present the only way to keep this information between function calls is to define it in a GLOBAL variable. This variable will have the scope of your entire script, so can clash with your main script variables.

The other problem area is when you want to change the value of one of the parameters. A simple classic example is the "POP" routine. This takes a stack, "pops" the top element off the stack and returns the popped off element. Consider a function to "pop" off the first character in a string:
code:
Function fnPopString($sString)
If $sString="" Exit 1 EndIf

$fnPopString=Left($sString,1)
$sString=SubStr($sString,2)
Exit 0
EndFunction

Looks good, eh?

Well no, it won't work. The variable $sString is LOCAL to the function, and is destroyed on exit. It is a copy of the string that you passed in your main script. Passing this type of information is known as "passing by value"

For functions which need to change variables outside their scope you need to use a method known as "pass by reference", or "pass by address". This method passes a pointer to the original variable so that it can be manipulated in the function.

KiXtart does not currently support pass by reference, so again you will need to use GLOBAL variables to achieve the result.

There is an advanced coding technique which you can use to abstract the variable name, but the variable you want to change still must be global.

Hopefully I haven't put you to sleep and I've answered most of your questions about functions.

If not, post a follow-up.

Top
#37522 - 2003-03-07 10:45 AM Re: GOSUB vs. FUNCTION
Jochen Administrator Offline
KiX Supporter
*****

Registered: 2000-03-17
Posts: 6380
Loc: Stuttgart, Germany
Whoa Richard !

that explains the nature of things, and should be considered to add in FAQ ...

Hey, Is that Avatar (MiniMe) you ?
_________________________



Top
#37523 - 2003-03-07 11:27 AM Re: GOSUB vs. FUNCTION
Richard H. Administrator Offline
Administrator
*****

Registered: 2000-01-24
Posts: 4946
Loc: Leatherhead, Surrey, UK
quote:
Hey, Is that Avatar (MiniMe) you ?
Yup, on my way to a Robbie Williams concert.

I loathed the bloke before the concert (I only went because I fancied one of the girls going). I have his last three albums now, and I've been living with the girl in question for the last two years.

Top
#37524 - 2003-03-07 02:37 PM Re: GOSUB vs. FUNCTION
Glenn Barnas Administrator Offline
KiX Supporter
*****

Registered: 2003-01-28
Posts: 4401
Loc: New Jersey
Holy Moly, Richard - that's GREAT!

One other comment about libraries & functions..

If you look at my tsControl.udf, there are about 15 individual functions in the file. That is the end result, but during development, each was a separate file, with a seperate Call statement in the test script. This made debugging a bit easier, as I didn't have to scroll through 1200 lines of code. Most individual functions had about 50-60 lines - very managable. Once everything had been tested, the individual files were combined into a library, so only one file needs to be distributed.

I still maintain the functions as individual files on my Development drive, in a sub-folder in the project folder. I make changes to the individual file and use a batch file (copy f1 + f2 + f3... newfile) to quickly create the library.

This concept is helpful when you have many related functions in a library, or when the size of the functions makes editing the resulting library uncomfortable.

Glenn
_________________________
Actually I am a Rocket Scientist! \:D

Top
#37525 - 2003-03-07 02:37 PM Re: GOSUB vs. FUNCTION
JohnQ Offline
Starting to like KiXtart

Registered: 2003-03-04
Posts: 171
Richard, If you have variable in your main script, say $richard for example, and you pass that into a function...
code:
Function fnExample($richard)
If $richard <> ""
do stuff
Endif
Endfunction

is your variable $richard killed at the end of the function or only if you would have set $richard to some other value during the function?

Thanks for all of the info!

Top
#37526 - 2003-03-07 02:43 PM Re: GOSUB vs. FUNCTION
Sealeopard Offline
KiX Master
*****

Registered: 2001-04-25
Posts: 11165
Loc: Boston, MA, USA
Since you're passing the variable into the function it will be initialized automatically inthe beginning and destroyed automatically at the end. Basically, the function is self-contained. Aditionally, any variable DIMmed inside the function will be destroyed upon exiting the function.

The main issue with functions versus GOSUB is that the function is self-contained. It's it's own entity. youc ould also say a user-defined function is similar in behavior as a build-in KiXtart function. This is why we try to mimick a UDF as close as possible to the build-in functions with regards to input parameters and error handling.

Try this:
code:
dim $richard

$richard='value 1'
? 'Initial value : '+$richard
$return=fnExample($richard)
? 'Return value : '+$return
? 'Richard variable : '+$richard

Function fnExample($richard)
? 'entering function : '+$richard
$richard='value 2'
? 'exiting function : '+$richard
$fnExample=$richard
Endfunction



[ 07. March 2003, 14:47: Message edited by: sealeopard ]
_________________________
There are two types of vessels, submarines and targets.

Top
#37527 - 2003-03-07 02:49 PM Re: GOSUB vs. FUNCTION
Richard H. Administrator Offline
Administrator
*****

Registered: 2000-01-24
Posts: 4946
Loc: Leatherhead, Surrey, UK
JohnQ,

The "$richard" in the function is completely different from the one in your main script. It is a new variable which contains a copy of the data passed to it, and is only visible to the function.

The visibility of the variable is what is known as its "scope".

Variables which are declared in the function definition have a scope local to the function, the same as if you had DIMmed them within the body of the function.

The fact that they have the same name is not relevant.

If your variable "$richard" in the main script is a global variable it will be obscured by the local "$richard" variable in the function - there is no way to reference it.

Top
#37528 - 2003-03-07 02:52 PM Re: GOSUB vs. FUNCTION
Sealeopard Offline
KiX Master
*****

Registered: 2001-04-25
Posts: 11165
Loc: Boston, MA, USA
My example code actually demonstrates this behavior. This is also described in the KiXtart Manual under the setion dealing with DIMming variables and the different scopes they can have.

John: Please take a look at the KiXtart Manual.
_________________________
There are two types of vessels, submarines and targets.

Top
#37529 - 2006-02-28 12:30 PM Re: GOSUB vs. FUNCTION
Rosario Carcò Offline
Fresh Scripter

Registered: 2002-08-28
Posts: 8
May I append another question I just run into?

It seems that it is not possible to call a subroutine with GOSUB from inside a Function? I get an error 'Label [xyzSub] not found'

The opposite however works fine, you can call every function from inside a function.

a) Could a KIX expert tell whether I am mistaken?

b) The SUBROUTINES may alter variables which were declared as globals whilst functions, as explained in the previous posts, have no chance to do so.

Both considerations may help deciding whether to implement code as function or as subroutine.

Thanks for all your valuable hints. Rosario

Top
#37530 - 2006-02-28 12:43 PM Re: GOSUB vs. FUNCTION
Richard H. Administrator Offline
Administrator
*****

Registered: 2000-01-24
Posts: 4946
Loc: Leatherhead, Surrey, UK
Quote:

b) The SUBROUTINES may alter variables which were declared as globals whilst functions, as explained in the previous posts, have no chance to do so.




This is not correct.

Functions may read and write variables which have been declared (implicitly or explicitly) in the global scope.

Functions cannot access variables which have been declared in the local scope of the script however subroutines can.

You should never use a subroutine if a function will do the job. You should avoid global variables unless you really have to use them.

Top
Page 1 of 2 12>


Moderator:  Jochen, Allen, Radimus, Glenn Barnas, ShaneEP, Ruud van Velsen, Arend_, Mart 
Hop to:
Shout Box

Who's Online
0 registered and 1003 anonymous users online.
Newest Members
StuTheCoder, M_Moore, BeeEm, min_seow, Audio
17884 Registered Users

Generated in 0.137 seconds in which 0.068 seconds were spent on a total of 12 queries. Zlib compression enabled.

Search the board with:
superb Board Search
or try with google:
Google
Web kixtart.org