But seriously, looking to use a goto is generally a sign that your program logic is flawed, and perhaps some re-thinking is in order.
Cheers,
Darren :)
Making blanket statements that goto is evil suffer from the dangers of Cargo Cultism.
This is not to say that there isn't wisdom encapsulated there, but if it's learned behavior by ROTE rather than comprehension then the inherent wisdom is lost.
goto, like a gun - isn't evil. It's what you do with it that counts.
I'll not belabor the point already stated clearly by others.
That being said - I haven't had a reason to use goto in perl personally. I'm intrigued by the prospect and I want to know more.
That being said - I don't know if the OP has clearly stated what that reason is in his case. Rather they've been focusing on fending off the initial kneejerk reaction. That reaction however should have been expected.
I don't see that it's necessarily wrong to question the motivation behind the choice however, since it's something that cuts against the grain of the party line concerning 'structured programming'. What I mean by that is simply that for those of us who started programming with a flavor of BASIC and then moved on to other languages, or who took an academic journey to become programmers - we have been taught that using goto is usually a sign that you're doing something 'wrong'. If nothing else it's a sign that you should be thinking about what you're doing very carefully - and the OP is clearly doing that.
Ronnie can you please elaborate on the subject?
Making blanket statements that goto is evil suffers from the dangers of Cargo Cultism.
I couldn't agree more!
By the way, who was it that said that goto is evil? (certainly not me)
but if it's learned behavior by ROTE rather than comprehension then the inherent wisdom is lost.
My sentiments exactly.
I might also add that making assumptions (and drawing conclusions) about one's level of knowledge and experience based on minimal evidence often does the recepient no justice at all, and in some cases can cause hurt and resentment - which does nobody any good.
But it's okay, because I'm not the type of person to take any of this personally :)
By the way, who was it that said that goto is evil?
Edsger W. Dijkstra in the classic paper "Go To Statement Considered Harmful" published in March 1968. This short paper is widely considered the seminal work which began the Structured Programming movement. (what do they teach in schools these days? :-) )
Which is to say, Dijkstra said it worse than his contemporaries thought it was. He also said that he thinks it's better than today's zero-tolerance. There are places where goto really is a good way to solve something.
⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊
The truth is that goto is a tool in the perl arsenal that can be used for good and evil. If anyone here is writing code that isn't indented properly, or relies on side effects from operations, or indeed doesn't parenthesise their arithmetic and logical instructions to prevent unexpected order of evaluation then they, too, should be viewed with disdain from the goto purists.
At least the thread author made a good attempt to justify the reason for needing goto; indeed the author needn't have justified anything. Perl has a goto statement and thus that's reason enough to be allowed to use it.
As a final note, I don't remember the last time I used goto in Perl or C programming (thought I've used it liberally in assembler).
instructional comment: one way of avoiding goto is to create a while loop and, should you want to skip something, use the next statement within the loop.
for my $prog (@programs) {
system($prog)
}
To disable one of the programs, just delete the element from the array. The 'step number' is the index to the array. If the code is more complex then put each step in a subroutine and have an array of subroutine references. The steps to run (or omit) could be passed on the command line.
So, here is my go at a solution to your problem (as I understand it). Please note the distinct lack of a [doc://goto] :p Note that I'm not suggesting that this is the most elegant solution, nor is it the most elegant Perl coding that you will find. (In fact, a LoH is probably a better approach - *shrug* - TIMTOWTDI). But as far as I can tell, it does what you have asked for.
#!/usr/bin/perl -wl
use strict;
# define a HoH containing info about our external scripts
# "file" - the name of the file
# "timeout" - how long we wait for it to finish before giving up
# "tries" - how many attempts we make at exceuting it
# "sleepy" - to simulate an actual run and generate some errors
# "execute" - whether or not we execute it on this run
my %scripts = (
1 => {
file => "/usr/bin/feed_the_cat.sh",
timeout => 5,
tries => 2,
sleepy => 6, # will cause this one to fail
},
2 => {
file => "/usr/bin/put_out_the_garbage.sh",
timeout => 10,
tries => 3,
sleepy => 5, # this one will succeed
},
3 => {
file => "/usr/bin/switch_off_the_lights.sh",
timeout => 10,
tries => 2,
sleepy => 13, # this one will fail
},
# etc, etc...
);
# Set everything to initially be executed
for (keys %scripts) { $scripts{$_}{execute}++; }
# We write any failures to here
my $last_run_failed = "failed.txt";
# Were there any failures on the last run?
if (-f $last_run_failed) {
print "Whoops, looks like we had a few failures on the last run - let's retry them :)";
# Set all scripts to NOT be executed, then
# reset for just those that failed last time
for (keys %scripts) { $scripts{$_}{execute}=undef; }
open FAILED, "<", $last_run_failed
or die "Duh, I couldn't open $last_run_failed!:$!";
while () {
chomp;
$scripts{$_}{execute}++;
}
close FAILED;
# Zap the failed file
unlink $last_run_failed
or die "Oops, I couldn't delete $last_run_failed";
}
SCRIPT:
for my $script (sort keys %scripts) {
# Skip this one if we need to
next SCRIPT if !defined $scripts{$script}{execute};
my $tries = $scripts{$script}{tries};
my $timeout = $scripts{$script}{timeout};
my $sleepytime = $scripts{$script}{sleepy};
TRY:
for my $try (1 .. $tries) {
print "Trying $scripts{$script}{file} (attempt $try/$tries).. ";
eval {
local $SIG{ALRM} = sub { die "alarm\n" };
alarm $timeout;
# The next line is just to simulate the scipt running
# In the real world, you have something like :
# system($scripts{$script}{file};
sleep $sleepytime;
alarm 0;
};
if ($@) {
# It timed out
print "whoops, timed out - let's try again...";
next TRY;
}
else {
# It worked
print "Yup, that one worked - lets move onto the next one..";
next SCRIPT;
}
}
# If we get to here, the script has failed to return within the timeout
# period after the specified number of tries
# Therefore, we record the fact in the "failed" file
print "Looks like $scripts{$script}{file} is foo-bar, giving giving up";
open FAILED, ">>", $last_run_failed
or die "Could not open $last_run_failed:$!";
print FAILED "$script";
close FAILED;
}
On the first run, I get the following output:
Trying /usr/bin/feed_the_cat.sh (attempt 1/2).. whoops, timed out - let's try again... Trying /usr/bin/feed_the_cat.sh (attempt 2/2).. whoops, timed out - let's try again... Looks like /usr/bin/feed_the_cat.sh is foo-bar, giving giving up Trying /usr/bin/put_out_the_garbage.sh (attempt 1/3).. Yup, that one worked - lets move onto the next one.. Trying /usr/bin/switch_off_the_lights.sh (attempt 1/2).. whoops, timed out - let's try again... Trying /usr/bin/switch_off_the_lights.sh (attempt 2/2).. whoops, timed out - let's try again... Looks like /usr/bin/switch_off_the_lights.sh is foo-bar, giving giving upAnd the contents of failed.txt are:
1 3So scripts 1 (feed_the_cat) and 3 (switch_off_the_lights) have failed.
On the second run, I get:
Whoops, looks like we had a few failures on the last run - let's retry them :) Trying /usr/bin/feed_the_cat.sh (attempt 1/2).. whoops, timed out - let's try again... Trying /usr/bin/feed_the_cat.sh (attempt 2/2).. whoops, timed out - let's try again... Looks like /usr/bin/feed_the_cat.sh is foo-bar, giving giving up Trying /usr/bin/switch_off_the_lights.sh (attempt 1/2).. whoops, timed out - let's try again... Trying /usr/bin/switch_off_the_lights.sh (attempt 2/2).. whoops, timed out - let's try again... Looks like /usr/bin/switch_off_the_lights.sh is foo-bar, giving giving upNotice this time that it only ran scripts 1 and 3, and skipped over script 2 (put_out_the_garbage). Of course, failed.txt still contains (1,3) because they failed again.
However, if I edit the script to simulate all three scripts succeeding (by reducing the "sleepytime"), I get:
Whoops, looks like we had a few failures on the last run - let's retry them :) Trying /usr/bin/feed_the_cat.sh (attempt 1/2).. Yup, that one worked - lets move onto the next one.. Trying /usr/bin/switch_off_the_lights.sh (attempt 1/2).. Yup, that one worked - lets move onto the next one..And failed.txt is gone:
/bin/ls: failed.txt: No such file or directoryI won't bother responding to any of the comment's you made which were obviously directed at me, as I've already spent way more time on this than I originally intended to.
Cheers,
Darren :)
question that occurs is - line 34 is setting an execute flag against each value held on the hash table?Well, sortof...
# Set everything to initially be executed
for (keys %scripts) { $scripts{$_}{execute}++; }
..just iterates through the hash, incrementing the value of $scripts{$key}{execute} for each $key. As none of these keys exist at this point, they are created (autovivication) and their respective values are set to 1.
So what we end up with is..
$scripts{1}{execute} = 1
$scripts{2}{execute} = 1
etc...
The same thing happens a little later on (on line 45)...
for (keys %scripts) { $scripts{$_}{execute}=undef; }
...but here we're setting them all to undef.
Then when we get into the main loop, the first thing we do is to test whether that key exists, and if it doesn't we skip it and move on to the next one...
# Skip this one if we need to
next SCRIPT if !defined $scripts{$script}{execute};
Incidentally, those for loops above could be done a little more elegently (and more efficiently) with a [doc://map]...
map { $scripts{$_}{execute}++; } keys %scripts;
Which book covers this - I've bought most of the O'Reilly booksPerl books that I have and would recommend are:
in the sense of different employers and the constraints that might apply depending on employer!Actually, I can empathise with this. I have recently changed employer and moved from an environment that was primarily *nix to one that is primarly *shudder* 'doze. And it hurts, believe me. But fortunately, I am in a position where I do have some level of control - so I'm busily replacing windows boxes with Linux ones whenever and where-ever I can ;)
Finally...
Sorry if the experience comment offendedNone taken. And I _was_ going to let it (and the other comments) go. But after I thought about it a bit I decided that I needed to clarify my position as I felt that I'd been misunderstood (and mis-represented).
Cheers, and good luck with your task at hand!
Darren :)
my @steps = (sub {...}, ...);
my $start_at = shift || 0;
for my $this_step ($start_at .. $#steps) {
$steps[$this_step]() or die "Oops! at step $this_step\n";
}
"Sorry but some of the reponses are idealogical clap trap! "I've never used a goto" indicates a lack of experience not knowledge"
Err..Isn't that just as much a crap response as you claim they are? I have used goto, back in the good old days of basic and by god i was glad to get rid of it as soon as i learned about functions ;) There are many ways to solve your problem, goto is 1 of them sure, but it is one that many of use prefer to avoid. That doesn't signifiy a lack of experience or knowledge, its just a preference. Your desire to use goto even when there are alternatives is fine, but realy, don't bash the people who just tried to help you. If you are too high and mighty for this crowd then don't ask for help, if you arn't then be gratefull for the help you get.
For my two cents i would probably do something like make each job a job.x.pl file where x is a number, then do some magic to start at whatever number you want and system those files....or maybe not. It realy depends on what your programs do.
BTW a very quick google on "perl go to" results in "are you sure you don't want perl goto" so you might just be getting -- for not searching first ;)
Actualy you continue to miss the point. My posts havn't been about wether goto is good or bad, or right or wrong in your case. My posts have been about your attitude. We don't know all of your criteria and you didn't give them to us. Instead you asked a question that was easily answered by google and then continue to complain about the responses. I still fail to see how re-writing 3rd party code to include gotos is any less difficult than other options but agian that is your choice and your issue.
Sorry if this offends your sensibilities but life sucks what can I say!?
That is not what offends me. Your tone and responces however do.
One final English lesson - "preference" implies choice - in this case I have none as re-writing the 3rd party code is NOT an option.
If you are going to teach me english then please at least read the context where the word was used. I was refering to the people who replied to you and there preference not to use goto.
Examine what is said, not who speaks -- Silence betokens consentSo with that in mind....
"I've never used a goto" indicates a lack of experience not knowledge.
Yes, perhaps it does. However, I think you misunderstand me. I actually said "in that time I've never used a goto" - referrring to the length of time I've been using Perl for.
Sure I've used goto's in the past. In fact, the BASIC programs I was writing in 1978 would have been littered with them. But this is 2006, and this is Perl. And thankfully, Perl provides us with a rich set of loop control and program flow features which help us to write more structured programs, and hence avoid bouncing all over the place with goto's.
Unlike some people I know why using goto is frowned upon
Good for you!
And which people would that be, btw?
doesn't alter the fact that there are times and places where it's use is required! This is one such case!
With respect, I disagree. I've already [id://541429|given you] a working example of how you can make do without one. And [monarch], [cdarke] and [Roy Johnson] have also given you pointers to methods that can avoid it.
please respond to the question not demonstrate petty prejudice!
Your original question asked if there was a "go to" in Perl. I told you that
there was, and I gave you links to the appropriate documentation.
How is this not responding to your question?
is to use a goto what will you do? Say to the boss it can't be done because it offends me?
In such a situation, I would use a goto. I'm not quite sure where you got the idea that the use of goto offends me. All I said was "looking to use a goto is generally a sign that your program logic is flawed". And, it generally is. As I've been learning to use Perl, there have been several occassions where I have found myself thinking "mmm, I need to use a goto here". And without exception - after doing some reading or seeking advice from others - I have found that it wasn't necessary at all.
Cheers,
Darren :)
Your trying to tell us that you can modify it to add gotos but not modify it by replacing those gotos with wrapping it in a subroutine? That simply doesn't compute. You asked for help, take what you get and don't complain so much, its simply annoying. You should note that you arn't in a questions and answers forum. You are in a seekers of wisdom forum. That general means that we will provide an answer and some other feedback. It also means that as I already stated, if you post a question thats so simple it can be googled in less than 30 seconds, we are going to assume some ignorance on your part. Who's fault is that? We only know what you tell us through action (your post) and your inaction (your lack of searching). Is that right? Is that just? I don't know, i do know it is human nature though ;)
Searching for "goto" and "go to" on this site (which I presume you have access to) also yeilds results that would have pointed you in the right direction.
So let me get this straight, you've been programming borderline obsolete programming languages in deadend jobs [1] for over three decades, you've now been saddled with the crappy task of improving a badly written system without really changing it, and you're at a company that's so moronic (or has so little trust in you) they won't even allow you decent web access. You don't have a clue about the system in question (saying that a system is "written in UNIX" makes you stand out as a real pro, you know), but you've heard something about this Perl language which is supposed to be good at system administration and integration, so you decide to use it. Unfortunately you don't have a clue about Perl either (at least not enough to ever do perldoc perlfunc) and the thirty years of legacy programming have changed your formerly mediocre problem-solving skills [2] into a one-track "this is how I've always done it" rut. So you post a stupid question and, because you're so down on your life and career, start insulting people who try to help you.
Have I got this about right? Real bundle of joy you are!
[1..2]These aren't baseless assumptions, if you weren't so bad at whatever string of meaningless jobs you attempted you certainly wouldn't be stuck with this kind of task after thirty years.
The 'perldoc' command, despite sometimes being split out from the distribution of Perl in some OS packages and/or core OS installs, is important to have installed. It provides access to documentation about the core language as well as to the included libraries (modules). While it's entirely possible to program Perl on a system that doesn't have perldoc installed, it's pretty darn near impossible for someone to program effectively and efficiently without some type of access to perldoc's functionality. (and hence to easily accessible and readable documentation in general)
In short, having access to the proper documentation for your language should fall under 'having the appropriate tools to work effectively' and is the responsibility of your employer to provide.
At the risk of making an assumption about your current situation, I can't help but find it somewhat sadistic that your employer both does not provide the documentation for a language they've assigned a task for and also will not provide the required tools to do your work when requested with the vague reasoning of 'not enough disk space'. Surely you can approach your employers and request that you either be permitted to have access to the documentation for the version of Perl you're working with, possibly on your workstation itself, or possibly via access to a website that has them. You should pay keen attention to finding the documentation appropriate for the version of Perl that you are working with as the language has changed quite significantly in its lifetime.
In addition, although the pointers to documentation that you've received were in response to your original request for information related to 'goto', however I would expect that you'll be very likely to require additional information that is clearly illustrated in the documentation in the future. I hope that you are able to acquire what you need.
Good luck!
Whoa there, big fella! No point in falling to the level of whoever is baiting you. :)
I see you've been around the Monastery for a while, albeit intermittently, so you ought to know how things are done around here. At the risk of giving unwanted advice, I have three comments:
In spite of what may seem a patronizing tone, my comments here are kindly meant, and may help you to make PerlMonks a more positive place for all of us. I'm not the anonymous monk(s) with whom you have been sparring, just in case you wondered. Try to view this interchange with a sense of humor, and take yourself a little less seriously. :)
You do miss the fundamental point of "eye for an eye" - it sets the upper limit for any punishment for a crime/transgression. The idea is not restricted to the Jewish belief, and surely does not mean that there is any obligation for you to "respond in kind". To "respond in kind" is juvenile behaviour, but there are many people who never overcome it when they grow older.
My dictionary did not find a definition of "prozletizer" - what kind of belief system is that?
You may view the original node and the consideration vote tally.
I appreciate your thoughtful response, and that you did not take offense at my remarks. :)
Two thoughts:
While both of those quotes can be found in the Christian Bible, I think that they are applicable to people of any faith (or none), in that they accurately depict real life (in addition to having spiritual value). We all admire someone who is 'big enough' to overlook a petty insult, someone who is not easily distracted from their goal by divisive remarks. And I think I am not alone in being motivated to help a humble person while desiring to 'take down a peg or two' a person who comes across as arrogant.
Although you are not the first to complain of 'bullying' or 'abuse' in this community, I'm not sure street sense will be very helpful here. After all, PerlMonks is almost entirely an exchange of words (and in some cases, ideas) between strangers. I've only met one other monk in real life (merlyn) that I know of, and although I found him to be a likeable and intelligent man, I'm pretty sure he doesn't know me from Adam (except that I'm alive and, thankfully, wear more than a fig leaf). To me (and I think to many others, including those inclined to nitpick) this community is just a fun place to exchange ideas in relative anonymity, and it is not possible to be abused here if one keeps a level head and doesn't take one's self too seriously. Ultimately, the only victory anyone can score against you here is to goad you into writing things that tarnish your own soul.
I would cheerfully let someone 'stand on me' verbally if I thought it would help me to get an answer I badly needed, and I would feel in no way diminished by the exchange. My 'rights' (to be treated respectfully, to be honored as a person) are not my master; I can (and do) freely waive them if they keep me from my objectives. While I'm not a pacifist, I can conceive of situations in which I might choose to waive my 'right' to defend myself physically, as well. But we are not playing for such high stakes here.
I'm not just trying to get the last word ... I really think that you should re-evaluate the way you think of this online community. It is a lot more fun to view it as a game or contest of wits than to take it personally, in my opinion. :)
What is a next/last but a goto? In fact, next LABEL; or last LABEL; are both gotos without much of a disguise. The only constraint upon them is that the label must be on a loop enclosing the next/last statement. next/last will even work within a subroutine.
use strict;
use warnings;
sub foo {
next LOOP;
}
LOOP: for ( 1 .. 10 ) {
if ( $_ < 5 ) {
foo();
}
print "$_\n";
}
----
Exiting subroutine via next at ./test.pl line 7.
Exiting subroutine via next at ./test.pl line 7.
Exiting subroutine via next at ./test.pl line 7.
Exiting subroutine via next at ./test.pl line 7.
5
6
7
8
9
10
Yes, a warning is thrown, but the code still works as expected.
As for a goto being an indication of flawed program logic, that's completely and utterly not true. Why do you use next/last? Here's an example:
while (Pretty easy to understand, right? Let's see what happens if next/last are disallowed because they're goto in disguise . . .) { next unless length; # Skip blank lines next if /^#/; # Skip comments next if /\bSKIP\b/; # Skip lines that want to be skipped # Do something useful here }
while (I hope the point is made.) { if ( length ) { if ( !/^#/ ) { if ( !/\bSKIP\b/ ) { # Do something useful here } } } }
I hope the point is made.Yes, the point is most definitely made, and taken :)
And I'll be the first to admit that I use next and last quite liberally.
And I'll also admit that I was quite surprised to find that goto hardly rates a mention in PBP - I suppose that can be taken to indicate that the author also condones its use.
However, I still think that I'll continue to avoid goto as much as possible in the future ;)
Cheers, and thanks..
Darren :)
But, to dismiss goto out of hand begs the question - why did Larry include goto? Djikstra's paper was 20 years before the release of Perl 1.0 and I'm pretty he knew about it.
Cheers - L~R
* - The link in that thread is dead ATM.
In that paper Knuth has two basic arguments for goto. The first is that there are algorithms that can be more efficiently written with goto than without. The second is that it is useful for exception handling. He also quotes a theorem that named loop control would obviate the first point.
Perl has exactly that form of named loop control, so the algorithmic argument for goto does not apply in Perl. (Besides, Perl's implementation of goto is not very efficient...) And since the 70's the idea of structured exception handling has come around. That is much better than the use of goto for the same purpose. Therefore Knuth's arguments fail for Perl.
For more detail on my opinions about goto, node 126026 is still accurate. And no, I have not run into any more legitimate needs for goto in Perl.
Since sed scripts use goto extensively, he either needed to automatically translate sed scripts to goto-less versions, or else he needed to add goto to Perl. It was easier to add goto to Perl, so he did.
This is one of the two necessary uses of goto that I have seen in Perl.
#!/usr/bin/perl -w
use strict;
use warnings;
sub step_1 {
print "Programming step 1\n";
# do junk
}
sub step_2 {
print "Programming step 2\n";
# more junk
}
sub step_3 {
print "Programming step 3\n";
# lots more junk
}
my @STEPS = (\&step_1, \&step_2, \&step_3);
my $SKIP=shift || 0;
for my $ST (0 .. $#STEPS) {
if ($ST < $SKIP) {
print "Skipping step $ST\n";
}
else {
&{$STEPS[$ST]};
}
}
--roboticus
In believing that you need to use goto to get your job done, you probably have an XY problem.
From what I understood of the original problem -- [Ronnie] has to port some code over to Perl, from some shell scripts.
It makes perfect sense to me to try to keep the logic flow the same between programs for the first iteration. If the program's logic was working, it makes no sense to try to refactor it at the same time ... we have no idea what the deadlines are, or any other constraints on this project, and I don't personally see the point in spouting ideology on this particular point, as goto has its uses.
I've used goto in Perl quite a few times in the past year. Most frequently, it's inside functions like AUTOLOAD that generate closures, and then goto the new function ... or any other time I insert logging functions in a child that I don't want to show up if the parent looks at caller:
my $obj = child->new();
$obj->do_something();
my $obj2 = child2->new();
$obj2->do_something();
exit;
package parent;
use Data::Dumper;
sub do_something {
warn Dumper { 'caller' => [ caller ] };
}
sub new { my $class = shift; return bless {}, $class };
package child;
use base qw( parent );
sub do_something {
my $self = shift;
$self->SUPER::do_something;
}
package child2;
use base qw( parent );
sub do_something {
goto &{'parent::do_something'};
}
So please whether you've been programming for a couple of years or like some of us 20 odd years please respond to the question not demonstrate petty prejudice!
The problem is, they *have* been responding to your question... You've just forgotten what you originally asked:
but there doesn't appear to be a "go to" facility in Perl can this be true? If so is there any other method available that will allow me to jump code given certain conditions?
You *did* ask if there were any other methods available to jump code, and Perl has a multitude of ways to do that without resorting to the infamous 'goto'.
And I, too, am a reformed mainframer with over 20 years in the business, and I wrote of my share of GOTO and PERFORM-THRU in my day... but in the last seven years (since I've been writing Perl) I haven't *needed* one.
That doesn't mean there's not occasions where it's appropriate, I just haven't had any reason to do it.
You asked for other methods... you shouldn't be surprised that you got 'em...