On Sunday 08 November 2009 03:44:15 pm David A. Black wrote:
> On Mon, 9 Nov 2009, David Masover wrote:

> > I can see why rcr147 was rejected, but it's not entirely without
> > precedent -- see .profile for sh and bash.
> >
> > And rcr169, I actually like. What if the exception was raised deep in
> > another method, but it's something you can handle? Also not without
> > precedent, as Lisp has these.
>
> True, but the business of precedents from other languages sort of
> cancels itself out, since it encompasses literally tens or hundreds of
> thousands of features, large and small.

My point wasn't that it had _ever_ been done, but that it had been done well, 
and had been found to be useful. For example, while I could simply include a 
list of environment variables somewhere, or tweak the bash commandline from 
/etc/passwd, it's much more convenient to be able to use actual shell logic in 
/etc/profile and .profile to set those variables.

Yes, it _can_ screw things up, if misused. I don't think that's a reason not 
to do it.

Similarly, Lisp restarts, when I read gigamonkeys.com/book, seemed to be 
really useful and something I'd miss in Ruby. In the book's example, he's got 
a log parser, with two restarts: parse-log-entry and skip-log-entry. That is, 
you could do something roughly equivalent to this:

begin
  logfile = LogParser.parse('/some/file')
rescue LogParser::MalformedEntry
  entry = $!.text
  if entry =~ /some_regex/
    restart :reparse, entry.gsub(/some/, 'substitution')
  else
    restart :skip
  end
end

I'm not attached to that syntax (actually, the 'restart' in particular looks 
cumbersome), but the point is that this is much more flexible than something 
like this:

LogParser.parse('/some/file', :skip_malformed => true, :fix_bad_entry => proc{|
x| x.gsub(/some/, 'substitution')})

First, that's not quite equivalent (and it's a little ugly). Second, it's much 
nicer to be able to actually separate the error handling logic.

And finally, one of the main points of exceptions -- to me, at least -- is that 
you don't need to have specific error-handling logic within each method that 
might throw an error. (This is something Java gets horribly wrong, by the way 
-- having to manually specify "throws" almost defeats the purpose.) It means 
the error _will_ be handled, even if it's somewhere much farther up the call 
stack, even if "handling" means aborting the program rather than letting an 
error be silently ignored.

So, it makes sense that if the error actually can be corrected up the call 
stack, it should be. For example:

def foo
  ...
  LogParser.parse ...
  ...
end

begin
  foo
rescue LogParser::MalformedEntry
  ...
end

The closest thing we currently have is "retry", which re-runs the entire 
block. Obviously, this isn't a good idea if we're halfway through a multi-
gigabyte log, and it doesn't help us actually correct the error.

Am I missing something obvious? Maybe a design pattern which avoids this, or 
maybe a way to implement the equivalent without changing Ruby itself?

> I think the BasicObject concept (unlike the putting-class-names-in-
> method-signatures concept) was bubbling under the surface for a long
> time... It wasn't a case of
> something fundamentally out of character for the language. Not all RCR
> rejection is created equal :-) (And part of that, too, is of course
> that Matz can change his mind over time.)

That was the impression I got there. I was pointing it out partly just to make 
sure I wasn't crazy, and that this was indeed a rejected BasicObject idea.