Use 'GoTo' between different subs, same module?

E

Ed

In the same module, I have a main Sub with a few other Subs containing
repeated routines. Can I place a GoTo line in the main Sub, and then as
part of another Sub have something like:

For Each whatever
If whatever = 0 Then
bolFlag = True
Exit For
.....

If bolFlag = True Then GoTo placeinmainsub
End Sub

Ed
 
H

Helmut Weber

Hi Ed,

you call another sub in the same project,
not necessarily the same module,
just by using it's name. Like:

Sub test01()
Dim rDcm As Range
Set rDcm = ActiveDocument.Range
With rDcm.Find
.Text = "quick"
If .Execute Then
test02 'or
' call test02
End If
End With
End Sub
' ---
Sub test02()
MsgBox "test02"
End Sub

Not to mention how to pass arguments, which may be optional...

--
Greetings from Bavaria, Germany

Helmut Weber, MVP WordVBA

Win XP, Office 2003
"red.sys" & Chr$(64) & "t-online.de"
 
E

Ed

Thanks for the reply, Helmut. What I was trying to do was to jump to a
certain point in the main sub, not necessarily the beginning.

Ed
 
J

Jonathan West

Helmut's code causes you to jump back to the main sub at the point you left
it.

If you want to jump to different places depending on what happens in the
called routine, then I suggest you do something like this

Sub test01()
Dim rDcm As Range
Dim i As Long
Set rDcm = ActiveDocument.Range
With rDcm.Find
.Text = "quick"
If .Execute Then
i = test02()
Select Case i
case 1
Goto GoHere
Case 2
Goto GoThere
case 3
Goto GoElsewhere
End Select
End If
End With
Exit Sub

GoHere:
MsgBox "You went here"
Exit Sub

GoThere:
MsgBox "You went there"
Exit Sub

GoElsewhere:
MsgBox "You went elsewhere"
Exit sub

End Sub
' ---
Function test02() As Long
test02 = 1 'or 2 or 3
End Sub

--
Regards
Jonathan West - Word MVP
www.intelligentdocuments.co.uk
Please reply to the newsgroup
Keep your VBA code safe, sign the ClassicVB petition www.classicvb.org
 
E

Ed

Jonathan West said:
Helmut's code causes you to jump back to the main sub at the point you left
it.

If you want to jump to different places depending on what happens in the
called routine, then I suggest you do something like this

Jonathan and Helmut:
Here's what I'd like to do, if it's possible. It's jumping between subs in
the same module, not necessarily back to the point where I left.

Sub Main()
' do stuff
ComeBack: '<=== want to return here
For Each whatever
'do more stuff
If Len(whatever) <> 0 Then
'do stuff
Else
NextSub '<=== jump to another sub in same module
End If
Next whatever
End Sub

Sub NextSub()
For Each whosit
If whosit <> 0 Then
'do stuff
Else
GoTo ComeBack '<== return to point in Main sub.
End If
Next whosit
End Sub
 
K

Karl E. Peterson

Ed said:
Jonathan and Helmut:
Here's what I'd like to do, if it's possible. It's jumping between
subs in the same module, not necessarily back to the point where I
left.

Sub Main()
' do stuff
ComeBack: '<=== want to return here
For Each whatever
'do more stuff
If Len(whatever) <> 0 Then
'do stuff
Else
NextSub '<=== jump to another sub in same module
End If
Next whatever
End Sub

Sub NextSub()
For Each whosit
If whosit <> 0 Then
'do stuff
Else
GoTo ComeBack '<== return to point in Main sub.
End If
Next whosit
End Sub

If you use Exit Sub at the point of GoTo ComeBack, execution will continue
in Main at the statement following the call to NextSub. It sounds like
that's your goal?
 
E

Ed

Karl E. Peterson said:
If you use Exit Sub at the point of GoTo ComeBack, execution will continue
in Main at the statement following the call to NextSub. It sounds like
that's your goal?

No - the goal is to return to a **different** point than the one I left,
**before** I called NextSub, if it is possible.
 
K

Karl E. Peterson

Ed said:
No - the goal is to return to a **different** point than the one I
left, **before** I called NextSub, if it is possible.

Ahh... I see now, the big arrow and string of asterisks, yes. <g>

Well, no, that's not directly supported. It is, in a word, what is commonly
called *spaghetti* code -- the sort of practice that gave BASIC such a bad
name in the first place.

You can of course _almost_ do what you want, by sticking another GoTo
ComeBack under the call to NextSub.

But what you have here is a *massive* failure to properly design the
algorithm. Something the person who inherits this code will run away from
screaming, eyeballs having exploded all over the monitor...

You get what I'm saying? <g>
 
J

Jay Freedman

Ed said:
Jonathan and Helmut:
Here's what I'd like to do, if it's possible. It's jumping between
subs in the same module, not necessarily back to the point where I
left.

Sub Main()
' do stuff
ComeBack: '<=== want to return here
For Each whatever
'do more stuff
If Len(whatever) <> 0 Then
'do stuff
Else
NextSub '<=== jump to another sub in same module
End If
Next whatever
End Sub

Sub NextSub()
For Each whosit
If whosit <> 0 Then
'do stuff
Else
GoTo ComeBack '<== return to point in Main sub.
End If
Next whosit
End Sub

Hi Ed,

The answer in general is no, you can't do that. At least, not that way. For
one thing, none of the procedures "know" anything about the labels in the
other procedures. Jonathan's suggestion is the right way to do it: make the
called sub into a function that returns some value depending on what
happened inside it, and then use If or Select Case in the calling sub to
redirect execution according to the returned value.

Under the covers, here's what happens when you call a subroutine:
- VBA saves a "snapshot" of the calling routine -- the variable values and
the pointer to the address of the currently executing statement (the call).
- It loads the code of the called routine into memory and starts executing
it at the beginning. During this phase, the calling routine is suspended,
and not necessarily anywhere in memory.
- When the called routine finishes, VBA unloads it and reloads the calling
routine. Execution resumes at the point immediately after the calling
statement address that was stored -- there's no way to change that, because
VBA has no mechanism to compute the address of some arbitrary label in code
that isn't even in memory.

--
Regards,
Jay Freedman
Microsoft Word MVP
Email cannot be acknowledged; please post all follow-ups to the newsgroup so
all may benefit.
 
E

Ed

Well, no, that's not directly supported. It is, in a word, what is
commonly
called *spaghetti* code -- the sort of practice that gave BASIC such a bad
name in the first place
But what you have here is a *massive* failure to properly design the
algorithm. Something the person who inherits this code will run away from
screaming, eyeballs having exploded all over the monitor...

And that's why I come here, to learn from the Masters!! <g>

Here's the basics of what I'm doing:
In MainSub -
-- Initial setup (it's all contained within the cells of a single table)
-- Begin main processing loop (this is where I want to come back to)
|__ Iterate through cells
|__ If a certain condition is found, jump to NextSub
Else keep going

In NextSub -
-- Loop through subset of cells doing stuff
|__ If a certain condition results that changes the setup Then
Return to beginning of main processing loop (the arrow and
asterisks)
Else keep going

How should this be >>correctly<< broken down, so as to save the eyeballs of
the world?

Ed
 
E

Ed

- When the called routine finishes, VBA unloads it and reloads the calling
routine. Execution resumes at the point immediately after the calling
statement address that was stored -- there's no way to change that,
because

And if I've used module-level variables across both routines - which I
usually do - then I could wind up somewhere unexpected with an incorrect
variable value. Now some of my head-scratching moments are starting to
clear up!

The answer, then, is what I think Jonathan and Karl are trying patiently to
explain - break routines and subroutines up into self-contained chunks that
can be fully terminated before moving into the next chunk? Am I getting
warm?

Ed
 
K

Karl E. Peterson

Ed said:
And that's why I come here, to learn from the Masters!! <g>

I'm glad you're (still) smiling. :)
Here's the basics of what I'm doing:
In MainSub -
-- Initial setup (it's all contained within the cells of a single
table)
-- Begin main processing loop (this is where I want to come back to)
|__ Iterate through cells
|__ If a certain condition is found, jump to NextSub
Else keep going

In NextSub -
-- Loop through subset of cells doing stuff
|__ If a certain condition results that changes the setup Then
Return to beginning of main processing loop (the arrow and
asterisks)
Else keep going

How should this be >>correctly<< broken down, so as to save the
eyeballs of the world?

Well, this is total air code, but it's more in keeping with accepted
standards. (Assuming, of course, I really understand your requirements.)

Sub Main()
Dim Complete As Boolean
' do stuff
Do
' Assume success for this loop through.
Complete = True
' Iterate through something.
For Each whatever
' do more stuff
If Len(whatever) <> 0 Then
' do stuff
Else
' Anomoly, need to process subset of cells
Complete = NextSub()
' start iteration over if NewSub failed
If Not Complete Then Exit For
End If
Next whatever
Loop Until Complete
End Sub

Function NextSub() As Boolean
For Each whosit
If whosit <> 0 Then
'do stuff
Else
'Failure, time to start over!
Exit Function
End If
Next whosit
' Wow, made it here, must have been successful.
NextSub = True
End Function

Later... Karl
 
E

Ed

Thanks for the patience, Karl. I will chew on this for a while and see if I
can trim my spaghetti back!

Ed
 
J

Jonathan West

Ed said:
because

And if I've used module-level variables across both routines - which I
usually do - then I could wind up somewhere unexpected with an incorrect
variable value. Now some of my head-scratching moments are starting to
clear up!

The answer, then, is what I think Jonathan and Karl are trying patiently
to
explain - break routines and subroutines up into self-contained chunks
that
can be fully terminated before moving into the next chunk? Am I getting
warm?

That is much better!

Follow these general rules for your routines

1. Keep them relatively short

2. Have each routine perform a single task.

3. Give it a meaningful name

4. Keep variables local wherever possible, and give them meaningful names

5. Where data needs to be returned to the calling routine, pass it back as
the return value of a function wherever possible

6. Where possible use structured branching (i.e. If-Then, Select Case,
For-Next, Do-Loop etc) in preference to Goto. (This doesn't mean you should
*never* use Goto, but if you have a good design you shouldn't need it all
that often)

7. If you need to drop out of a loop early, use the Exit command (Exit Do,
Exit Do etc)

8. Thoroughly test each individual routine with the full range of data that
it might receive, before going on to the next.

More information can be found in these articles

The art of defensive programming
http://www.word.mvps.org/FAQs/MacrosVBA/MaintainableCode.htm

How to cut out repetition and write much less code, by using subroutines and
functions that take arguments
http://www.word.mvps.org/FAQs/MacrosVBA/ProcArguments.htm

Why variables should be declared properly
http://www.word.mvps.org/FAQs/MacrosVBA/DeclareVariables.htm

Also, I would strongly recommend buying a book called "Code Complete" by
Steve McConnell. It describes these principles much better than I can.


--
Regards
Jonathan West - Word MVP
www.intelligentdocuments.co.uk
Please reply to the newsgroup
Keep your VBA code safe, sign the ClassicVB petition www.classicvb.org
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top