Forum: Ruby-core [Ruby 1.9 - Feature #5394][Open] Anonymous Symbols, Anonymous Methods

Posted by Kurt Stephens (Guest)
on 2011-10-03 21:11
(Received via mailing list)
Issue #5394 has been reported by Kurt  Stephens.

----------------------------------------
Feature #5394: Anonymous Symbols, Anonymous Methods
http://redmine.ruby-lang.org/issues/5394

Author: Kurt  Stephens
Status: Open
Priority: Normal
Assignee:
Category:
Target version:


Proposal for Anonymous Symbols and Anonymous Methods

Anonymous Methods (AnonMeths) can be used for complex orthogonal 
behaviors that dispatch by receiver class without patching core or other 
sensitive classes in a globally visible manner.
AnonMeths are located by Anonymous Symbols (AnonSyms).
AnonSyms do not have parseable names, and can only be referenced by 
value, limiting namespace problems and promoting encapsulation.
AnonMeths are GCed once the AnonSym bound to them are GCed.
AnonMeths would not appear in Object#methods, thus will not confuse 
introspection.

Assume:

<pre><code class="ruby">
  Symbol.new() => #<Symbol:123412> # an AnonSymbol than can never be 
parsed in ruby code.
  anon_sym = Symbol.new() # an AnonSym in a variable that can be 
closed-over or passed by value.
</code></pre>

Optional Supporting Syntax:

<pre><code class="ruby">
  a.*anon_sym(args...) # equiv. to a.send(anon_sym, args...)
  class A
    def *anon_sym(args...); body...; end
  end
</code></pre>

equiv. to:

<pre><code class="ruby">
  class A
    define_method(anon_sym) {| args... | body... }
  end
</code></pre>

AnonSyms are not added directly to a Module's internal symbol-to-method 
table.
Instead, each AnonSym has an internal module-to-method table that is 
GCed when the AnonSym is GCed.

<pre><code class="ruby">
  rcvr.send(anon_sym, ...)
</code></pre>

will use anon_sym's module-to-method table to locate a method based on 
usual the receiver's module lookup chain.

Example Application:

Typical visitor pattern that pollutes Array and Object method 
namespaces:

<pre><code class="ruby">
  class Array;  def visit(visitor); each { | elem | elem.visit(visitor); 
} end; end
  class Object; def visit(visitor); visitor.something(self); 
end; end
</code></pre>

Functional alternative using "case ...; when ...":

<pre><code class="ruby">
  def visit(obj, visitor)
    case obj
    when Array
      obj.each { | elem | visit(elem, visitor) }
    else
      visitor.something(obj)
    end
  end
</code></pre>

AnonMeth version:

<pre><code class="ruby">
  def visit(obj, visitor)
    sel = Symbol.new
    class Array;   def *sel(visitor); each { | elem | elem.*sel(visitor) 
}; end; end
    class Object;  def *sel(visitor); visitor.something(self); 
end; end
    obj.*sel(visitor)
  end
</code></pre>

Imagine that visit() needs dynamic hooks to visit different types:

<pre><code class="ruby">
  def visit(obj, visitor)
    sel = Symbol.new
    class Array;   def *sel(visitor); each { | elem | elem.*sel(visitor) 
}; end; end
    class Object;  def *sel(visitor); visitor.something(self); 
end; end
    add_visit_methods!(sel)
    obj.*sel(visitor)
  end
  def add_visit_methods!(sel)
    class Hash;    def *sel(visitor); each { | k, v | v.*sel(visitor); 
end; end
    ...
  end
</code></pre>

The AnonSym send "rcvr.*sel(...)" dispatches, like a normal method send, 
directly to the appropriate AnonMeth for "*sel".
visit() can be extended dynamically by adding more AnonMeths bound to 
"*sel".
The functional "case ...; when..." version is difficult to extend and 
maintain and is likely to not perform as well as anon messages.
This is similar in style to Scheme letrecs, but is object-oriented.

This idea could be extended to Anonymous Ivars to resolve other 
namespacing and encapsulation issues for mixins that require state.

-- Kurt Stephens
Posted by Gary Wright (Guest)
on 2011-10-03 22:27
(Received via mailing list)
On Oct 3, 2011, at 3:11 PM, Kurt Stephens wrote:
>
> Optional Supporting Syntax:
>
> <pre><code class="ruby">
> a.*anon_sym(args...) # equiv. to a.send(anon_sym, args...)
> class A
>   def *anon_sym(args...); body...; end
> end
> </code></pre>


I'm not sure about the anonymous symbols but you might want to take a 
look at this discussion:

<http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/...

regarding using strings/expressions to invoke methods without the use of 
send().

Gary Wright
Posted by Kurt Stephens (Guest)
on 2011-10-04 03:32
(Received via mailing list)
Issue #5394 has been updated by Kurt  Stephens.


Related: http://redmine.ruby-lang.org/issues/show/4288
----------------------------------------
Feature #5394: Anonymous Symbols, Anonymous Methods
http://redmine.ruby-lang.org/issues/5394

Author: Kurt  Stephens
Status: Open
Priority: Normal
Assignee:
Category:
Target version:


Proposal for Anonymous Symbols and Anonymous Methods

Anonymous Methods (AnonMeths) can be used for complex orthogonal 
behaviors that dispatch by receiver class without patching core or other 
sensitive classes in a globally visible manner.
AnonMeths are located by Anonymous Symbols (AnonSyms).
AnonSyms do not have parseable names, and can only be referenced by 
value, limiting namespace problems and promoting encapsulation.
AnonMeths are GCed once the AnonSym bound to them are GCed.
AnonMeths would not appear in Object#methods, thus will not confuse 
introspection.

Assume:

<pre><code class="ruby">
  Symbol.new() => #<Symbol:123412> # an AnonSymbol than can never be 
parsed in ruby code.
  anon_sym = Symbol.new() # an AnonSym in a variable that can be 
closed-over or passed by value.
</code></pre>

Optional Supporting Syntax:

<pre><code class="ruby">
  a.*anon_sym(args...) # equiv. to a.send(anon_sym, args...)
  class A
    def *anon_sym(args...); body...; end
  end
</code></pre>

equiv. to:

<pre><code class="ruby">
  class A
    define_method(anon_sym) {| args... | body... }
  end
</code></pre>

AnonSyms are not added directly to a Module's internal symbol-to-method 
table.
Instead, each AnonSym has an internal module-to-method table that is 
GCed when the AnonSym is GCed.

<pre><code class="ruby">
  rcvr.send(anon_sym, ...)
</code></pre>

will use anon_sym's module-to-method table to locate a method based on 
usual the receiver's module lookup chain.

Example Application:

Typical visitor pattern that pollutes Array and Object method 
namespaces:

<pre><code class="ruby">
  class Array;  def visit(visitor); each { | elem | elem.visit(visitor); 
} end; end
  class Object; def visit(visitor); visitor.something(self); 
end; end
</code></pre>

Functional alternative using "case ...; when ...":

<pre><code class="ruby">
  def visit(obj, visitor)
    case obj
    when Array
      obj.each { | elem | visit(elem, visitor) }
    else
      visitor.something(obj)
    end
  end
</code></pre>

AnonMeth version:

<pre><code class="ruby">
  def visit(obj, visitor)
    sel = Symbol.new
    class Array;   def *sel(visitor); each { | elem | elem.*sel(visitor) 
}; end; end
    class Object;  def *sel(visitor); visitor.something(self); 
end; end
    obj.*sel(visitor)
  end
</code></pre>

Imagine that visit() needs dynamic hooks to visit different types:

<pre><code class="ruby">
  def visit(obj, visitor)
    sel = Symbol.new
    class Array;   def *sel(visitor); each { | elem | elem.*sel(visitor) 
}; end; end
    class Object;  def *sel(visitor); visitor.something(self); 
end; end
    add_visit_methods!(sel)
    obj.*sel(visitor)
  end
  def add_visit_methods!(sel)
    class Hash;    def *sel(visitor); each { | k, v | v.*sel(visitor); 
end; end
    ...
  end
</code></pre>

The AnonSym send "rcvr.*sel(...)" dispatches, like a normal method send, 
directly to the appropriate AnonMeth for "*sel".
visit() can be extended dynamically by adding more AnonMeths bound to 
"*sel".
The functional "case ...; when..." version is difficult to extend and 
maintain and is likely to not perform as well as anon messages.
This is similar in style to Scheme letrecs, but is object-oriented.

This idea could be extended to Anonymous Ivars to resolve other 
namespacing and encapsulation issues for mixins that require state.

-- Kurt Stephens
Posted by Yusuke Endoh (Guest)
on 2011-10-04 12:54
(Received via mailing list)
Hello,

To all:
This proposal aims to address pollution and collision problem of name
space, as well as refinement.  But the approach is different.
Though the explanation is not so catchy :-), language designers may
want to check it out.


To Kurt:
I recommend you to clarify the advantages and disadvantages between
your proposal and the traditional ones (like refinement and classbox).

I have some points.  Because class statement changes the scope of local
variables, the following code will not work:

  anon_sym = Symbol.new()
  class A
    def *anon_sym(args...); body...; end
  end

And, the syntax "a.*anon_sym" collides against the call to method *

  x, y = 3, 2
  p(x.*y)  #=> 6

The letter is not essential problem, but the former is not negligible.



#4288 aims to provide chemistry with other languages and the discussion
focuses on "syntax game", so it is better to distinguish between them.
Posted by Nobuyoshi Nakada (nobu)
on 2011-10-04 18:48
(Received via mailing list)
Hi,

(11/10/04 4:11), Kurt Stephens wrote:
>   def add_visit_methods!(sel)
>     class Hash;    def *sel(visitor); each { | k, v | v.*sel(visitor);      end; 
end
>     ...
>   end
> </code></pre>
>
> The AnonSym send "rcvr.*sel(...)" dispatches, like a normal method send, 
directly to the appropriate AnonMeth for "*sel".
> visit() can be extended dynamically by adding more AnonMeths bound to "*sel".
> The functional "case ...; when..." version is difficult to extend and maintain 
and is likely to not perform as well as anon messages.
> This is similar in style to Scheme letrecs, but is object-oriented.

Is this double dispatching system your true goal?  If so, anonymous
symbol doesn't seem the only way nor the best way, for me.
Posted by mame (Yusuke Endoh) (Guest)
on 2012-03-26 20:34
(Received via mailing list)
Issue #5394 has been updated by mame (Yusuke Endoh).

Status changed from Open to Feedback


----------------------------------------
Feature #5394: Anonymous Symbols, Anonymous Methods
https://bugs.ruby-lang.org/issues/5394#change-25223

Author: kstephens (Kurt  Stephens)
Status: Feedback
Priority: Normal
Assignee:
Category:
Target version:


Proposal for Anonymous Symbols and Anonymous Methods

Anonymous Methods (AnonMeths) can be used for complex orthogonal 
behaviors that dispatch by receiver class without patching core or other 
sensitive classes in a globally visible manner.
AnonMeths are located by Anonymous Symbols (AnonSyms).
AnonSyms do not have parseable names, and can only be referenced by 
value, limiting namespace problems and promoting encapsulation.
AnonMeths are GCed once the AnonSym bound to them are GCed.
AnonMeths would not appear in Object#methods, thus will not confuse 
introspection.

Assume:

<pre><code class="ruby">
  Symbol.new() => #<Symbol:123412> # an AnonSymbol than can never be 
parsed in ruby code.
  anon_sym = Symbol.new() # an AnonSym in a variable that can be 
closed-over or passed by value.
</code></pre>

Optional Supporting Syntax:

<pre><code class="ruby">
  a.*anon_sym(args...) # equiv. to a.send(anon_sym, args...)
  class A
    def *anon_sym(args...); body...; end
  end
</code></pre>

equiv. to:

<pre><code class="ruby">
  class A
    define_method(anon_sym) {| args... | body... }
  end
</code></pre>

AnonSyms are not added directly to a Module's internal symbol-to-method 
table.
Instead, each AnonSym has an internal module-to-method table that is 
GCed when the AnonSym is GCed.

<pre><code class="ruby">
  rcvr.send(anon_sym, ...)
</code></pre>

will use anon_sym's module-to-method table to locate a method based on 
usual the receiver's module lookup chain.

Example Application:

Typical visitor pattern that pollutes Array and Object method 
namespaces:

<pre><code class="ruby">
  class Array;  def visit(visitor); each { | elem | elem.visit(visitor); 
} end; end
  class Object; def visit(visitor); visitor.something(self); 
end; end
</code></pre>

Functional alternative using "case ...; when ...":

<pre><code class="ruby">
  def visit(obj, visitor)
    case obj
    when Array
      obj.each { | elem | visit(elem, visitor) }
    else
      visitor.something(obj)
    end
  end
</code></pre>

AnonMeth version:

<pre><code class="ruby">
  def visit(obj, visitor)
    sel = Symbol.new
    class Array;   def *sel(visitor); each { | elem | elem.*sel(visitor) 
}; end; end
    class Object;  def *sel(visitor); visitor.something(self); 
end; end
    obj.*sel(visitor)
  end
</code></pre>

Imagine that visit() needs dynamic hooks to visit different types:

<pre><code class="ruby">
  def visit(obj, visitor)
    sel = Symbol.new
    class Array;   def *sel(visitor); each { | elem | elem.*sel(visitor) 
}; end; end
    class Object;  def *sel(visitor); visitor.something(self); 
end; end
    add_visit_methods!(sel)
    obj.*sel(visitor)
  end
  def add_visit_methods!(sel)
    class Hash;    def *sel(visitor); each { | k, v | v.*sel(visitor); 
end; end
    ...
  end
</code></pre>

The AnonSym send "rcvr.*sel(...)" dispatches, like a normal method send, 
directly to the appropriate AnonMeth for "*sel".
visit() can be extended dynamically by adding more AnonMeths bound to 
"*sel".
The functional "case ...; when..." version is difficult to extend and 
maintain and is likely to not perform as well as anon messages.
This is similar in style to Scheme letrecs, but is object-oriented.

This idea could be extended to Anonymous Ivars to resolve other 
namespacing and encapsulation issues for mixins that require state.

-- Kurt Stephens
Posted by alexeymuranov (Alexey Muranov) (Guest)
on 2012-06-27 14:22
(Received via mailing list)
Issue #5394 has been updated by alexeymuranov (Alexey Muranov).


I just thought myself about anonymous methods and wanted to post it here 
with "Joke" status.  I thought about a possibility to change at runtime 
the method name, or switch two method bodies, and not to require that 
every method have a name.  With every class there would be associated a 
`Set` of class methods and a `Set` of instance methods, some named, some 
not, some having multiple names.
----------------------------------------
Feature #5394: Anonymous Symbols, Anonymous Methods
https://bugs.ruby-lang.org/issues/5394#change-27521

Author: kstephens (Kurt  Stephens)
Status: Feedback
Priority: Normal
Assignee:
Category:
Target version:


Proposal for Anonymous Symbols and Anonymous Methods

Anonymous Methods (AnonMeths) can be used for complex orthogonal 
behaviors that dispatch by receiver class without patching core or other 
sensitive classes in a globally visible manner.
AnonMeths are located by Anonymous Symbols (AnonSyms).
AnonSyms do not have parseable names, and can only be referenced by 
value, limiting namespace problems and promoting encapsulation.
AnonMeths are GCed once the AnonSym bound to them are GCed.
AnonMeths would not appear in Object#methods, thus will not confuse 
introspection.

Assume:

<pre><code class="ruby">
  Symbol.new() => #<Symbol:123412> # an AnonSymbol than can never be 
parsed in ruby code.
  anon_sym = Symbol.new() # an AnonSym in a variable that can be 
closed-over or passed by value.
</code></pre>

Optional Supporting Syntax:

<pre><code class="ruby">
  a.*anon_sym(args...) # equiv. to a.send(anon_sym, args...)
  class A
    def *anon_sym(args...); body...; end
  end
</code></pre>

equiv. to:

<pre><code class="ruby">
  class A
    define_method(anon_sym) {| args... | body... }
  end
</code></pre>

AnonSyms are not added directly to a Module's internal symbol-to-method 
table.
Instead, each AnonSym has an internal module-to-method table that is 
GCed when the AnonSym is GCed.

<pre><code class="ruby">
  rcvr.send(anon_sym, ...)
</code></pre>

will use anon_sym's module-to-method table to locate a method based on 
usual the receiver's module lookup chain.

Example Application:

Typical visitor pattern that pollutes Array and Object method 
namespaces:

<pre><code class="ruby">
  class Array;  def visit(visitor); each { | elem | elem.visit(visitor); 
} end; end
  class Object; def visit(visitor); visitor.something(self); 
end; end
</code></pre>

Functional alternative using "case ...; when ...":

<pre><code class="ruby">
  def visit(obj, visitor)
    case obj
    when Array
      obj.each { | elem | visit(elem, visitor) }
    else
      visitor.something(obj)
    end
  end
</code></pre>

AnonMeth version:

<pre><code class="ruby">
  def visit(obj, visitor)
    sel = Symbol.new
    class Array;   def *sel(visitor); each { | elem | elem.*sel(visitor) 
}; end; end
    class Object;  def *sel(visitor); visitor.something(self); 
end; end
    obj.*sel(visitor)
  end
</code></pre>

Imagine that visit() needs dynamic hooks to visit different types:

<pre><code class="ruby">
  def visit(obj, visitor)
    sel = Symbol.new
    class Array;   def *sel(visitor); each { | elem | elem.*sel(visitor) 
}; end; end
    class Object;  def *sel(visitor); visitor.something(self); 
end; end
    add_visit_methods!(sel)
    obj.*sel(visitor)
  end
  def add_visit_methods!(sel)
    class Hash;    def *sel(visitor); each { | k, v | v.*sel(visitor); 
end; end
    ...
  end
</code></pre>

The AnonSym send "rcvr.*sel(...)" dispatches, like a normal method send, 
directly to the appropriate AnonMeth for "*sel".
visit() can be extended dynamically by adding more AnonMeths bound to 
"*sel".
The functional "case ...; when..." version is difficult to extend and 
maintain and is likely to not perform as well as anon messages.
This is similar in style to Scheme letrecs, but is object-oriented.

This idea could be extended to Anonymous Ivars to resolve other 
namespacing and encapsulation issues for mixins that require state.

-- Kurt Stephens
Posted by mame (Yusuke Endoh) (Guest)
on 2012-11-20 15:01
(Received via mailing list)
Issue #5394 has been updated by mame (Yusuke Endoh).

Target version set to next minor


----------------------------------------
Feature #5394: Anonymous Symbols, Anonymous Methods
https://bugs.ruby-lang.org/issues/5394#change-33314

Author: kstephens (Kurt  Stephens)
Status: Feedback
Priority: Normal
Assignee:
Category:
Target version: next minor


Proposal for Anonymous Symbols and Anonymous Methods

Anonymous Methods (AnonMeths) can be used for complex orthogonal 
behaviors that dispatch by receiver class without patching core or other 
sensitive classes in a globally visible manner.
AnonMeths are located by Anonymous Symbols (AnonSyms).
AnonSyms do not have parseable names, and can only be referenced by 
value, limiting namespace problems and promoting encapsulation.
AnonMeths are GCed once the AnonSym bound to them are GCed.
AnonMeths would not appear in Object#methods, thus will not confuse 
introspection.

Assume:

<pre><code class="ruby">
  Symbol.new() => #<Symbol:123412> # an AnonSymbol than can never be 
parsed in ruby code.
  anon_sym = Symbol.new() # an AnonSym in a variable that can be 
closed-over or passed by value.
</code></pre>

Optional Supporting Syntax:

<pre><code class="ruby">
  a.*anon_sym(args...) # equiv. to a.send(anon_sym, args...)
  class A
    def *anon_sym(args...); body...; end
  end
</code></pre>

equiv. to:

<pre><code class="ruby">
  class A
    define_method(anon_sym) {| args... | body... }
  end
</code></pre>

AnonSyms are not added directly to a Module's internal symbol-to-method 
table.
Instead, each AnonSym has an internal module-to-method table that is 
GCed when the AnonSym is GCed.

<pre><code class="ruby">
  rcvr.send(anon_sym, ...)
</code></pre>

will use anon_sym's module-to-method table to locate a method based on 
usual the receiver's module lookup chain.

Example Application:

Typical visitor pattern that pollutes Array and Object method 
namespaces:

<pre><code class="ruby">
  class Array;  def visit(visitor); each { | elem | elem.visit(visitor); 
} end; end
  class Object; def visit(visitor); visitor.something(self); 
end; end
</code></pre>

Functional alternative using "case ...; when ...":

<pre><code class="ruby">
  def visit(obj, visitor)
    case obj
    when Array
      obj.each { | elem | visit(elem, visitor) }
    else
      visitor.something(obj)
    end
  end
</code></pre>

AnonMeth version:

<pre><code class="ruby">
  def visit(obj, visitor)
    sel = Symbol.new
    class Array;   def *sel(visitor); each { | elem | elem.*sel(visitor) 
}; end; end
    class Object;  def *sel(visitor); visitor.something(self); 
end; end
    obj.*sel(visitor)
  end
</code></pre>

Imagine that visit() needs dynamic hooks to visit different types:

<pre><code class="ruby">
  def visit(obj, visitor)
    sel = Symbol.new
    class Array;   def *sel(visitor); each { | elem | elem.*sel(visitor) 
}; end; end
    class Object;  def *sel(visitor); visitor.something(self); 
end; end
    add_visit_methods!(sel)
    obj.*sel(visitor)
  end
  def add_visit_methods!(sel)
    class Hash;    def *sel(visitor); each { | k, v | v.*sel(visitor); 
end; end
    ...
  end
</code></pre>

The AnonSym send "rcvr.*sel(...)" dispatches, like a normal method send, 
directly to the appropriate AnonMeth for "*sel".
visit() can be extended dynamically by adding more AnonMeths bound to 
"*sel".
The functional "case ...; when..." version is difficult to extend and 
maintain and is likely to not perform as well as anon messages.
This is similar in style to Scheme letrecs, but is object-oriented.

This idea could be extended to Anonymous Ivars to resolve other 
namespacing and encapsulation issues for mixins that require state.

-- Kurt Stephens
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.