special super call for module class-level inclusion

Discussion in 'Ruby' started by Trans, Aug 28, 2007.

  1. Trans

    Trans Guest

    Since I've come upon the issue again, I reckon, it's as good time as
    any to put this in the air.

    The issue, again, is that module class methods are not
    "inherited" (for lack of a better word). In the past I've argued for
    this, but it has been consistently argued down due to the extraneous
    methods it would add to classes. However, it occurs to me that the
    core problem that I continually face for the lack of this, it simply
    that I can't call super in a class level method and expect it to move
    through included module methods. The reason this is such a problem, it
    that it makes it very difficult to create an "inheriting variable".
    This is the reason Facets contains inheritor.rb, but even that is
    limited to only simple cases.

    To make this clear, here is a simple example of the idea:

    class X
    include M
    def self.foo
    [ 'Xfoo' ]
    end
    end

    module M
    def self.foo
    [ 'Mfoo' ] + super
    end
    end

    class Y < X
    include M
    def self.foo
    [ 'Yfoo' ] + super
    end
    end

    Y.foo #=> [ 'Yfoo', 'Xfoo' ]

    As you can see there is no 'Mfoo' in the list.

    If your're wondering how this is useful, consider any use-case where
    meta-information needs to associated to a method. Just as methods are
    inherited so too their meta-information. Possible uses are annotations
    and pre, post, around wraps.

    So the thought I had today is that rather then full inclusion at the
    class-level, that we might simply have an alternate #super call that
    would traverse the include modules class methods as well as classes. I
    realize that might be tricky to implement, but it would satisfy the
    need without all the unwanted baggage.

    T.
     
    Trans, Aug 28, 2007
    #1
    1. Advertising

  2. Trans wrote:
    > The issue, again, is that module class methods are not
    > "inherited" (for lack of a better word). In the past I've argued for
    > this, but it has been consistently argued down due to the extraneous
    > methods it would add to classes. However, it occurs to me that the


    IMHO the reason for this problem is that modules serve double duty as
    both mixins (instance methods) and namespaces (class methods).

    > core problem that I continually face for the lack of this, it simply
    > that I can't call super in a class level method and expect it to move
    > through included module methods. The reason this is such a problem, it
    > that it makes it very difficult to create an "inheriting variable".
    > This is the reason Facets contains inheritor.rb, but even that is
    > limited to only simple cases.


    The problem piqued my interest so despite my best attempts at
    self-control I wound up writing code for it :-/

    class Module
    attr_accessor :class_methods_module
    def class_methods(&block)
    self.class_methods_module ||= begin
    mod = Module.new
    core = (class << self; self; end)
    prev = core.method:)included)
    core.send:)define_method, :included) do |into_class|
    prev.call(into_class)
    into_class.extend(mod)
    end
    mod
    end
    class_methods_module.class_eval(&block)
    end
    end

    class Class
    def class_methods(&block)
    instance_eval(&block)
    end
    end

    module M
    def a;"Ma";end
    class_methods do
    def b;"Mb";end
    end
    end

    class C
    include M
    def a;"Ca"+super;end
    class_methods do
    def b;"Cb"+super;end
    end
    end

    puts C.new.a #=> CaMa
    puts C.b #=> CbMb
     
    Daniel DeLorme, Aug 30, 2007
    #2
    1. Advertising

  3. Trans

    Trans Guest

    On Aug 29, 4:58 pm, Daniel DeLorme <> wrote:

    > The problem piqued my interest so despite my best attempts at
    > self-control I wound up writing code for it :-/
    >
    > class Module
    > attr_accessor :class_methods_module
    > def class_methods(&block)
    > self.class_methods_module ||= begin
    > mod = Module.new
    > core = (class << self; self; end)
    > prev = core.method:)included)
    > core.send:)define_method, :included) do |into_class|
    > prev.call(into_class)
    > into_class.extend(mod)
    > end
    > mod
    > end
    > class_methods_module.class_eval(&block)
    > end
    > end
    >
    > class Class
    > def class_methods(&block)
    > instance_eval(&block)
    > end
    > end


    Nice work! That's not the easiest piece of meta-code to write. But has
    been touched on before. Facets has had a version of this for a while
    now, used extensively by Nitro/Og, written primarily by Daniel
    Schierbeck. It looks like this:

    class Module


    alias_method :append_features_without_class_extension, :append_features

    def class_extension(&block)
    @class_extension ||= Module.new do
    def self.append_features(mod)
    append_features_without_class_extension(mod)
    end
    end
    @class_extension.module_eval(&block) if block_given?
    @class_extension
    end

    private :class_extension

    def append_features(mod)
    append_features_without_class_extension(mod)
    mod.extend(class_extension)
    if mod.instance_of? Module
    mod.__send__:)class_extension).__send__:)include,
    class_extension)
    end
    end

    end

    class Class
    undef_method :class_extension
    end

    Your definition of Class's method is an interesting idea and may make
    a good adjustment Facets' undef_method.

    On the downside, this approach doesn't RDoc well --actually it doesn't
    RDOc at all. Also, many people seem put off by the general aesthetic
    of it too.

    As of late I've been leaning toward the idea of the old ClassMethods
    module solution, but modifying #include (or a similar new method) to
    handle the extension rather than using the included callback.
    (Personally, I'd also prefer a better name than ClassMethods, but
    that's of minor consequence).

    T.
     
    Trans, Aug 31, 2007
    #3
    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. Guest

    super.super.super how?

    Guest, Feb 19, 2005, in forum: Java
    Replies:
    24
    Views:
    10,823
    Darryl Pierce
    Feb 24, 2005
  2. Fernando Rodriguez

    Getting the super class via the super() function

    Fernando Rodriguez, Nov 21, 2003, in forum: Python
    Replies:
    2
    Views:
    728
    Bob Willan
    Nov 22, 2003
  3. pabbu
    Replies:
    8
    Views:
    745
    Marc Boyer
    Nov 7, 2005
  4. fi3nd
    Replies:
    0
    Views:
    389
    fi3nd
    Apr 8, 2010
  5. Matthew Braid

    $class::SUPER as well as $instance::SUPER?

    Matthew Braid, Aug 6, 2004, in forum: Perl Misc
    Replies:
    2
    Views:
    313
    Matthew Braid
    Aug 9, 2004
Loading...

Share This Page