Allow gosub in procedures

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Allow gosub in procedures

Post by Mistrel »

We can Goto out of a function but we can't Gosub. In my opinion Gosub would be much more useful and safer.

Yes, I agree that this is generally a bad thing to do, but it does have its uses. Gosub would sure beat the pants off of Gotoing out and Gotoing back in. :?
citystate
Enthusiast
Enthusiast
Posts: 638
Joined: Sun Feb 12, 2006 10:06 pm

Re: Allow gosub in procedures

Post by citystate »

why not just use Procedures instead of subroutines - even safer than gosub
there is no sig, only zuul (and the following disclaimer)

WARNING: may be talking out of his hat
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Re: Allow gosub in procedures

Post by Mistrel »

citystate wrote:why not just use Procedures instead of subroutines - even safer than gosub
It would just make my life easier for the code I'm working with. I don't have the option of modifying this code in that way.

Gosub would also be easier to jump around inside a function than Goto if you want to get back from where you started.
jack
Addict
Addict
Posts: 1358
Joined: Fri Apr 25, 2003 11:10 pm

Post by jack »

Goto Gosub are OK if used judiciously, as long as you don't goto or gosub from one sub into another and another ..., I mean keep subs modular.
jack
Addict
Addict
Posts: 1358
Joined: Fri Apr 25, 2003 11:10 pm

Post by jack »

here's dirty hack that will allow gosub inside a procedure, use at your own risk.

Code: Select all

Global NewList gosublist.l() 
Global retaddress.l 

Macro _gosub(label,retrn) 
  AddElement(gosublist()) 
  gosublist()=?retrn 
  ! lea eax,[l_#label] 
  ! jmp eax 
EndMacro 

Macro _return 
  retaddress=gosublist() 
  DeleteElement(gosublist()) 
  ! jmp [v_retaddress] 
EndMacro 

Procedure test1() 
  Shared gosublist.l(),retaddress.l 
  i.l 
  For i=1 To 10 
    _gosub(factorial,l1) ;you need to supply a return label, in this case l1 
    PrintN("This never gets executed")
    l1: PrintN(Str(fac)) 
  Next 
  ProcedureReturn 
  factorial: 
    If fac.l=0 
      fac=1 
      n.l=1 
    EndIf 
    fac=fac*n 
    n=n+1 
  _return 

EndProcedure 



  OpenConsole() 
  test1() 
  Input() 
  CloseConsole() 
  End 
  
freak
PureBasic Team
PureBasic Team
Posts: 5940
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

Gosub adjusts the stack, Goto doesn't. Thats why you can use the one inside procedures and not the other.
quidquid Latine dictum sit altum videtur
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

I don't believe either one belongs in a modern variant of the Basic language. There's far more power in PB today than was ever in early Basic's, so much in fact that using primitive commands like these is not only pointless but it leads to seriously bad programming styles.

This is just one frog's opinion and I hope I haven't offended anyone by airing it. :)
BERESHEIT
jack
Addict
Addict
Posts: 1358
Joined: Fri Apr 25, 2003 11:10 pm

Post by jack »

I agree with the danger of writing bad code, but contrary to purest, I belive that goto and gosub can be useful if used judiciously, for example: don't goto or gosub out of a procedure and don't goto into or out of a sub, try not to nest gosub's.
personally, I would rather have local procedures instead.
jack
Addict
Addict
Posts: 1358
Joined: Fri Apr 25, 2003 11:10 pm

Post by jack »

another way, no asm needed.

Code: Select all

Macro _gosub(label,retrn) 
  AddElement(gosublist()) 
  gosublist()=?retrn 
  GoToEIP(?label)
EndMacro 

Macro _return 
  retaddress=gosublist() 
  DeleteElement(gosublist()) 
  GoToEIP(retaddress)
EndMacro 

Procedure test1() 
  NewList gosublist.l() 
  retaddress.l 
  i.l 
  For i=1 To 10 
    _gosub(factorial,l1) ;you need to supply a return label, in this case l1 
    PrintN("This never gets executed") 
    l1: PrintN(Str(fac)) 
  Next 
  ProcedureReturn 
  factorial: 
    If fac.l=0 
      fac=1 
      n.l=1 
    EndIf 
    fac=fac*n 
    n=n+1 
  _return 

EndProcedure 



  OpenConsole() 
  test1() 
  Input() 
  CloseConsole() 
  End 
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Post by Mistrel »

freak wrote:Gosub adjusts the stack, Goto doesn't. Thats why you can use the one inside procedures and not the other.
I didn't know this. DarkBasic allows Gosubing out of a function so I suspected that it was a design choice. :roll:
User avatar
Fluid Byte
Addict
Addict
Posts: 2336
Joined: Fri Jul 21, 2006 4:41 am
Location: Berlin, Germany

Post by Fluid Byte »

Of course DarkBasic allows this, then again, it's rubbbish.
Windows 10 Pro, 64-Bit / Whose Hoff is it anyway?
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

Mistrel wrote:
freak wrote:Gosub adjusts the stack, Goto doesn't. Thats why you can use the one inside procedures and not the other.
I didn't know this. DarkBasic allows Gosubing out of a function so I suspected that it was a design choice. :roll:
DarkBasic is an interpreter.
User avatar
Demivec
Addict
Addict
Posts: 4260
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

jack wrote:I agree with the danger of writing bad code, but contrary to purest, I belive that goto and gosub can be useful if used judiciously, for example: don't goto or gosub out of a procedure and don't goto into or out of a sub, try not to nest gosub's.
I agree with those statements. Gosub inside a procedure would be used when there would be a benefit of reusing code with the added speed of not having to handle a procedure call because all operations would be performed on local variables. To quote the manual: "Gosub is useful when building fast structured code." It only has application in advanced cases, because beginners are never in a hurry. :wink:
Last edited by Demivec on Mon Jan 21, 2008 8:15 pm, edited 1 time in total.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

Demivec wrote:
jack wrote:I agree with the danger of writing bad code, but contrary to purest, I belive that goto and gosub can be useful if used judiciously, for example: don't goto or gosub out of a procedure and don't goto into or out of a sub, try not to nest gosub's.
I agree with those statements. Gosub inside a procedure would be used when there would be a benefit of reusing code with the added speed of not having to handle a procedure call because all operations would be performed on local variables. It only has application in advanced cases, because beginners are never in a hurry. :wink:
The problem is, that with gosub, it's not possible to re-use the local variables because gosub changes the stack offset, and local variables is access with a fixed stack offset. Adjusting this at run-time would bring a way greater speed penalty than using gosub could ever fix.
User avatar
Demivec
Addict
Addict
Posts: 4260
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

Trond wrote:The problem is, that with gosub, it's not possible to re-use the local variables because gosub changes the stack offset, and local variables is access with a fixed stack offset. Adjusting this at run-time would bring a way greater speed penalty than using gosub could ever fix.
That is a reason why something would have to be changed so it could be implemented. I didn't know that was a side-effect. I'm happy to be aware of it now.

On a side note, I'm interrested in a "On <indexvalue> ExecProc" kind of command as well. It would be used instead of the Select/Case. I think it has merits for speed and ease of reading. But that's another story.
Post Reply