Comment on this RCR (edit wiki page) | RCRchive home

RCR 210: event keyword for ruby

submitted by sanatg on Sun Feb 08 2004 10:19:50 PM -0800

Status: withdrawn


Abstract

Ruby currently lacks an event keyword. It is possible to implement event handlers by defining method pointers and attaching blocks at runtime. However, an event keyword would reduce the typing required when defining events.

Problem

The following code block implements an Authenticator class with 2 events - on_authenticate and on_failure. The Consumer class attaches method blocks to these event handlers at runtime.
class Authenticator
        #event
        def on_authenticate(&on_authenticate)
                @on_authenticate = on_authenticate
        end

        #event
        def on_failure(&on_failure)
                @on_failure = on_failure
        end

        #constructor
        def initialize
                on_authenticate {}
                on_failure {}
        end
        
        def authenticate(username, password)
                if username == 'john' and password == 'doe'
                        @on_authenticate.call
                else
                        @on_failure.call
                end     
        end
end

class Consumer
        #event handler
        def on_authenticate
                puts 'Successfully authenticated'
        end
        
        def on_failure
                puts 'Authentication failed'
        end
        
        def run
                auth = Authenticator.new
                
                #attach event handlers
                auth.on_authenticate {on_authenticate}
                auth.on_failure {on_failure}
                
                auth.authenticate('john', 'doe') #succeeds
                auth.authenticate('jim', 'smith') #fails
        end
end

Consumer.new.run
The definition of Authenticator above requires defining 2 attributes that point to a method and initializing those attributes with empty blocks.

Proposal

An event keyword with some of the plumbing handled by the runtime would solve this problem. For example, the above code for Authenticator would look something like -
class Authenticator
        #events
        event on_authenticate, on_failure

        def authenticate(username, password)
                if username == 'john' and password == 'doe'
                        @on_authenticate.call
                else
                        @on_failure.call
                end     
        end
end

Analysis

The addition of the event keyword would eliminate the need to define method pointers and assigning them to attributes. This would be handled by the Ruby runtime. Also the need to assign empty blocks in the constructor would not be required, so attaching an event handler in the consuming class is not mandatory.

Vote for this RCR

Strongly opposed [4]
Opposed [0]
Neutral [0]
In favor [0]
Strongly advocate [0]

Change the status of this RCR to:

accepted

rejected

withdrawn


I don't really understand what "event" keyword does. Can you explain more in detail for me to decide? Besides, from your example in the proposal, "event" seems more like a method like "attr_reader" rather than a keyword.

-- matz.


The "event" keyword would let the programmer avoid having to write the following:

1. The on_authenticate method (supplying the block pointer as a parameter)

2. having to initialize the attribute @on_authenticate to an empty block in the initialize method

1 (above) is necessary so that the consuming class can attach a block to @on_authenticate at runtime

2 (above) is necessary so that attaching a block at runtime is optional for the consuming class

The "event" keyword could let the runtime do 1 and 2 behind the scenes.

--sanatg


One could write this as an extension. I think it's too specialized to make sense as a language feature. -- DavidBlack


Just a tiny bit of metaprogramming...

class Class
  def event(*events)
    events.each do |e|
      class_eval <<-EOF
      def on_#{e}(&block)
        @on_#{e} = block
      end
      EOF
    end
  end
end
class Foo
  event :bar
  def foo
    @on_bar.call if @on_bar
  end
end
a = Foo.new a.on_bar { puts "callback" } a.foo

You can also initialize the @on_xxx instance variables by redefining Foo.new.

MauricioFernandez


The above code looks good. Thanks. Will withdraw this RCR :-)

--sanatg

Add comments here


Back to RCRchive.


RCR Submission page and RCRchive powered by Ruby, Apache, RuWiki (modified), and RubLog