* Robert Klemme said:
And, does it feel better? For me it does - for Knuth apparently not. I
haven't felt the need for a goto in ages. I also rarely use continue
and break in loops. My impression is that quite a number of cases where
either is chosen can be greatly improved and actually simplified by
choosing a different loop condition. My 0.02EUR...
Tell that Matz & Co.
,----[ ruby-1.9$ grep -c goto *.c | grep -v 0 ]
Last time I checked C did not have exceptions. Without looking at the
exact locations that fact alone might attribute for quite a few of them:
File ruby/ext/openssl/ossl_ocsp.c
5 100.00% err
File ruby/ext/openssl/ossl_pkcs12.c
3 100.00% err
File ruby/ext/openssl/ossl_pkcs7.c
3 100.00% err
File ruby/bignum.c
8 72.73% bad
1 9.09% bignum
1 9.09% bigparse
1 9.09% out_of_range
"goto", "break" et al aren't bad in itself like to tool is, but it is
like a sharp knife which can do damage more easily when handled
carelessly than an edgeless knife. Also, often a sharp knife is not the
right tool either, like, when you want to fasten a screw.
I do say though that a lot of code I see (and have to change) has
"break" and "continue" in there and becomes easier to read and
understand once you take them out. I do have to concede that in the
past of my company there was one guy who wrote exceptionally bad code.
Looking a bit further at label counts in goto.c:
File ruby/regex.c
39 51.32% fail
4 5.26% numeric_char
4 5.26% invalid_escape
4 5.26% nofinalize
3 3.95% end_of_pattern
3 3.95% restore_best_regs
3 3.95% repeat
3 3.95% normal_char
2 2.63% too_big
2 2.63% memory_exhausted
2 2.63% invalid_pattern
1 1.32% nested_meta
1 1.32% on_failure
1 1.32% unfetch_interval
1 1.32% advance
1 1.32% startpos_adjust
1 1.32% begbuf_match
1 1.32% range_retry
Of course, a state machine is special in a way. Like a parser, which is
typically generated:
File ruby/parse.c
6 8.70% decode_num
6 8.70% trailing_uc
5 7.25% retry
4 5.80% again
4 5.80% eof
3 4.35% yyerrlab
3 4.35% yynewstate
3 4.35% error
3 4.35% yyoverflowlab
2 2.90% yyerrorlab
2 2.90% yyerrlab1
2 2.90% id_regist
2 2.90% gvar
2 2.90% quoted
2 2.90% ternary
2 2.90% yyreduce
2 2.90% escaped
2 2.90% yybackup
2 2.90% yyreturn
2 2.90% id
2 2.90% yydefault
1 1.45% yysetstate
1 1.45% new_id
1 1.45% quotation
1 1.45% yyacceptlab
1 1.45% yyabortlab
1 1.45% start_num
1 1.45% octal_number
1 1.45% newline
If you want to do it yourself, here's the quickly hacked gotolyzer(TM):
Robert@Babelfish2 /c/TEMP
$ cat gotolyzer.rb
#!/bin/env ruby
ARGV << "." if ARGV.empty?
ARGV.each do |dir|
Dir[dir + "/**/*.{h,c}"].each do |file|
cnt = Hash.new 0
File.read(file).scan(%r{\bgoto\b\s+([^\s;]+)}) do |m|
cnt[m] += 1
end
unless cnt.empty?
puts "File #{file}"
sum = 0
cnt.sort_by {|k,v| sum += v; -v}.each do |label, count|
printf "%5d %5.2f%% %s\n", count, count * 100.0 / sum, label
end
puts
end
end
end
Robert@Babelfish2 /c/TEMP
$
You couldn't do that as elegantly and shortly in C. That's the kind of
sacrifice Phlip mentioned.
Cheers
robert