From: Robert Klemme Date: 2008-04-26T21:45:03+09:00 Subject: Re: goto On 26.04.2008 01:29, Simon Krahnke wrote: > * Robert Klemme (08:32) schrieb: > >> On 21.04.2008 23:28, Michael W. Ryder wrote: >>> I chose this after reading about it in Knuth's 2nd volume. I wanted >>> to try to implement the binary greatest common divisor algorithm in >>> Ruby. It took a little effort but I was able to implement it without >>> any Go Tos. It is hard to go from languages that require jumping >>> around in the code to one that doesn't. It's a totally different mind >>> set. >> 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