Ruby Forum Ruby > Matz: can we have rescue/else/ensure available in all blocks?

Posted by coderrr (Guest)
on 16.05.2008 00:03
(Received via mailing list)
Hi Matz,

I recently posted a Ruby 1.9 wishlist (http://groups.google.com/group/
ruby-talk-google/browse_thread/thread/d771ffa9fe10b811/
c8b5b0b02bd1e2d4) and the #1 item was to have rescue/else/ensure
available in all blocks w/o the need for begin/end.  It turned out to
be the one thing that everyone agreed on.  I think anyone who has done
a real project in Ruby has run into this.

Is there any way you can get this in 1.9?

This (contrived example):

pages.each do |page|
  page.links.each do |link|
    process link
  rescue MalformedLinkError
    @bad_links << link
  end
rescue MalformedPageError
  @bad_pages << page
end

Is so much nicer than this:

pages.each do |page|
  begin
    page.links.each do |link|
      begin
        process link
      rescue MalformedLinkError
        @bad_links << link
      end
    end
  rescue MalformedPageError
    @bad_pages << page
  end
end

It would make all our lives better!  :]

- steve
http://coderrr.wordpress.com
Posted by Yukihiro Matsumoto (Guest)
on 16.05.2008 01:18
(Received via mailing list)
Hi,

In message "Re: Matz: can we have rescue/else/ensure available in all 
blocks?"
    on Fri, 16 May 2008 07:02:47 +0900, coderrr 
<coderrr.contact@gmail.com> writes:

|This (contrived example):
|
|pages.each do |page|
|  page.links.each do |link|
|    process link
|  rescue MalformedLinkError
|    @bad_links << link
|  end
|rescue MalformedPageError
|  @bad_pages << page
|end

can be considered as

  pages.each do |page|
    begin
      page.links.each do |link|
        begin
          process link
        rescue MalformedLinkError
          @bad_links << link
        end
      end
    rescue MalformedPageError
      @bad_pages << page
    end
  end

and

  begin
    pages.each do |page|
      begin
        page.links.each do |link|
          process link
        end
      rescue MalformedLinkError
        @bad_links << link
      end
    end
  rescue MalformedPageError
    @bad_pages << page
  end

If it contains ensure, things are more complicated.  Perhaps you would
expect

   foo do
      break
   ensure
      puts "foo"
   end

would print "foo" even when foo does not give control to the block.


              matz.
Posted by coderrr (Guest)
on 16.05.2008 02:03
(Received via mailing list)
Hey Matz,

Thanks a lot for the quick reply.

I agree it is possible that someone who doesn't know the syntax could
potentially misinterpret these things.  I think though, that this should 
be
weighed against the benefit of adding it to the language.  I assume it's
your judgment that the cost outweighs the benefit on this?  I of course
think the opposite :)

I wonder what other developers think about how easily confused these 
would
be, and about how that weighs against the benefits?

The benefits are more concise syntax (which is the thing I love most 
about
ruby), removing 2 lines and an indentation for a lot of rescue 
statements

Also, I would be happy if only the ability to rescue were added to all
blocks but begin/end were required for else/ensure since they are less
commonly used.

- steve
http://coderrr.wordpress.com
Posted by Peter Jones (Guest)
on 16.05.2008 03:31
(Received via mailing list)
coderrr <coderrr.contact@gmail.com> writes:
>     @bad_pages << page
>   end
> end

If you write code that looks like that, maybe you should give Java a
second look ;)

Seriously though, you could easily restructure your code to be a bit
more OO and then you wouldn't have to worry about rescuing exceptions
all over the place, including several times in nested loops.
Posted by coderrr (Guest)
on 16.05.2008 04:53
(Received via mailing list)
>
> If you write code that looks like that, maybe you should give Java a
> second look ;)
>
> Seriously though, you could easily restructure your code to be a bit
> more OO and then you wouldn't have to worry about rescuing exceptions
> all over the place, including several times in nested loops.
>

It was a contrived example.  So would that be a "not in favor of" from 
you
Peter?

- steve
http://coderrr.wordpress.com
Posted by Michael Neumann (Guest)
on 16.05.2008 12:11
(Received via mailing list)
coderrr wrote:
 >> If you write code that looks like that, maybe you should give Java a
 >> second look ;)
 >>
 >> Seriously though, you could easily restructure your code to be a bit
 >> more OO and then you wouldn't have to worry about rescuing 
exceptions
 >> all over the place, including several times in nested loops.
 >>
 >
 > It was a contrived example.  So would that be a "not in favor of"
from you
 > Peter?

How would you have "rescue" and "ensure" blocks when using "{" and "}",
both of which are (almost) equivalent to "do" and "end"?

   pages.each {|page|
      ...
   }

Regards,

   Michael
Posted by Peter Jones (Guest)
on 16.05.2008 16:46
(Received via mailing list)
coderrr <coderrr.contact@gmail.com> writes:
> It was a contrived example.  So would that be a "not in favor of" from you
> Peter?

I'm certainly not convinced.  Maybe you could post a more real world
example because I'm having a hard time seeing the usefulness in nested
rescues.
Posted by coderrr (Guest)
on 17.05.2008 01:32
(Received via mailing list)
> How would you have "rescue" and "ensure" blocks when using "{" and "}",
> both of which are (almost) equivalent to "do" and "end"?
>
>  pages.each {|page|
>     ...
>  }
>
>
pages.each { |page|
rescue SomeError
...
ensure
...
}

Or you could just not allow it for { }, only for do/end.  I agree it 
looks
weird, and is probably more confusing when using it with { }.

- steve
http://coderrr.wordpress.com
Posted by coderrr (Guest)
on 17.05.2008 02:05
(Received via mailing list)
> I'm certainly not convinced.  Maybe you could post a more real world
> example because I'm having a hard time seeing the usefulness in nested
> rescues.
>
>
This has nothing to do with nested rescues.  I merely used that in the
example to make it more compelling, although I guess for you it did the
opposite :P

Here's how you can get some real world examples:
cat > findem.rb <<EOF
ARGV.each do |fn|
  data = File.read(fn)
  ms = data.scan(%r{
            do \s* (?:\| [^|]* \|)+ \s*
                begin
                  (?:(?!end).)+?
                end \s*
            end
             }mx)

  if ! ms.empty?
    puts fn
    ms.each{|m| puts m }
  end
end
EOF

find /usr/lib/ruby/gems/1.8/gems -name "*.rb" | xargs ruby findem.rb >
the_real_world

for me:
grep \\.rb the_real_world | wc -l
=> 43

- steve
http://coderrr.wordpress.com
Posted by coderrr (Guest)
on 17.05.2008 02:10
(Received via mailing list)
>             do \s* (?:\| [^|]* \|)+ \s*


sorry, this line should read:

 do \s* (?:\| [^|]* \|)? \s*

after that, I get 67 results instead of 43

- steve
http://coderrr.wordpress.com
Posted by Peter Jones (Guest)
on 17.05.2008 03:41
(Received via mailing list)
coderrr <coderrr.contact@gmail.com> writes:
> find /usr/lib/ruby/gems/1.8/gems -name "*.rb" | xargs ruby findem.rb >
> the_real_world

Ah, now I know why.  I ran this on ~/ and it only showed lines in a
few gems that I happened to have lying around, but nothing in my code.

I guess it's just not an idiom that I use.  That might be because my
background, I tend to use exceptions most often for situations that
can't be recovered from.

I'm not suggesting that you do, but I know a lot of people use
exceptions as high-level flow control, which I find disturbing.

Thanks for the code searcher.
Posted by coderrr (Guest)
on 17.05.2008 07:46
(Received via mailing list)
btw, that script _will_ give some false positives when there are other
blocks/ifs/whiles inside the block in question but for me those made
up less than 5% of the results

- steve
http://coderrr.wordpress.com