Getting a list of aliases

Hi all,

Is there a way to get a list of instance method aliases somehow?

# Hypothetical syntax
Array.instance_method_aliases # ['size', 'map', ...]

If not, I think it would be a nice little bit of extra inspection I could use in certain situations, like when I'm in irb and feeling too lazy to look at the documentation. :wink:

Actually, this idea struck me when I tried to figure out just the "core" methods for a given class and wanted to exclude the aliases. At the time, I had to view the source code directly and count them. This proved more difficult than I thought, because sometimes methods would redefine functions with different names rather than use rb_define_alias() in the source code.

To give you an example of what I mean, in array.c the Array#map function is not declared using rb_define_alias(), but is simply mapped (no pun intended) to a different function:

rb_define_method(rb_cArray, "collect", rb_ary_collect, 0);
rb_define_method(rb_cArray, "map", rb_ary_collect, 0);

Thoughts?

- Dan

Is there a way to get a list of instance method aliases somehow?

# Hypothetical syntax
Array.instance_method_aliases # ['size', 'map', ...]

If not, I think it would be a nice little bit of extra inspection I could use in certain situations, like when I'm in irb and feeling too lazy to look at the documentation. :wink:

Actually, this idea struck me when I tried to figure out just the "core" methods for a given class and wanted to exclude the aliases. At the time, I had to view the source code directly and count them. This proved more difficult than I thought, because sometimes methods would redefine functions with different names rather than use rb_define_alias() in the source code.

To give you an example of what I mean, in array.c the Array#map function is not declared using rb_define_alias(), but is simply mapped (no pun intended) to a different function:

rb_define_method(rb_cArray, "collect", rb_ary_collect, 0);
rb_define_method(rb_cArray, "map", rb_ary_collect, 0);

WARNING: this gets gross:

It is a little less relevant with the core classes (seeing how they don't change very much), but easier to figure out what is aliased. You can use ParseTree to get the sexps for the class Array, and then it becomes pretty "obvious":

ruby -I../RubyInline/dev:lib -rparse_tree -e 'class Array; alias :blah :map; end; p ParseTree.new.parse_tree(Array)'

[[:class, :Array, :Object, ...
   [:defn, :blah, [:fbody, [:cfunc, 504080, 0]]], ...
   [:defn, :collect, [:cfunc, 504080, 0]],
   [:defn, :collect!, [:cfunc, 504206, 0]], ...
   [:defn, :map, [:cfunc, 504080, 0]],
   [:defn, :map!, [:cfunc, 504206, 0]], ...
]]

So, with c-implemented functions, your :defn is pretty much just a pointer to the C-function. You can compare the addresses and see what's been aliased. Likewise, with a real alias to a :cfunc you can dig a bit deeper and see that it points to it properly.

In the case of aliases on ruby methods, it gets harder:

% ruby -I../RubyInline/dev:lib -rparse_tree -e 'class X; def y; end; alias :x :y; end; p ParseTree.new.parse_tree(X)'

[[:class, :X, :Object,
   [:defn, :x, [:fbody, [:scope, [:block, [:args], [:nil]]]]],
   [:defn, :y, [:scope, [:block, [:args], [:nil]]]]]]

So, while you can conclude that :fbody is a marker for an alias to SOMETHING, you can't tell what because it is already expanded. You should be able to either compare sexps or use some C to dig in and see that the implementations (nd_body pointer) have the same address. The code in question is:

    st_insert(RCLASS(klass)->m_tbl, name,
      (st_data_t)NEW_METHOD(NEW_FBODY(body, def, origin), orig->nd_noex));

so the addresses should be the same. (yes, either option is rather icky).

路路路

On Jun 11, 2006, at 7:17 AM, Daniel Berger wrote:

Ryan Davis wrote:

Is there a way to get a list of instance method aliases somehow?

# Hypothetical syntax
Array.instance_method_aliases # ['size', 'map', ...]

If not, I think it would be a nice little bit of extra inspection I could use in certain situations, like when I'm in irb and feeling too lazy to look at the documentation. :wink:

Actually, this idea struck me when I tried to figure out just the "core" methods for a given class and wanted to exclude the aliases. At the time, I had to view the source code directly and count them. This proved more difficult than I thought, because sometimes methods would redefine functions with different names rather than use rb_define_alias() in the source code.

To give you an example of what I mean, in array.c the Array#map function is not declared using rb_define_alias(), but is simply mapped (no pun intended) to a different function:

rb_define_method(rb_cArray, "collect", rb_ary_collect, 0);
rb_define_method(rb_cArray, "map", rb_ary_collect, 0);

WARNING: this gets gross:

It is a little less relevant with the core classes (seeing how they don't change very much), but easier to figure out what is aliased. You can use ParseTree to get the sexps for the class Array, and then it becomes pretty "obvious":

ruby -I../RubyInline/dev:lib -rparse_tree -e 'class Array; alias :blah :map; end; p ParseTree.new.parse_tree(Array)'

[[:class, :Array, :Object, ...
  [:defn, :blah, [:fbody, [:cfunc, 504080, 0]]], ...
  [:defn, :collect, [:cfunc, 504080, 0]],
  [:defn, :collect!, [:cfunc, 504206, 0]], ...
  [:defn, :map, [:cfunc, 504080, 0]],
  [:defn, :map!, [:cfunc, 504206, 0]], ...
]]

So, with c-implemented functions, your :defn is pretty much just a pointer to the C-function. You can compare the addresses and see what's been aliased. Likewise, with a real alias to a :cfunc you can dig a bit deeper and see that it points to it properly.

In the case of aliases on ruby methods, it gets harder:

% ruby -I../RubyInline/dev:lib -rparse_tree -e 'class X; def y; end; alias :x :y; end; p ParseTree.new.parse_tree(X)'

[[:class, :X, :Object,
  [:defn, :x, [:fbody, [:scope, [:block, [:args], [:nil]]]]],
  [:defn, :y, [:scope, [:block, [:args], [:nil]]]]]]

So, while you can conclude that :fbody is a marker for an alias to SOMETHING, you can't tell what because it is already expanded. You should be able to either compare sexps or use some C to dig in and see that the implementations (nd_body pointer) have the same address. The code in question is:

    st_insert(RCLASS(klass)->m_tbl, name,
      (st_data_t)NEW_METHOD(NEW_FBODY(body, def, origin), orig->nd_noex));

so the addresses should be the same. (yes, either option is rather icky).

Very interesting Ryan, thank you.

What do you think about adding an Object.aliases method, though? Or is it just not worth the memory/speed hit?

Dan

路路路

On Jun 11, 2006, at 7:17 AM, Daniel Berger wrote:

I am not sure if I get your question right... maybe this is what you need:

require 'set'

def acts_as_test
  TestClasses.get << self
end

class TestClasses
  @@test_classes = Set.new
  def self.get
    @@test_classes
  end
end

class TestMe
  acts_as_test
end

class TestMeToo
  acts_as_test
end

TestClasses.get.inspect

#<Set: {TestMeToo, TestMe}>

-------- Original-Nachricht --------

路路路

Datum: Tue, 13 Jun 2006 23:19:51 +0900
Von: Daniel Berger <djberg96@gmail.com>
An: ruby-talk@ruby-lang.org
Betreff: Re: Getting a list of aliases

Ryan Davis wrote:
>
> On Jun 11, 2006, at 7:17 AM, Daniel Berger wrote:
>
>> Is there a way to get a list of instance method aliases somehow?
>>
>> # Hypothetical syntax
>> Array.instance_method_aliases # ['size', 'map', ...]
>>
>> If not, I think it would be a nice little bit of extra inspection I
>> could use in certain situations, like when I'm in irb and feeling too
>> lazy to look at the documentation. :wink:
>>
>> Actually, this idea struck me when I tried to figure out just the
>> "core" methods for a given class and wanted to exclude the aliases.
>> At the time, I had to view the source code directly and count them.
>> This proved more difficult than I thought, because sometimes methods
>> would redefine functions with different names rather than use
>> rb_define_alias() in the source code.
>>
>> To give you an example of what I mean, in array.c the Array#map
>> function is not declared using rb_define_alias(), but is simply mapped
>> (no pun intended) to a different function:
>>
>> rb_define_method(rb_cArray, "collect", rb_ary_collect, 0);
>> rb_define_method(rb_cArray, "map", rb_ary_collect, 0);
>
> WARNING: this gets gross:
>
> It is a little less relevant with the core classes (seeing how they
> don't change very much), but easier to figure out what is aliased. You
> can use ParseTree to get the sexps for the class Array, and then it
> becomes pretty "obvious":
>
> ruby -I../RubyInline/dev:lib -rparse_tree -e 'class Array; alias :blah
> :map; end; p ParseTree.new.parse_tree(Array)'
>
> [[:class, :Array, :Object, ...
> [:defn, :blah, [:fbody, [:cfunc, 504080, 0]]], ...
> [:defn, :collect, [:cfunc, 504080, 0]],
> [:defn, :collect!, [:cfunc, 504206, 0]], ...
> [:defn, :map, [:cfunc, 504080, 0]],
> [:defn, :map!, [:cfunc, 504206, 0]], ...
> ]]
>
> So, with c-implemented functions, your :defn is pretty much just a
> pointer to the C-function. You can compare the addresses and see what's
> been aliased. Likewise, with a real alias to a :cfunc you can dig a bit
> deeper and see that it points to it properly.
>
> In the case of aliases on ruby methods, it gets harder:
>
> % ruby -I../RubyInline/dev:lib -rparse_tree -e 'class X; def y; end;
> alias :x :y; end; p ParseTree.new.parse_tree(X)'
>
> [[:class, :X, :Object,
> [:defn, :x, [:fbody, [:scope, [:block, [:args], [:nil]]]]],
> [:defn, :y, [:scope, [:block, [:args], [:nil]]]]]]
>
> So, while you can conclude that :fbody is a marker for an alias to
> SOMETHING, you can't tell what because it is already expanded. You
> should be able to either compare sexps or use some C to dig in and see
> that the implementations (nd_body pointer) have the same address. The
> code in question is:
>
>> st_insert(RCLASS(klass)->m_tbl, name,
>> (st_data_t)NEW_METHOD(NEW_FBODY(body, def, origin),
>> orig->nd_noex));
>
> so the addresses should be the same. (yes, either option is rather
icky).
>
>

Very interesting Ryan, thank you.

What do you think about adding an Object.aliases method, though? Or is
it just not worth the memory/speed hit?

Dan

I think it is certainly doable and compact/fast enough if it is done in C as a standard method, but not really worth it given my ParseTree solution. I vote for aliased_methods tho. :slight_smile:

路路路

On Jun 13, 2006, at 7:19 AM, Daniel Berger wrote:

Very interesting Ryan, thank you.

What do you think about adding an Object.aliases method, though? Or is it just not worth the memory/speed hit?

sorry, wrong post :frowning:

-------- Original-Nachricht --------

路路路

Datum: Tue, 13 Jun 2006 23:41:41 +0900
Von: Peter Ertl <pertl@gmx.org>
An: ruby-talk@ruby-lang.org
Betreff: Re: Getting a list of aliases

I am not sure if I get your question right... maybe this is what you need:

require 'set'

def acts_as_test
  TestClasses.get << self
end

class TestClasses
  @@test_classes = Set.new
  def self.get
    @@test_classes
  end
end

class TestMe
  acts_as_test
end

class TestMeToo
  acts_as_test
end

> TestClasses.get.inspect
#<Set: {TestMeToo, TestMe}>

-------- Original-Nachricht --------
Datum: Tue, 13 Jun 2006 23:19:51 +0900
Von: Daniel Berger <djberg96@gmail.com>
An: ruby-talk@ruby-lang.org
Betreff: Re: Getting a list of aliases

> Ryan Davis wrote:
> >
> > On Jun 11, 2006, at 7:17 AM, Daniel Berger wrote:
> >
> >> Is there a way to get a list of instance method aliases somehow?
> >>
> >> # Hypothetical syntax
> >> Array.instance_method_aliases # ['size', 'map', ...]
> >>
> >> If not, I think it would be a nice little bit of extra inspection I
> >> could use in certain situations, like when I'm in irb and feeling too
> >> lazy to look at the documentation. :wink:
> >>
> >> Actually, this idea struck me when I tried to figure out just the
> >> "core" methods for a given class and wanted to exclude the aliases.
> >> At the time, I had to view the source code directly and count them.
> >> This proved more difficult than I thought, because sometimes methods
> >> would redefine functions with different names rather than use
> >> rb_define_alias() in the source code.
> >>
> >> To give you an example of what I mean, in array.c the Array#map
> >> function is not declared using rb_define_alias(), but is simply
mapped
> >> (no pun intended) to a different function:
> >>
> >> rb_define_method(rb_cArray, "collect", rb_ary_collect, 0);
> >> rb_define_method(rb_cArray, "map", rb_ary_collect, 0);
> >
> > WARNING: this gets gross:
> >
> > It is a little less relevant with the core classes (seeing how they
> > don't change very much), but easier to figure out what is aliased. You
> > can use ParseTree to get the sexps for the class Array, and then it
> > becomes pretty "obvious":
> >
> > ruby -I../RubyInline/dev:lib -rparse_tree -e 'class Array; alias :blah
> > :map; end; p ParseTree.new.parse_tree(Array)'
> >
> > [[:class, :Array, :Object, ...
> > [:defn, :blah, [:fbody, [:cfunc, 504080, 0]]], ...
> > [:defn, :collect, [:cfunc, 504080, 0]],
> > [:defn, :collect!, [:cfunc, 504206, 0]], ...
> > [:defn, :map, [:cfunc, 504080, 0]],
> > [:defn, :map!, [:cfunc, 504206, 0]], ...
> > ]]
> >
> > So, with c-implemented functions, your :defn is pretty much just a
> > pointer to the C-function. You can compare the addresses and see
what's
> > been aliased. Likewise, with a real alias to a :cfunc you can dig a
bit
> > deeper and see that it points to it properly.
> >
> > In the case of aliases on ruby methods, it gets harder:
> >
> > % ruby -I../RubyInline/dev:lib -rparse_tree -e 'class X; def y; end;
> > alias :x :y; end; p ParseTree.new.parse_tree(X)'
> >
> > [[:class, :X, :Object,
> > [:defn, :x, [:fbody, [:scope, [:block, [:args], [:nil]]]]],
> > [:defn, :y, [:scope, [:block, [:args], [:nil]]]]]]
> >
> > So, while you can conclude that :fbody is a marker for an alias to
> > SOMETHING, you can't tell what because it is already expanded. You
> > should be able to either compare sexps or use some C to dig in and see
> > that the implementations (nd_body pointer) have the same address. The
> > code in question is:
> >
> >> st_insert(RCLASS(klass)->m_tbl, name,
> >> (st_data_t)NEW_METHOD(NEW_FBODY(body, def, origin),
> >> orig->nd_noex));
> >
> > so the addresses should be the same. (yes, either option is rather
> icky).
> >
> >
>
> Very interesting Ryan, thank you.
>
> What do you think about adding an Object.aliases method, though? Or is
> it just not worth the memory/speed hit?
>
> Dan