Gosub or functions?
Blitz3D Forums/Blitz3D Beginners Area/Gosub or functions?
| ||
@all Whats the best? Gosub/Return or calling a function? which is the fastest, why and how? |
| ||
Use functions.. period! Once you are used to functions you never want to go back to gosub thingies. Not to mention the arguements you can send with to function. |
| ||
Yeh, I agree Functions rule - but which is faster - are there pros and cons in different uses of them? It's an interesting question. |
| ||
@puki exactly, I am interested in the "nitti-gritty" details of differences in speed etc ... |
| ||
gosubs seems faster than functions try this code :p [/code] Graphics 800,600,0,2 t=MilliSecs() For a=1 To 1000000 Gosub blah Next Text 0,0,MilliSecs()-t Flip t=MilliSecs() For a=1 To 1000000 bloh() Next Text 0,10,MilliSecs()-t Flip WaitKey End .blah Return Function bloh() End Function [/code] results are 8 12 on my system debug off but remember that you can use the same vars in all of your functions as they are locals, in oposition of the gosub that you have to use variables that are available in the entire program, also you can't pass values with gosub, you have to put them in the vars before. |
| ||
@ford escort good input! |
| ||
Interesting but you are hardly going to have a million gosubs or function calls per frame so the difference in performance in a game will be negligable. Functions allow you to structure your code making it easier to debug and understand, for these reasons I've not used a gosub ever in Blitz...or any other language I can think of that has functions. Gosub is one of those commands that should be banished from any programming language, along with its partner in crime goto =) |
| ||
I've used GoTo before. If I have a choice between using a GoTo, or coding for 2 hours to avoid having to use a GoTo and still get the same result, I know what I'd rather do. |
| ||
Yeah, gosubs are useful. If you wanna have a bit of code that does a job without input, then i use gosubs. Nothing wrong with it, unless your a code snob. Goto is extremely useful too. If you have a large section of code you don't wanna run, put a label at the end of it, and use goto to skip bits of the code. :) |
| ||
Gfk, if you have to spend two hours to avoid using a Goto, I'd hate to see your code! ;) |
| ||
I think he meant if he had the choice, he'd use goto ;) So would i :) |
| ||
I think he meant if he had the choice, he'd use goto ;) So would i :) Yes. |
| ||
I use Gosub's very often too. If it's a very general routine then I use a Gosub just to keep code clean and separate. If it's a very specific task that should be separated comepletely from the rest of my data I use a function. Both are in your toolbox and both should be used. |
| ||
@all Goto's can be quite OK. Look at this code snippet: For i = 1 To bot_numchars bot_currentchar = Asc(Mid(FadeTextBot$,i,1)) If bot_currentchar = bot_space Then : Goto skipbot : End If bot_currentchar = bot_currentchar - 65 DrawImage (vh_fadeintro_fnt,bot_tempx,bot_tempy,bot_currentchar) .skipbot bot_tempx = (bot_tempx+vh_fadeintro_fntwidth) : Next In the code above we print bitmap characters to the screen, and if a SPACE character ( ) is needed to be printed, we print nothing, but increment the X position to align the next position. This also saves having an empty SPACE character in the bitmap font ... |
| ||
That code seems to be formatted for maximum unreadability. Here it is neatened up: For i = 1 To bot_numchars bot_currentchar = Asc(Mid(FadeTextBot$,i,1)) If bot_currentchar = bot_space Then : Goto skipbot bot_currentchar = bot_currentchar - 65 DrawImage (vh_fadeintro_fnt,bot_tempx,bot_tempy,bot_currentchar) .skipbot bot_tempx = (bot_tempx+vh_fadeintro_fntwidth) Next I rarely use Goto because the code is usually clearer without it. For example: For i = 1 To bot_numchars bot_currentchar = Asc(Mid(FadeTextBot$,i,1)) If bot_currentchar <> bot_space bot_currentchar = bot_currentchar - 65 DrawImage (vh_fadeintro_fnt,bot_tempx,bot_tempy,bot_currentchar) End If bot_tempx = (bot_tempx+vh_fadeintro_fntwidth) Next |
| ||
Gosubs are faster simply because nothing except a return memory pointer value is pushed onto the stack... When you call a function (be it one you wrote or some of the ones built into Blitz, the CPU will push the passed variables onto the stack along with a "return" memory pointer so it knows where to go when the function is done...once the CPU gets to the function it pulls (pops) all those variables back off the stack for the function to use...when it hits the end of the function (or a return) it pops the "return memory address pointer" off the stack, pushes whatever return value set by the function (return 7 for example) back onto the stack and jumps to the memory location indicated by the "return memory address" and the program continues...if you didn't tell the function to return a specific value (like Return 7) then a NULL (zero) value is pushed onto the stack in place of it... A gosub works in a simular manner...the "return to" pointer is pushed onto the stack, the CPU jumps to the gosub routine...then once done it pops the return value back off the stack and jumps to that location...no extra pushes/pops required, which is why it's a bit faster A goto works in a manner simular to the JMP assembly instruction...indeed..be it a function, subroutine, or just a goto...they all use one of the JMP opcodes...however goto doesn't push anything onto the stack, and because of this it is faster then both functions and subroutines. However if speed it your big concern then you shouldn't use any of these...the fastest code is always going to be strait inline stuff...no functions, no subroutines, no use of goto...this is because there can be a large varience in the amount of time it takes your CPU to process a JMP opcode...this is because the location in your code that the CPU is trying to JMP to may not yet exist in the processors cache, so the processor must wait for it to load in from system memory (this is called a "cache hit", as in you take a speed hit from haveing the CPU waiting around several cycles waiting on the correct bit of code). essentualy functions are just more advanced subroutines, which are just more advanced ways of haveing goto. |
| ||
I'd say that there's another kind of speed that is important.. "development-speed". So, maybe gosubs are a little bit faster.. but in these days I'd say that development-time is way more important since that actually costs you or your company money. So, again: functions! I use goto rarely, but when I use it, it's because blitz has no block-commenting. |
| ||
@MSW Thank you for that very informative, high quality post! Personally, I agree with Shambler that the speed difference between functions and gosubs is negligible and that the fact that functions make you pass in values can make them a bit easier to debug and understand. On the other hand, if you decide not to pass in a zillion variables and use globals instead, it will be equally unreadable. Also, you can't declare a variable as global inside a function. As for goto, one very useful feature is that they can be used inside functions. I find myself using them to skip to the end of a function to do cleanup things before exiting. Overall, I say use whatever works for you. |
| ||
Gosub is the spawn of Satan! Never really liked it much, and probably never will. Didnt even use it way back when on the ancient Acorn Electron (cos functions made my code look pretty). I like them for the following reasons: 1) Tidy code is easier to understand and to debug. Functions make it tidier. 2) Recursive functions are seriously useful, especially when dealing with parent and child entities in B3D. 3) Large numbers of Gosubs can get very confusing very quickly. Just thought I'd add my input. |
| ||
@all good, valid feedback |
| ||
Don't see why a gosub should make code confusing, it is written just like a function, and can be used so with a speed increase. |
| ||
well for exemple you have a function that write hello world to a graphic bufferfunction heloworld(buffer) setbuffer buffer text 10,10,"hello world" end function you can call it later for multiple buffers like that helloworld(imagebuffer(mypic1) helloworld(backbuffe()) helloworld(imagebuffer(mypic2)) to do the same things with gosub the code may like the same .helloworld setbuffer buffer text 10,10,"hello world" return but more difficult to use buffer=imagebuffer(mypic1):gosub helloworld buffer=backbuffer():gosub helloworld buffer=imagebuffer(mypic2):gosub helloworld and you have to remember the name of the variables used in the 'gosub' so quicker but more difficult to code :) |
| ||
10 if x > 10 then 20 gosub 160 25 else if x < 10 then 30 gosub 180 50 end if this case wont catch if it = 0 then your code executes as sequentially oh but wait it gets better! 60 //do stuff here 70 gosub 25 oh but wait. what if we add 1 line above line 25. Now we have to go through allllllll of our bloody code to update the goto statements. (depending if you have declaired line numbers or not. GO SUBS COMPOND SPAGETTI CODING> im sorry eBusiness. but i cant agreee. obviously you havent worked on any large systems that use more than 40 lines of code . GO SUB USERS SHOULD BE NAILED TO A TREE! sorry for the excessive emotion on this one. But try spending !!2 years!! updating code on a project that someone decided to use incorrect gosubs with includes. then talk to me about how it shouldnt '..make things confusing...' !!!!!!arg... !!!!!! im so frustrated for even reading that 'use go subs they are cool' response... lol sorry if i offended anyone. |
| ||
Ppl who use gosubs like that deserve all they get :) If used properly, there not a problem, as, as i said, there used for a purpose that doesn't require input. :) |
| ||
Lol @baudspeed =) I agree completely though, just nice to see someone so passionate about it =) |
| ||
@Baudspeed OH NO! Now I will have to change all of my 30-year-old or just retarded code that uses LINE NUMBERS to gosub! I was sure it was a brilliant way to code as you can see that all of the code in the code archives looks like that, just with functions instead. now im off to "COMPOND?" on my dinasaur-basic |
| ||
@Coorae wow brilliant argument for using gosubs. coorae. bravo.bravo.bravo. <insert crickets chirping here> |
| ||
this case wont catch if it = 0 then your code executes as sequentially apparently you dont know so ... with a gosub you return to where it was called from. this is not the same as goto. Assuming the gosubs return (the coder is somewhat competent), the execution will always pass through that code no matter what x is. |
| ||
coorae. thanks for backing your opinion up. i can see what you are getting at. But i would *fire* a programmer on the spot if they were working in a language that allowed functions but used gosubs. I spent too much time supporting garbage code. I have seen developers leave companies because they wrote garbage code and their jobs were to support it. Then the next guy who comes through has no doc because you really honestly cant document gosub/gotos. I'm not stating this again so that i can try and change your opinion. You have an opinon. I just don't agree with it. I appreciate the fact that you did back it up though. Thanks. |
| ||
It just seems like you were talking about GOTO. Most gosubs that work just like a function are not any harder to document than a function that could be in its place. I'm not stating this again so that i can try and change your opinion. You have an opinon. I just don't agree with it. My only shown opinions were that I dont like that your argument was not well made, and I dont like jumping based on line numbers either. Im glad you took it well. I used to use gosub until I found that functions are better in the long run. That is my opinion, I now rarely use gosub or goto. |
| ||
Baudspeed, line numbers are dead, today we use labels, like this:Repeat Dostuff Gosub dootherstuff Forever End .dootherstuff Doing stuff ReturnSee, not much different from a function, only it's faster :) |
| ||
I have always found Gosubs easyer to follow than functions. In ford escort's egs. buffer=imagebuffer(mypic1):gosub helloworld I know exactly what the code is doing at this point helloworld(imagebuffer(mypic1) But I don't have a clue what is going on here. The gosub code is self explanitory. When I use a function I always have to comment it so I know what the line of code is really doing. The only thing harder to follow then functions is Includes. Now includes really confuse a program. Because then you have to load up the include file in a seperate window and search for your varibles. Some includes I have seen include other includes, which include other includes. You end up searching through 10 files to find what a varible stands for. No wonder software is so expensive these days. |
| ||
repeat DrawPlayer() forever seems clear to me.. not less clear than: repeat Gosub DrawPlayer forever I've no problems anymore with includes since I know how to make my own stuff highlight using that declr trick. and what about: repeat DrawPlayer(100,100) forever compared to: repeat PlayerX=100:PlayerY=100:gosub DrawPlayer forever The main reason I like functions over gosubs is that functions look like other commands. Imagine the Rect command using a gosub: RectX=0:RectY=0:RectWIdth=100:RectHeight=40:RectFill=true:gosub Rect I use long variablenames since they need to be globals, and common stuff like x and y are usually already in use. and now as a function: Rect 0,0,100,40,true By using functions all stuff looks uniform. ... 2ct. |
| ||
PS. I dont use goto's or gosubs. Not because I dont like them, just that Iv had good coding style shoved down me from college and UNI so its kinda habbit not to use em. |
| ||
The key here is variable scope. You should preferably use functions, because that way any larger or more complicated subroutines use their own 'local' variables, which means they have *no* chance of screwing up you 'main' variables. Ofcourse if you're not carefull you can still screw up Globals, arrays and types, but generally using functions is safer, particularilly if you're writting a long and/or complex subroutine. I haven't used goto/gosub for at least a decade. It really holds no advantages over functions/methods. Speed difference is negliable, and certainly not worth the possible stabilty trade-off. |
| ||
>> The key here is variable scope Good point, FlameDuck. I must admit, however, that I still use Gosub for short programs, mostly because I use a handful of variables that I want to use globally, and I can't be bothered declaring them as such separately (poor excuse) or passing them into the function. If I do anything serious or complicated I use functions. I still think Goto has certain limited uses on rare occasions (like inside a function, for example). But its use should be minimized or you end up with confusing spaghetti code that is difficult to understand or debug. >>The way I see it. if it works use it. NO programmer should be worried about how some one else is going to think of them because of their code. Amen, Yavin. Unless you are working for someone else and perceptions matter. But we're mostly hobbyists around here. |
| ||
I have done some asm programming, over the years. And I know that all functions are actually converted into gosubs or in asm terms calls to subroutines. And all branching functions are converted into some type of jmp. eg jle, jne, jeq, jz. I find goto invaluable when debuging. To comment out areas or pass over suspected problem areas. Because of my asm programming skills I like gosubs because they are used exactly like a call in asm. you push your paramaters on the stack and then call the subroutine. That is the way the windows apl works too. |
| ||
@AbbaRue just as you I have programmed Assembler for DECADES and also tend to use gosub/goto primarily for debugging purposes |
| ||
Having programmed Assembler has nothing to do with it (I still program assembler on occasion, mostly when absolutely nessecary). Functions are *not* just glorified gosubs (or jumps/branches) because they have their own namespace. I find block commenting much more useful than gotos for debuging purposes. That is the way the windows apl works too. The Windows API, and indeed *most* API's are objective in nature. Thats how OOP originated. Engineers at Xerox PARC, while inventing the GUI, also invented OOP (more specificly SmallTalk) to make it all manageable. |