|
Post by Walt Decker on May 19, 2023 16:55:29 GMT -5
SUB and FUNCTION are not commands per se, but they appear to cause confusion with many of the LB users.
Explain what they are, what their parameters are, how they work, pros and cons vs GOSUB/GOTO, and show some simple examples.
|
|
|
Post by Walt Decker on May 24, 2023 10:41:52 GMT -5
Looks like no one wants to discuss this. I will wait a bit longer before I make the attempt.
|
|
|
Post by Rod on May 24, 2023 16:33:42 GMT -5
Interesting, discussion presumes prior knowledge and informed input or discussion.
The reality is that many readers already know what subs and functions are and probably kinda wonder what the point of the discussion is.
The counter to that is that BASIC returners may not know what a sub, function, procedure , constant, global is and need guided.
So scope becomes the first point to be clarified.
|
|
|
Post by colinmcm on May 24, 2023 17:53:16 GMT -5
Good points Rod. I also wonder what there is to discuss. When I first started using LB I was frustrated, rather than confused, by the issue of scope with Call and Gosub, as well as with the differing calling syntaxes.
My solution was pretty well always to use functions. A single calling syntax, no doubt about what variables were used ( enclosed in the brackets), no scope issues, except for the odd global variable. If you don't need to capture the return value from the function just use dummy = myfunction() (or dummy$ =myfunction$() ) then throw your dummy out of the pram. I got on well enough with that in several programs over the years. I don't know, but I suspect that as Gosub and Call came about when computing power was so much more limited that now, that they were less resource hungry than functions, at a time when resource use mattered. I doubt anyone would invent them today.
|
|
|
Post by xxgeek on May 24, 2023 20:38:06 GMT -5
Some members are experts, some are novices, and some are somewhere in between. First I'd like to state that I am closer to novice than expert, far closer. I am a hacker, (not the evil type) I have hacked my way around computers for over 40 years, and have learned a lot about many things related to computers, operating systems and coding, but not ever taken any kind of course. Terminology is my Achilles heal. I can only assume there are others in the same boat. Functions, and or subs are just small programs basically. I think of them as 'commands not available in the command list" They are used to avoid repetition in code, among other things. If your code needs to do something a few, to many many times, then a function or sub is a good idea. As an example, lets take the function for checking if a file exists. function fileExists(path$, filename$) dim info$(0, 0) files path$, filename$, info$() fileExists = val(info$(0, 0)) 'non zero is true end function
If you were writing a program that needed to check existence of many files you would need to write the same code over and over to check 'each' file. But with the file exists function you just need to if fileExists("Somefolder", "somefile") then [doWhatever] Saving a lot of time and a tiny bit of energy. Another example: global text$, file$ text$="Some text" file$ = DefaultDir$;"\mytext.txt"
call writeFile
'sub to write each Listing to corresponding file sub writeFile open file$ for output as #1 #1, text$ close #1 end sub
Since it would be impossible for any programming language to have a command for every possible thing a programmer/user may want to do, programmers have created their own 'little programs' called subs, and functions to act as commands they wish they had in the programming language they are working in. Commands we use in LB are after all just 'little programs' written in another lower level language. A novice trying to help other novices when the experts go over our heads
|
|
|
Post by Walt Decker on May 25, 2023 16:51:18 GMT -5
SUB END SUB Defines a block of code (procedure).
'
CALL : BASIC instruction, similar to GOSUB. SUB : Defines the code block type. SubName : Defines the beginning of the code block and can be any name; similar to [LABEL.NAME] in Liberty Basic.
Arg1, Arg2$, Arg3: Are input parameters called ARGUMENTS. They must be variable names. By Liberty Basic convention, all arguments are passed to the code block (procedure) by value; however in the case of a string variable a copy is made of the variable and the memory address of the copy is passed to the procedure. If the procedure changes the value of its arguments, when the procedure is complete the values are unchanged in the caller.
BYREF : Modifies the behaviour of the procedure, that is, if the procedure changes the value of its arguments, the changed values are also changed in the caller.
END SUB : BASIC instrucion that defines the end of the procedure; functions the same as the BASIC instruction RETURN. As far as I know, BASIC, in general, is the only high level language that has SUB/END SUB code blocks. The terms SUB/END SUB, I think, is derived from the BASIC language GOSUB/RETURN instructions. Both define blocks of code that perform specific operations.
PROS AND CONS: GOSUB versus CALL SUB
PRO: GOSUB: Executes slightly faster than CALL SUB. The reason, only the return code address is put on the stack so only one value, the return address, is removed from the stack when the RETURN instruction is encountered.
PRO: GOSUB: All variables are visible to the GOSUB procedure. With CALL SUB only those values passed to it, with the exception of GLOBALs, are visible to the procedure.
CON: GOSUB: All variables are visible to the GOSUB procedure. Also, all variables used in the procedure are visable to all other portions of the application if there are no CALL SUB or FUNCTION() procedures in the application. This means that the programmer must be very careful when using varaibles and usuallty has to define more variables than necessary.
CON: GOSUB: Literal values can not be passed to the procedure although the procedure can use literal values within the procedure.
PRO: CALL SUB: Variables outside the procedure, with the exception of GLOBAL variables, are invisible to the procedure. Also variables used within the procedure are invisible to the rest of the application. This means that variables outside the procedure are never changed.
PRO: CALL SUB: Literal and/or variable values can be passed to the procedure.
PRO: CALL SUB: Because of their versitlity they can reduce both source and complied code footprint.
PRO: CALL SUB: Easy to port from one application to another because there is no worry about matching or changing variables.
EXAMPLES: Recursive GOSUB and Recursive CALL SUB
GOSUB ' Addend = 5 Adder = 1 Target = 100 RetValue = 0
GOSUB [ADD.IT] PRINT "Addend = "; Addend PRINT "Adder = "; Adder PRINT "Target = "; Target PRINT "RetValue = "; RetValue END
[ADD.IT]
RetValue = Addend + Adder
IF RetValue < Target THEN Adder = RetValue GOSUB [ADD.IT] END IF
RETURN [END.ADD.IT] '
CALL SUB ' Addend = 5 Adder = 1 Target = 100 RetValue = 0
CALL AddEm Addend, Adder, Target, RetValue
PRINT "Addend = "; Addend PRINT "Adder = "; Adder PRINT "Target = "; Target PRINT "RetValue = "; RetValue END
'---------------- '----------------
SUB AddEm Ad, Ar, Match, BYREF Value
Addend = Ad Adder = Ar '================ ' Addend and Adder are not the same variables as ' Addend and Adder in the caller '================
Value = Addend + Adder
IF Value < Match THEN Adder = Value CALL AddEm Addend, Adder, Match, Value END IF
END SUB '
If you execute the two code snippets you can see that GOSUB changes the value of two variales, Adder and RetValue, while CALL SUB changes only the value of interest, RetValue. =======================================================
FUNCTION END FUNCTION Defines a block of code (procedure).
'
FUNCTION : Defines the procedure type. FunctionName, FunctionName$ : Defines the beginning of the procedure and the type of value that can be returned; also the name is a variable.
Arg1, Arg2$, Arg3: Are input parameters called ARGUMENTS. They must be variable names. By Liberty Basic convention, all arguments are passed to the code block (procedure) by value; however in the case of a string variable a copy is made of the variable and the memory address of the copy is passed to the procedure. If the procedure changes the value of its arguments, when the procedure is complete the values are unchanged in the caller.
BYREF : Modifies the behaviour of the procedure, that is, if the procedure changes the value of its arguments, the changed values are also changed in the caller.
END FUNCTION : BASIC instrucion that defines the end of the procedure; functions the same as the BASIC instruction RETURN.
The term "FUNCTION", I think, is derived from the math notation Fx = which means the function of x. When functions were first introduced in basic languages they were limited to one liners. If I remember correctly the syntax was something like:
FNfoo = A + B FNtwofoo = (A + B) * (C + D)
and the result was obtained by Z = FNfoo; X = FNtwofoo.
As can be seen from the FUNCTION description, a SUB and FUNCTION are almost identical. Externally the only differences are are calling syntax, block syntax, and functions have both a numeric and string mode where subs have only one mode. Internally functions can return a value that GOSUB and CALL SUB can use directly while subs can not return a value except through the BYVAL variable modifier. Functions have the same pros and cons as SUBS versus GOSUB and have the same functionality as SUBs.
Personally, I do not care for LB's SUB syntax, so I use it only when forced to considering my programming style.
So, let's take a look at some GOSUB, CALL SUB, and FUNCTION code.
GOSUB and FUNCTION ' GOSUB [WRITE.DATA] END
'---------------------- '----------------------
[WRITE.DATA]
FilePath$ = "" Dummy$ = ""
FOR I = 1 TO 3 FilePath$ = FN.GetFile$(DefaultDir$, 0) PRINT FilePath$ NEXT I
Dummy$ = FN.GetFile$(DefaultDir$, 1) RETURN
'---------------------- '----------------------
FUNCTION FN.GetFile$(Path$, Reset)
[FILE.DTA] DATA "MyData.tad" DATA "SomeData.dat" DATA "AllData.Lst"
IF Reset THEN RESTORE [FILE.DTA] EXIT FUNCTION END IF
Dta$ = ""
READ Dta$ FN.GetPath$ = Path$ + "\" + Dta$ END FUNCTION '
CALL SUB AND FUNCTION '
Xwide = 400 Yhigh = 500 WinHndl = FN.DefineWindow("TEST", Xwide, Yhigh) WAIT
'----------------------- '-----------------------
FUNCTION DefineWindow(WinTitle$, Xw, Yh)
Cx = 0 Cy = 0
WinHndl = 0
CALL ScreenCenter(Cx, Cy) CALL SetWinPos(Cx - Xw / 2, Cy - Yh / 2) CALL SewWinSize(Xw, Yh)
OPEN WinTitle$ FOR WINDOW AS #TST #TST, "TRAPCLOSE WIN.TST"
WinHndl = FN.GetHndl("#TST") DefineWindow = WinHndl END FUNCTION
'----------------- '-----------------
SUB WIN.TST TstHndl$
CLOSE #TstHndl$ END END SUB
'----------------- '-----------------
SUB ScreenCenter BYREF X, BYREF Y)
X = DisplayWidth / 2 Y = DisplayHeight / 2 END SUB
'----------------- '-----------------
SUB SetWinPos(Ux, Uy)
UpperLeftX = INT(Ux) UpperLeftY = INT(Uy) END SUB
'----------------- '-----------------
SUB SetWinSize(Xw, Yh)
WindowWidth = Xw WindowHeight = Yh) END SUB
'----------------- '-----------------
FUNCTION FN.CheckTag$(Tag$)
IF LEFT$(Tag$, 1) <> "#" THEN Tag$ = "#" + Tag$
FN.CheckTag$ = Tag$ END FUNCTION
'----------------- '-----------------
FUNCTION FN.GetHndl(WinTag$)
Hndl = 0
WinTag$ = FN.CheckTag$(WinTag$)
ON ERROR GOTO [HANDLE.EFFOR]
Hndl = HWND(#WinTag$) FN.GetHndl = Hndl EXIT FUNCTION
[HANDLE.EFFOR] PRINT "HANDLE ERROR" PRINT WinTag$; " is invalid" END FUNCTION
'
|
|