Send operator: proof of concept implementation

Put together a proof of concept of Gary W.'s idea of using an
operator for send instead of a method. This also incorporates an
implementation of Ara’s Pervasives. There are a couple caveats to this
implementation however that would have to be handled in any production
version.

  1. It uses >> rather then ->, for obvious reasons. So as it is, it will
    not work with a few classes that already use >> (unless they are
    redefined).

  2. You have to pass an array, since an operator normally can’t handle
    more that one arg. This also means unfortunately that blocks can’t be
    passed.

  3. It doesn’t provide a “pervasive send” operator.

Usage:

send equivalent to ‘.’

obj >> [:method, *args]

send as (binds to method in parent class/module)

obj >> [Ancestor, :method, *args]

The second form can also be used to bypass privacy.

obj >> [(obj>>:class), :method, *args]

Albeit this will bypass singletons (aside from this it would be nice to
have method that returns the singleton if it exists, but the regular
class otherwise).


module Kernel

module Pervasives
METHODS = {}
Kernel.instance_methods.each do |m|
METHODS[m] = Kernel.instance_method(m)
end
METHODS.each do |s,m|
define_method s do |o,*a|
m.bind(o).call(*a)
end
module_function s
end
end
Pervasives.freeze(Pervasives)

def >>(a)
a = [a].flatten
case a[0] when Module, Class
c, m, *a = *a
c.instance_method(m).bind(self).call(*a)
else
if respond_to?(a[0])
Pervasives.send(self,*a)
elsif respond_to?(:method_missing)
method_missing(*a)
else
raise NoMethodError, “private method called for #{self}”
end

end

end

end

#=begin test

require ‘test/unit’

class TestSendOP < Test::Unit::TestCase

class C
  def a; "c"; end
end

class X < C
  def send; "send"; end
  def a; "a"; end
  private
  def b; "b"; end
end

def setup
  @x = X.new
end

def test_send
  assert_equal( "send", @x.send )
end

def test_normal
  assert_equal( "a", @x >> [:a] )
end

def test_as_C
  assert_equal( "c", @x >> [C,:a] )
end

def test_singleton
  assert_equal( "a", @x >> [(class<<@x;self;end),:a] )
end

def test_singleton_bypass_private
  assert_equal( "b", @x >> [(class<<@x;self;end),:b] )
end

def test_private
  assert_raises(NoMethodError){ @x >> [:b] }
end

end

#=end

On Jan 6, 2007, at 4:12 PM, Trans wrote:

Put together a proof of concept of Gary W.'s idea of using an
operator for send instead of a method. This also incorporates an
implementation of Ara’s Pervasives. There are a couple caveats to this
implementation however that would have to be handled in any production
version.

Interesting. Just to clarify: If my idea is worth anything it can’t
really be implemented via a redefine-able operator. That would just
change
the area of concern from #send being redefined to #operator being
redefined.
I realize that Trans is basically just experimenting with syntax at this
point.

  1. It uses >> rather then ->, for obvious reasons. So as it is, it
    will
    not work with a few classes that already use >> (unless they are
    redefined).

Well, I would still argue that << would be better than >> for mnemonic
reasons but I understand that a lot more classes have << already
defined.

  1. It doesn’t provide a “pervasive send” operator.

Well, as long as folks aren’t redefining methods in BasicObject you
almost
have a “pervasive send” operator:

obj >> [BasicObject, :object_id]

I think there is a strong argument to be made that BasicObject should be
frozen. You can override methods there via inheritance but I don’t
think
BasicObject itself should be modified.

Gary W.

On 1/7/07, [email protected] [email protected] wrote:

change
Well, I would still argue that << would be better than >> for mnemonic
reasons but I understand that a lot more classes have << already
defined.

Yeah, if we were to go the arrow route, you’d probably want

obj ← message and want ← to be something you can’t override.