Breaking out of nested subroutine?

H

Hemant Shah

Folks,

How do I break out from a nested subroutine to the outside of parent
subroutine?


# ----- Module2.pm
sub Function2()
{

sub Function3()
{
If certain condition is met go back to Function1.
How do I return to Function1 from here?
}

Some perl code.

Function3();

More perl code.
}


# ----- Module1.pm

use Module2;

sub Function1()
{
Module2::Function2();

How do I get here from Function3()?

More code.
}


# ----- Main Program

use Module1;

Module1::Function1();

More code.



Thanks.

--
Hemant Shah /"\ ASCII ribbon campaign
E-mail: (e-mail address removed) \ / ---------------------
X against HTML mail
TO REPLY, REMOVE NoJunkMail / \ and postings
FROM MY E-MAIL ADDRESS.
-----------------[DO NOT SEND UNSOLICITED BULK E-MAIL]------------------
I haven't lost my mind, Above opinions are mine only.
it's backed up on tape somewhere. Others can have their own.
 
M

Matt Garrish

Hemant Shah said:
Folks,

How do I break out from a nested subroutine to the outside of parent
subroutine?


# ----- Module2.pm
sub Function2()
{

sub Function3()
{
If certain condition is met go back to Function1.
How do I return to Function1 from here?
}

Some perl code.

Function3();

More perl code.
}


# ----- Module1.pm

use Module2;

sub Function1()
{
Module2::Function2();

How do I get here from Function3()?

More code.
}


# ----- Main Program

use Module1;

Module1::Function1();

More code.

Return a value from Function3 indicating whether you should go back to
Function1. As a rather contrived example:

Function1();

sub Function1 {
Function2();
print "Have a good day!\n";
}

sub Function2 {
my ($ok, $retval) = Function3();
return unless $ok;
print "Your lucky number is $retval!\n";
}

sub Function3 {
my $x = sprintf("%2d", rand(1)*100);
if ($x != 13) {
return 1,$x;
}
else {
return 0,0;
}
}

Matt
 
G

gnari

Hemant Shah said:
Folks,

How do I break out from a nested subroutine to the outside of parent
subroutine?


# ----- Module2.pm
sub Function2()
{

sub Function3()
{
If certain condition is met go back to Function1.
How do I return to Function1 from here?

return ABORTVALUE if somecondition;
}

Some perl code.

Function3();
return if Function3() == ABORTVALUE;
More perl code.
}

gnari
 
B

Bob Walton

Hemant Shah wrote:

....
How do I break out from a nested subroutine to the outside of parent
subroutine?


# ----- Module2.pm
sub Function2()
{

sub Function3()
{
If certain condition is met go back to Function1.
How do I return to Function1 from here?
}

Some perl code.

Function3();

More perl code.
}


# ----- Module1.pm

use Module2;

sub Function1()
{
Module2::Function2();

How do I get here from Function3()?

More code.
}


# ----- Main Program

use Module1;

Module1::Function1();

More code.


Menant, you can put a block around the call to Function2(), and then use
a "last" statement to break out of that block. Like:

# ----- Main Program
use junk479m1;
print "main program\n";
junk479m1::Function1();
#More code.
print "more code in main program\n";


# ----- junk479m1.pm
package junk479m1;
use junk479m2;
sub Function1()
{
print "function1\n";
{junk479m2::Function2();} #note block around the call

#How do I get here from Function3()?
#More code.
print "function1 more code\n";
}
1;

# ----- junk479m2.pm
package junk479m2;
sub Function2()
{
sub Function3()
{
print "function3\n";
#If certain condition is met go back to Function1.
last; #execute this conditionally
#How do I return to Function1 from here?
print "more stuff in function3\n";
}
#Some perl code.
print "function2\n";
Function3();
print "more code in function2\n";
#More perl code.
}
1;

HTH. BTW, your modules were missing the "package" statement and they
did not return a true value as written. Also, the definition of a sub
inside a sub another sub is OK, I guess, but a bit unconventional. I'm
not sure if it compiles it everytime Function2 is executed? If so, that
would be a waste of cycles.
 
M

Mladen Gogala

Folks,

How do I break out from a nested subroutine to the outside of parent
subroutine?

What you are asking for, is called a non-local goto in C terminology,
and is considered an extremely bad programming practice. In order to
emulate it, one would have to have a subroutine called main() (where did I
see that before?) set it up as a signal handler for, say, signal 10
(USR1). When one wants to jump back from a subroutine, signal is sent to
itself by using kill function. and you find yourself back in the "main"
function. That was, in essence, the same way it was implemented in C
library. Of course, your perl script would look like this.

#!/usr/bin/perl -w
use strict;
# You need POSIX package to send signal to yourself. It contains
# the getpid() function needed to get your process id.
use POSIX;
use Whatever::else::You::want::to::use;
# Global variables
my ($glob1,$glob2,....,$globn);
main;

sub main {
.....
}

Normally, perl programmers have hard time to un-learn things like C,
and master perl idioms. What you are asking for, is a C programming
technique, so you'll have to emulate program structure and behavior
of the C programs, which means going exactly the opposite way then
the most perl programmers usually go.
 
Z

Zeljko Vrba

Folks,

How do I break out from a nested subroutine to the outside of parent
subroutine?
As someone already said, this is nonlocal goto (setjmp/longjmp in C).
In perl you can emulate this with die/eval:

eval {
# call your sub
}
if($@ eq 'something') {
# $@ is return value from die
}

your sub:
sub X {
# whatever
die 34; # this is your return value to innermost eval{}
}
 
A

Anno Siegel

Bob Walton said:
Hemant Shah wrote:
[...]

... Also, the definition of a sub
inside a sub another sub is OK, I guess, but a bit unconventional. I'm
not sure if it compiles it everytime Function2 is executed? If so, that
would be a waste of cycles.

A sub definition is only compiled once, nested or not. What you get is
a named closure (unless you consider that a contradiction in terms).
That is, the inner sub can access lexical variables defined in the
outer one.

Come to think of it, that's another way to abort a call:

sub outer {
# ...
my $abort;
sub inner {
# ...
if ( some_condition() ) {
$abort = 1;
return;
}
# ...
inner( ...);
return if $abort;
# ...
}

However, that's all too tricky for my taste. The straightforward method
is to return something characteristic from the inner call that tells
the outer call not to continue.

Anno
 
B

Brian McCauley

Bob Walton said:
Hemant Shah wrote:
[...]

... Also, the definition of a sub
inside a sub another sub is OK, I guess, but a bit unconventional. I'm
not sure if it compiles it everytime Function2 is executed? If so, that
would be a waste of cycles.

A sub definition is only compiled once, nested or not. What you get is
a named closure (unless you consider that a contradiction in terms).

It does not behave a proper closure.
That is, the inner sub can access lexical variables defined in the
outer one.

But only the first time the outer sub is called.
Come to think of it, that's another way to abort a call:

sub outer {
# ...
my $abort;
sub inner {
# ...
if ( some_condition() ) {
$abort = 1;
return;
}
# ...
inner( ...);
return if $abort;
# ...
}

However, that's all too tricky for my taste.

Also it doesn't work after the fist call to outer().

For further explaintion of this, look up the explaintion of the
warning that perl will emit when you compile the above code.

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
A

Anno Siegel

Brian McCauley said:
Bob Walton said:
Hemant Shah wrote:
[...]

... Also, the definition of a sub
inside a sub another sub is OK, I guess, but a bit unconventional. I'm
not sure if it compiles it everytime Function2 is executed? If so, that
would be a waste of cycles.

A sub definition is only compiled once, nested or not. What you get is
a named closure (unless you consider that a contradiction in terms).

It does not behave a proper closure.

You're right.
But only the first time the outer sub is called.


Also it doesn't work after the fist call to outer().

For further explaintion of this, look up the explaintion of the
warning that perl will emit when you compile the above code.

Yeah... missed that too.

Sorry for the sloppy posting.

Anno
 
H

Hemant Shah

While said:
Hemant Shah wrote:

...


Menant, you can put a block around the call to Function2(), and then use
a "last" statement to break out of that block. Like:

# ----- Main Program
use junk479m1;
print "main program\n";
junk479m1::Function1();
#More code.
print "more code in main program\n";


# ----- junk479m1.pm
package junk479m1;
use junk479m2;
sub Function1()
{
print "function1\n";
{junk479m2::Function2();} #note block around the call

#How do I get here from Function3()?
#More code.
print "function1 more code\n";
}
1;

# ----- junk479m2.pm
package junk479m2;
sub Function2()
{
sub Function3()
{
print "function3\n";
#If certain condition is met go back to Function1.
last; #execute this conditionally
#How do I return to Function1 from here?
print "more stuff in function3\n";
}
#Some perl code.
print "function2\n";
Function3();
print "more code in function2\n";
#More perl code.
}
1;

HTH. BTW, your modules were missing the "package" statement and they
did not return a true value as written. Also, the definition of a sub
inside a sub another sub is OK, I guess, but a bit unconventional. I'm
not sure if it compiles it everytime Function2 is executed? If so, that
would be a waste of cycles.

Thanks, I will give that a try. The code I posted was just a small
fragment, so it did not have all the statements from a perl module.

--
Hemant Shah /"\ ASCII ribbon campaign
E-mail: (e-mail address removed) \ / ---------------------
X against HTML mail
TO REPLY, REMOVE NoJunkMail / \ and postings
FROM MY E-MAIL ADDRESS.
-----------------[DO NOT SEND UNSOLICITED BULK E-MAIL]------------------
I haven't lost my mind, Above opinions are mine only.
it's backed up on tape somewhere. Others can have their own.
 
H

Hemant Shah

Folks,

Thanks for all the different ways to break out of a nested subroutine
I will give them a try and see which works.

There may be a simpler way in the module I am using.

I am using XML::pARSER to parse an xml file and have define handlers for
Start, End, and Char. I want to stop processing, when I encounter a
particular tag (i.e. break out of Start handler and stop further processing
of XML file).



--
Hemant Shah /"\ ASCII ribbon campaign
E-mail: (e-mail address removed) \ / ---------------------
X against HTML mail
TO REPLY, REMOVE NoJunkMail / \ and postings
FROM MY E-MAIL ADDRESS.
-----------------[DO NOT SEND UNSOLICITED BULK E-MAIL]------------------
I haven't lost my mind, Above opinions are mine only.
it's backed up on tape somewhere. Others can have their own.
 
S

Seungbeom Kim

Mladen said:
What you are asking for, is called a non-local goto in C terminology,
and is considered an extremely bad programming practice.

You can't generalise like that. Those situations happen quite frequently,
and they're what exception handling in C++, Java, etc. is designed for.
 
5

510046470588-0001

Seungbeom Kim said:
You can't generalise like that. Those situations happen quite
frequently, and they're what exception handling in C++, Java, etc. is
designed for.

Scheme is much better off, as it has call-with-current-continuation
which even allows to resume subroutines later on.

Klaus Schilling
 
M

Mladen Gogala

You can't generalise like that. Those situations happen quite
frequently, and they're what exception handling in C++, Java, etc. is
designed for.

Exception handling is not the same as longjmp. Exception handling is an OO
technique in which objects "throw error objects" (unfortunately, English
betrays us here) which are then "caught" in exception handlers. Non-local
goto or long jump is also a technique based on system trap, but without
any handlers, just a context switch. The expression "break out of
subroutine" is more reminiscent of longjmp then of the throw-catch
mechanism, at least in my opinion. You'll note that, in contrast to C,
perl doesn't have "goto" command, which was deemed bad by Mr. Dijsktra in
his historic paper called "Modular Programming", published in the middle
of the last century. From the point of view of modular programming, any
goto is a bad thing. Non-local goto is a very bad thing, I'm afraid.
 
B

Brian McCauley

Mladen Gogala said:
Exception handling is not the same as longjmp. Exception handling is an OO
technique in which objects "throw error objects" (unfortunately, English
betrays us here) which are then "caught" in exception handlers. Non-local
goto or long jump is also a technique based on system trap, but without
any handlers, just a context switch. The expression "break out of
subroutine" is more reminiscent of longjmp then of the throw-catch
mechanism,

Doesn't seem to inply one mechanism over the other to me.
at least in my opinion.

Throw-catch is just a more elegant way to do what longjmp achieved in
a rather quick and dirty fashion. In Perl (and other modern
languages) when you break out of deep stack frame t unwinds the stack
giving each stack frame a chance to clean up after itself.
You'll note that, in contrast to C, perl doesn't have "goto"
command,
Errr...?

which was deemed bad by Mr. Dijsktra in
his historic paper called "Modular Programming", published in the middle
of the last century. From the point of view of modular programming, any
goto is a bad thing.

Be aware that not only is Perl's goto() a goto but so too are
return(), next(), last() and especially redo().

Use the best tool for the job. Do not let just reject it because it
has been "deemed bad".

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
M

Mladen Gogala


You are right. I've never used it, and I didn't even know it existed.
Be aware that not only is Perl's goto() a goto but so too are
return(), next(), last() and especially redo().

Next is an equivalent to "continue", last is an equivalent to "break".
C doesn't have anything like "redo". Why do you think those are goto's?
When you translate them to assembly language, they all do include JMP
command, but they're not equivalent to the goto command in its classic
sense.
Use the best tool for the job. Do not let just reject it because it
has been "deemed bad".

Modular programming dictates you to break program in subroutines and
functions where it makes sense, instead of writing monolithic monsters
having 10,000+ lines of code in a single program unit. When you have
subs, goto just doesn't look like The Right Way (TM) to control the
program flow. Of course, it is all highly subjective. The important
thing for programs is to work and to be easy to maintain. If you can
achieve that with a goto or two, good for you.
 
U

Uri Guttman

A> Well, I find 'goto' in C programs quite handy. In Perl too, except I
A> usually spell 'goto' as 'redo', 'next' or 'last'.


A> BTW, I've no doubt that Mr. Dijkstra would have the same dim
A> opinion about Perl as a language as he had for 'goto' as a
A> statement.

heh, i agree. we all want those fun state variables in each nested loop
and checking for them at each level. GAHHH!!!!

and to the OP, magic goto is very useful but has little to do with
classic goto. larry had a bad habit of overloading function names (eval,
select, goto).

uri
 
M

Matija Papec

X-Ftn-To: Abigail

Abigail said:
A few things:

- Perl does have a 'goto' statement. In fact, it has three goto statements,
and three statements who, while they aren't spelled 'goto', aren't very
different from a 'goto'. ('last', 'next' and 'redo').

But they are different, and they differ in significant way; at least when
analyzing code from algorithm perspective.
- The paper you are referring to is:
Edsger W. Dijkstra: "Go To Statement Considered Harmful"
However, the title isn't his. The title he put on the paper he submitted
to the CACM was "A case against the GOTO statement"; the editor, Niklaus
Wirth, changed the title.
- There's another famous computer scientist, who, unlike EWD, gives the
impression of actually having used a computer more than once in his life.
He also wrote a paper. The paper I refer to:
Donald E. Knuth: "Structured Programming with goto Statements"
I prefer this 72 page discussion of goto's pro and cons over the 2.5 page
emotional pamphlet of EWD. Heck, DEK's reference list is longer than EWDs
entire paper.

IMO, using goto is like swearing. There are people that never swear, even
when they should, and so they cut themselves from clear and straight to the
point way of expression (at least in some specific situations). On the other
hand, Dijkstra IMHO had some hard time with poor programmers which were
swearing all the time, so he came to idea to take away "goto" freedom from
them so their work could become more readable. It all depends to whom are
you applying the rules which brings us to familiar cons. and pros. for
freedom/strict environment.
 
M

Michele Dondi

On Thu, 29 Jul 2004 18:55:35 -0400, Mladen Gogala

[about goto()]
You are right. I've never used it, and I didn't even know it existed.

Not only does it exist, but it also allow an &-form which is not
really a goto in the sense you were talking about:

[admittedly stupid example]


#!/usr/bin/perl -l

use strict;
use warnings;

sub doit;

doit $_, qw/foo bar baz/ for 0..2;

sub doit () {
my $i=shift;
print "Operation <$i>:";
goto ( sub { print for @_ },
sub { print scalar @_ },
sub { print "@_" } )[$i];
}

__END__



Michele
 
M

Mladen Gogala

Well, I find 'goto' in C programs quite handy. In Perl too, except I
usually spell 'goto' as 'redo', 'next' or 'last'.

It's not the same thing. The "C" equivalent of "next" is "continue",
equivalent of "last" is "break", while C doesn't have an equivalent of
"redo". If the command exists, you are welcome to use it, but I want to be
the one who would maintain your programs, if you make an extensive use of
the "goto" command. Modular programming languages are usually accompanied
by certain kind of aesthetics which regards the use of "goto" statement as
"ugly". This is not a liberty issue, this is aesthetics. It's exactly the
same thing as putting a bra on the goddess of justice, or putting a
loincloth on a replica of Michelangelo's "David": doable, but silly.
 

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

Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top