Forum: Ruby Common Lisp conditions

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Gavin S. (Guest)
on 2009-02-23 16:00
(Received via mailing list)
Hi,

So far as the search engine on this newsgroup is concerned, there's
been no discussion about including a Common Lisp-style condition
system in a future version of Ruby.  For information about these, [1]
is a good readable resource.

For those who don't know what they offer above normal exception-
handling (as we know it in Ruby, Java, C++, ...), conditions need not
be errors and they need not unwind the stack.  A low-level function
can signal that something is wrong, and provide multiple ways of
handling it (which is appropriate, because the handling code is low-
level).  A high-level function can receive the signal and choose which
low-level handler to run, or can "handle" it itself or ignore it (the
latter two options being what's available in Ruby etc.).  Another good
example is low-level code issuing a warning and higher-level code
deciding whether to print it.  It's _very_ elegant.

For those who _do_ know about Common Lisp conditions, is there any
appetite for them in Ruby?  I see great positives and no negatives.
They don't seem at all un-Ruby-like; in fact the relationship between
high- and low-level code reminds me of the elegance of blocks and
yield.

After a small amount of thought, I haven't come up with a suitable
syntax.  That's probably because I haven't used the things, only read
about them.

Just curious about people's thoughts, and quietly hopeful for Ruby
2.0 :)

Gavin

[1]
http://gigamonkeys.com/book/beyond-exception-handl...
Jörg W Mittag (Guest)
on 2009-02-25 22:23
(Received via mailing list)
Gavin S. wrote:
> So far as the search engine on this newsgroup is concerned, there's
> been no discussion about including a Common Lisp-style condition
> system in a future version of Ruby.
[...]
> For those who _do_ know about Common Lisp conditions, is there any
> appetite for them in Ruby?  I see great positives and no negatives.
> They don't seem at all un-Ruby-like; in fact the relationship between
> high- and low-level code reminds me of the elegance of blocks and
> yield.

They seem to work very well in Ola B.'s new language Ioke
(<http://Ioke.Org/>), which borrows heavily from Ruby. So, I agree:
they would fit very well. Replacing Exceptions with Conditions could
probably even be done in a (somewhat) backwards-compatible way. Maybe
they could replace throw/catch, too.

> After a small amount of thought, I haven't come up with a suitable
> syntax.  That's probably because I haven't used the things, only read
> about them.

I just tried converting the example from Practical Common Lisp, but it
isn't too pretty. I hope that's because I mis-translated the original
procedural Common Lisp into pseudo-OO Ruby and not because my chosen
syntax is ugly.

    class MalformedLogEntryError < RuntimeError
      def initialize text
        @text = text
      end
      attr_reader :text
    end

    class LogEntryParser
      def parse_log_entry text
        error MalformedLogEntryError.new(text) unless
text.wellformed_log_entry?
        LogEntry.new( ... )
      restart use_value(value)
        value
      restart reparse_entry(fixed_text)
        parse_log_entry fixed_text
      end
    end

    class LogfileParser
      def parse_log_file file
        File.each_line(file).map do |line|
          begin
            @log_entry_parser.parse_log_entry text
          restart skip_log_entry
            nil
          end
        end
      end
    end

    class LogAnalyzer
      def main
        find_all_logs.each do |log|
          analyze_log log
        end
      handle MalformedLogEntryError
        restart skip_log_entry
      end

      def analyze_log log
        @logfile_parser.parse_log_file(log).each do |entry|
          analyze_entry entry
        end
      end
    end

    class StrictLogAnalyzer # Annotates malformed entries instead of
ignoring
      def main
        super
      handle MalformedLogEntryError => c
        MalformedLogEntry.new(c.text)
      end
    end

jwm
Jörg W Mittag (Guest)
on 2009-02-26 00:20
(Received via mailing list)
Gavin S. wrote:
> So far as the search engine on this newsgroup is concerned, there's
> been no discussion about including a Common Lisp-style condition
> system in a future version of Ruby.
[...]
> For those who _do_ know about Common Lisp conditions, is there any
> appetite for them in Ruby?  I see great positives and no negatives.
> They don't seem at all un-Ruby-like; in fact the relationship between
> high- and low-level code reminds me of the elegance of blocks and
> yield.

They seem to work very well in Ola B.'s new language Ioke
(<http://Ioke.Org/>), which borrows heavily from Ruby. So, I agree:
they would fit very well. Replacing Exceptions with Conditions could
probably even be done in a (somewhat) backwards-compatible way. Maybe
they could replace throw/catch, too.

> After a small amount of thought, I haven't come up with a suitable
> syntax.  That's probably because I haven't used the things, only read
> about them.

[Supersede: my original article had an example translation of the code
example from the book Practical Common Lisp, but my translation was,
for lack of a better word, bullshit. So I deleted it.]

jwm
Christopher D. (Guest)
on 2009-02-26 23:05
(Received via mailing list)
On 2/23/09, Gavin S. <removed_email_address@domain.invalid> wrote:
> can signal that something is wrong, and provide multiple ways of
> high- and low-level code reminds me of the elegance of blocks and
>
> [1]
> http://gigamonkeys.com/book/beyond-exception-handl...
>
>

Exceptions don't need to be errors in Ruby, though conventionally they
are used for that and throw/catch for similar non-errors. As far as
the additional functionality of conditions, its not that hard to
implement at least what I see as the most important one (restarts) on
top of Ruby's existing exception-handling using continuations, e.g.,
in Ruby 1.8 (and, I would presume, Ruby 1.9 with the addition of
"require 'continuation'" at the top:

# This code is untested on any but the demo case at the end.

class Condition < Exception

  FAIL = Object.new

  def self.alert(*args)
    block = (block_given? ? lambda { |c| yield c } : nil)
    callcc { |cont| raise self.new(cont, block, *args) }
  end

  def initialize(c, block, *args)
    @continuation = c
    @restarts = {}
    block.call(self) if block
  end

  def add_restart(restart_name, &block)
    @restarts[restart_name] = lambda do |*args|
      result=block.call(self, *args)
      @continuation.call(*result) unless result==FAIL
      nil
    end
    self
  end

  def restarts
    @restarts.dup
  end

  def restart(restart_name, *args)
    @restarts[restart_name].call(*args) if @restarts.include?
restart_name
  end
end

class BadValueCondition < Condition
  attr_reader :value

  def initialize(c, block, val, *args)
    @value = val
    super
  end
end

def process_value(val)
  if (val.div 2) == (val.quo 2)
    BadValueCondition.alert(val)
  else
    val.to_s
  end
end

def process(range)
  range.map { |val| process_value(val) }.compact
rescue BadValueCondition => c
  c.add_restart(:ignore) {}
  c.add_restart(:substitute_warning) { |c, *args| "Bad: #{c.value}" }
  raise
end


[:ignore, :substitute_warning].each do |strategy|
  begin
    puts "\n---\nDemonstrating restart #{strategy.inspect}"
    arr = process(1..10)
    puts arr.join("\n")
  rescue BadValueCondition => c
    c.restart(strategy)
    raise
  end
end
GS (Guest)
on 2009-02-27 23:28
(Received via mailing list)
On Feb 27, 8:03 am, Christopher D. <removed_email_address@domain.invalid> wrote:
>
> Exceptions don't need to be errors in Ruby, though conventionally they
> are used for that and throw/catch for similar non-errors. As far as
> the additional functionality of conditions, its not that hard to
> implement at least what I see as the most important one (restarts) on
> top of Ruby's existing exception-handling using continuations, e.g.,
> in Ruby 1.8 (and, I would presume, Ruby 1.9 with the addition of
> "require 'continuation'" at the top:
>
>    [code snipped]

That's very impressive and interesting, Christopher.  Thanks!

Gavin
This topic is locked and can not be replied to.