Overriding methods in a class using a mixin

Discussion in 'Ruby' started by James Coglan, Nov 14, 2008.

  1. James Coglan

    James Coglan Guest

    [Note: parts of this message were removed to make it a legal post.]

    Hi list,
    I just had this idea and thought I'd share it in case someone can improve
    upon it, make it more robust. Basically, I've run into a situation a few
    times where I want to override methods in a class but retain access to old
    implementations, the sort of thing people like to use alias_method_chain
    for. I tend to favour this approach, though:

    class Foo
    meth = instance_method:)foo)
    define_method:)foo) do |some, args|
    result = meth.bind(self).call(some, args)
    # do extra stuff...
    end
    end

    But, then you've lost the old implementation: it's hidden in the closure and
    you can't get another reference to it from anywhere else. So, I've come up
    with a way in which you can copy the class's methods into a module, include
    that module (making it part of the inheritance chain) and then mix other
    modules in. Later modules can thereby override the class's own methods and
    use 'super' to refer to them. This lets you insert code between an existing
    class and all its subclasses, which can be useful.

    Code on github, with an example:
    http://gist.github.com/25104

    Comments, suggestions, and accusations of idiocy all very much welcome.
    Expanding from this, I'd like to figure out how I can insert modules at
    arbitrary points in the inheritance chain, rather than just using 'include'
    to come between a module and it's last included module.

    --
    James Coglan

    Lead JavaScript Developer
    theOTHERmedia
    http://ojay.othermedia.org
    +44 (0) 7771512510
     
    James Coglan, Nov 14, 2008
    #1
    1. Advertising

  2. James Coglan

    Trans Guest

    On Nov 14, 5:02=A0pm, "James Coglan" <> wrote:
    > Hi list,
    > I just had this idea and thought I'd share it in case someone can improve
    > upon it, make it more robust. Basically, I've run into a situation a few
    > times where I want to override methods in a class but retain access to ol=

    d
    > implementations, the sort of thing people like to use alias_method_chain
    > for. I tend to favour this approach, though:
    >
    > class Foo
    > =A0 meth =3D instance_method:)foo)
    > =A0 define_method:)foo) do |some, args|
    > =A0 =A0 result =3D meth.bind(self).call(some, args)
    > =A0 =A0 # do extra stuff...
    > =A0 end
    > end
    >
    > But, then you've lost the old implementation: it's hidden in the closure =

    and
    > you can't get another reference to it from anywhere else. So, I've come u=

    p
    > with a way in which you can copy the class's methods into a module, inclu=

    de
    > that module (making it part of the inheritance chain) and then mix other
    > modules in. Later modules can thereby override the class's own methods an=

    d
    > use 'super' to refer to them. This lets you insert code between an existi=

    ng
    > class and all its subclasses, which can be useful.
    >
    > Code on github, with an example:http://gist.github.com/25104


    Well done. I've explored a number of approaches to this is a pretty
    good one.

    On the downside though the reoccurring binding is going to slow things
    down.

    Anther approach is to override #new and #extend the object with the
    "aspect" module upon creation.

    > Comments, suggestions, and accusations of idiocy all very much welcome.
    > Expanding from this, I'd like to figure out how I can insert modules at
    > arbitrary points in the inheritance chain, rather than just using 'includ=

    e'
    > to come between a module and it's last included module.


    You can just include it in the ancestor you want it to go after. But
    of course that's going to effect all subclasses of that class.

    Facets definition of Kernel#at() might interest you though.

    T.
     
    Trans, Nov 15, 2008
    #2
    1. Advertising

  3. James Coglan

    ara.t.howard Guest

    On Nov 14, 2008, at 3:02 PM, James Coglan wrote:

    > Hi list,
    > I just had this idea and thought I'd share it in case someone can
    > improve
    > upon it, make it more robust. Basically, I've run into a situation a
    > few
    > times where I want to override methods in a class but retain access
    > to old
    > implementations, the sort of thing people like to use
    > alias_method_chain
    > for. I tend to favour this approach, though:
    >
    > class Foo
    > meth = instance_method:)foo)
    > define_method:)foo) do |some, args|
    > result = meth.bind(self).call(some, args)
    > # do extra stuff...
    > end
    > end



    alias_method_chain_is_crap_because_it_leads_to_madness_like_this

    your method is *ok* but it chops the method in half - dropping blocks
    on the floor

    check this out

    http://drawohara.com/post/7241442/ruby-saner-way-to-redefine-methods

    a @ http://codeforpeople.com/
    --
    we can deny everything, except that we have the possibility of being
    better. simply reflect on that.
    h.h. the 14th dalai lama
     
    ara.t.howard, Nov 15, 2008
    #3
  4. James Coglan

    James Coglan Guest

    [Note: parts of this message were removed to make it a legal post.]

    >
    > your method is *ok* but it chops the method in half - dropping blocks on
    > the floor




    I made some changes that mean blocks are supported -- turns out storing a
    reference to the module a method is defined in is a little messy. I notice
    you look up old methods via the class that's calling the method, whereas I
    want the exact module storing the method to handle the lookup. Not sure if
    there's much practical difference but I find my way easier to think about.

    http://gist.github.com/25104
     
    James Coglan, Nov 15, 2008
    #4
  5. James Coglan

    ara.t.howard Guest

    On Nov 15, 2008, at 5:33 AM, James Coglan wrote:

    >
    > I made some changes that mean blocks are supported -- turns out
    > storing a
    > reference to the module a method is defined in is a little messy. I
    > notice
    > you look up old methods via the class that's calling the method,
    > whereas I
    > want the exact module storing the method to handle the lookup. Not
    > sure if
    > there's much practical difference but I find my way easier to think
    > about.
    >
    > http://gist.github.com/25104



    couple observations after a quick browse

    your override method will not allow one to redefine a method which
    takes a block. you cannot say

    override:)map) do
    list = []
    each(&block){|element| list << element} # block does not
    exist!
    list
    end

    because you lose the handle on any block passed to the method. any
    use of define_method drops a block on the floor.

    m.bind(self).call(*args[0...m.arity], &block)

    blows up when arity is negative, which it often is

    cfp:~ > ruby -e' def foo(a,b,*c) end; p
    Object.instance_method:)foo).arity '
    -3

    override will blow up stashing methods which may or may not actually
    be defined on that class, for instance

    override('inspect'){ 'but inspect is not an instance method' }


    the pre-clusion ability is handy for sure though.

    cheers.

    ,
    a @ http://codeforpeople.com/
    --
    we can deny everything, except that we have the possibility of being
    better. simply reflect on that.
    h.h. the 14th dalai lama
     
    ara.t.howard, Nov 15, 2008
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Florian Frank

    Extract methods in a class to mixin?

    Florian Frank, Sep 10, 2003, in forum: Ruby
    Replies:
    0
    Views:
    111
    Florian Frank
    Sep 10, 2003
  2. Michael Roth

    Mixin of class methods?

    Michael Roth, Sep 24, 2005, in forum: Ruby
    Replies:
    8
    Views:
    144
    michele
    Sep 26, 2005
  3. Kenneth McDonald
    Replies:
    5
    Views:
    345
    Kenneth McDonald
    Sep 26, 2008
  4. dc

    removing mixin methods

    dc, Oct 31, 2008, in forum: Ruby
    Replies:
    1
    Views:
    83
    Mike Gold
    Oct 31, 2008
  5. John Lane
    Replies:
    6
    Views:
    196
    John Lane
    Feb 9, 2010
Loading...

Share This Page