Super's not so super today

Can anyone help me get around this?

  class C
    def r ; "r" ; end
  end

  module M
    def r
      #return '{' + super + '}'
      target = lambda{ super }
      b( target )
    end
    def b( target )
      '{' + target.call + '}'
    end
  end

  module N
    def r
      target = lambda{ super }
      b( target )
    end
    def b( target )
      '[' + target.call + ']'
    end
  end

  class D < C
    include M
    include N
  end

  d = D.new
  p d.r #=> "[[r]]"

The result should be "[{r}]". Notice the remarked line I left in there,
if you unremark that line it works fine. So what going on? What can I
do to fix this?

Thanks,
T.

Looking at this, I don't think there's anything wrong with you're
super at all, but rather, which b is being called. M#b and N#b collide
when they're both included and you're losing your M#b altogether. If
you rename so that those methods are different, you can see it
working:

  $ cat test.rb
  class C
    def r ; "r" ; end
  end

  module M
    def r
      #return '{' + super + '}'
      target = lambda{ super }
      b( target )
    end
    def b( target )
      '{' + target.call + '}'
    end
  end

  module N
    def r
      target = lambda{ super }
      q( target ) # note the changed method name here
    end
    def q( target ) # and here
      '[' + target.call + ']'
    end
  end

  class D < C
    include M
    include N
  end

  d = D.new
  p d.r #=> "[{r}]"

  $ ruby test.rb
  "[{r}]"

Jacob Fugal

···

On 7/18/06, transfire@gmail.com <transfire@gmail.com> wrote:

  class C
    def r ; "r" ; end
  end

  module M
    def r
      #return '{' + super + '}'
      target = lambda{ super }
      b( target )
    end
    def b( target )
      '{' + target.call + '}'
    end
  end

  module N
    def r
      target = lambda{ super }
      b( target )
    end
    def b( target )
      '[' + target.call + ']'
    end
  end

  class D < C
    include M
    include N
  end

  d = D.new
  p d.r #=> "[[r]]"

The result should be "[{r}]". Notice the remarked line I left in there,
if you unremark that line it works fine. So what going on? What can I
do to fix this?

Jacob Fugal wrote:

···

On 7/18/06, transfire@gmail.com <transfire@gmail.com> wrote:
> class C
> def r ; "r" ; end
> end
>
> module M
> def r
> #return '{' + super + '}'
> target = lambda{ super }
> b( target )
> end
> def b( target )
> '{' + target.call + '}'
> end
> end
>
> module N
> def r
> target = lambda{ super }
> b( target )
> end
> def b( target )
> '[' + target.call + ']'
> end
> end
>
> class D < C
> include M
> include N
> end
>
> d = D.new
> p d.r #=> "[[r]]"
>
> The result should be "[{r}]". Notice the remarked line I left in there,
> if you unremark that line it works fine. So what going on? What can I
> do to fix this?

Looking at this, I don't think there's anything wrong with you're
super at all, but rather, which b is being called. M#b and N#b collide
when they're both included and you're losing your M#b altogether. If
you rename so that those methods are different, you can see it
working:

  $ cat test.rb
  class C
    def r ; "r" ; end
  end

  module M
    def r
      #return '{' + super + '}'
      target = lambda{ super }
      b( target )
    end
    def b( target )
      '{' + target.call + '}'
    end
  end

  module N
    def r
      target = lambda{ super }
      q( target ) # note the changed method name here
    end
    def q( target ) # and here
      '[' + target.call + ']'
    end
  end

  class D < C
    include M
    include N
  end

  d = D.new
  p d.r #=> "[{r}]"

  $ ruby test.rb
  "[{r}]"

Jacob Fugal

Ah! Of course, Thank you. Unfortuantely NOW I need class local methods!
:frowning:

T.

transfire@gmail.com wrote:

Ah! Of course, Thank you. Unfortuantely NOW I need class local methods!
:frowning:

Well, this leads me to ask again about these state of affairs for a
future Ruby. Are we going to get local instance vars? I think the
suggested notation was @_. And likewise what of local methods?

If I recall correctly I think that last thing I suggest was making all
instance vars local, which would measn accessors were paramount in
sharing data better levels and then local methods could be defined with

  def @method()

But maybe that's too much. Anyway it's just a thought. I don't really
care so much how it's done just so long as it becomes possible. If you
want a usecase, my particular case is defining cross-concerns, I want
to be able to access the internal state of the class hierachy in
general as we do now, while maintiang a separate local state (for the
concern) as well.

On a side note I think I found a bug in Ruby, maybe

  class X
    def self.method_added(name)
      p name
    end
  end

  class X
    def x; end
   end
   => :x

  class << X
    undef_method :method_added
  end

  class X
    def y; end
  end
  => NoMethodError: undefined method `method_added' for X:Class

</Trans>

You get the same error even if you don't override method_added first.
It looks like the call to method_added is hard-coded in
rb_add_method() in eval.c.. (also in rb_alias())

It seems like a bug to me - the c code should check that callback
methods still exist before calling them.

-Adam

···

On 7/18/06, Trans <transfire@gmail.com> wrote:

On a side note I think I found a bug in Ruby, maybe

  class << X
    undef_method :method_added
  end

  class X
    def y; end
  end
  => NoMethodError: undefined method `method_added' for X:Class

Is it a bug? You are undef'ing it after all. remove_method would seem
more appropriate in this use case.

But maybe a warning like "undefining `method_added' may cause serious
problem" like for __send__, __id__, etc. might be in order.

Regards,
Sean

···

On 7/18/06, Trans <transfire@gmail.com> wrote:

On a side note I think I found a bug in Ruby, maybe

  class X
    def self.method_added(name)
      p name
    end
  end

  class X
    def x; end
   end
   => :x

  class << X
    undef_method :method_added
  end

  class X
    def y; end
  end
  => NoMethodError: undefined method `method_added' for X:Class

</Trans>

If we ever get local methods, this seems like a reasonable notation to me.

Regards,
Sean

···

On 7/18/06, Trans <transfire@gmail.com> wrote:

transfire@gmail.com wrote:

> Ah! Of course, Thank you. Unfortuantely NOW I need class local methods!
> :frowning:

Well, this leads me to ask again about these state of affairs for a
future Ruby. Are we going to get local instance vars? I think the
suggested notation was @_. And likewise what of local methods?

If I recall correctly I think that last thing I suggest was making all
instance vars local, which would measn accessors were paramount in
sharing data better levels and then local methods could be defined with

  def @method()

But maybe that's too much.

Adam Shelly wrote:

···

On 7/18/06, Trans <transfire@gmail.com> wrote:
> On a side note I think I found a bug in Ruby, maybe
>
> class << X
> undef_method :method_added
> end
>
> class X
> def y; end
> end
> => NoMethodError: undefined method `method_added' for X:Class
>
>
You get the same error even if you don't override method_added first.
It looks like the call to method_added is hard-coded in
rb_add_method() in eval.c.. (also in rb_alias())

It seems like a bug to me - the c code should check that callback
methods still exist before calling them.

I see. Okay, at least that makes sense. I agree though, I seem more
logical that it would check for the method, rather then hard coding an
empty one into core. But maybe it's more efficient that way?

Thanks,
T.

Sean O'Halpin wrote:

>
> On a side note I think I found a bug in Ruby, maybe
>
> class X
> def self.method_added(name)
> p name
> end
> end
>
> class X
> def x; end
> end
> => :x
>
> class << X
> undef_method :method_added
> end
>
> class X
> def y; end
> end
> => NoMethodError: undefined method `method_added' for X:Class
>
>
> </Trans>
>
>
Is it a bug? You are undef'ing it after all. remove_method would seem
more appropriate in this use case.

But maybe a warning like "undefining `method_added' may cause serious
problem" like for __send__, __id__, etc. might be in order.

Weel, yea sort of. B/c look at what happended to me. I defined my own
method_added in a paritcular class, and in order to prevent an infinite
loop I need to undefine it in a subclass of it. I.e.

  class X
    def method_added
      ... this might define a method in a Y
    end
  end

  class Y < X
    remove_method :method_added # goes right back to infinite loop
    undef_method :method_added # bombs per our "bug"
    def method_added; end # what I ended up with
  end

So there's an easy fix but it's seems a bit wasteful. One wuould expect
undef to work and save a call to a noop. Butmaybe it's more efficeint
to just make the call to the noop then it is to see if it's present? I
somehow doubt it though. In whihc case I say it's a minor bug.

T.

···

On 7/18/06, Trans <transfire@gmail.com> wrote:

Having thought about it a bit more, I'm inclined to agree. There's no
(logical) reason why method_added should be called if you don't define
it yourself, so it seems reasonable to be able to undef it completely
from a class without side-effects.

Regards,
Sean

···

On 7/19/06, transfire@gmail.com <transfire@gmail.com> wrote:

Sean O'Halpin wrote:
> On 7/18/06, Trans <transfire@gmail.com> wrote:
> >
> > On a side note I think I found a bug in Ruby, maybe
> >
> > class X
> > def self.method_added(name)
> > p name
> > end
> > end
> >
> > class X
> > def x; end
> > end
> > => :x
> >
> > class << X
> > undef_method :method_added
> > end
> >
> > class X
> > def y; end
> > end
> > => NoMethodError: undefined method `method_added' for X:Class
> >
> > </Trans>
> >
> Is it a bug? You are undef'ing it after all. remove_method would seem
> more appropriate in this use case.
>
> But maybe a warning like "undefining `method_added' may cause serious
> problem" like for __send__, __id__, etc. might be in order.

Weel, yea sort of. B/c look at what happended to me. I defined my own
method_added in a paritcular class, and in order to prevent an infinite
loop I need to undefine it in a subclass of it. I.e.

  class X
    def method_added
      ... this might define a method in a Y
    end
  end

  class Y < X
    remove_method :method_added # goes right back to infinite loop
    undef_method :method_added # bombs per our "bug"
    def method_added; end # what I ended up with
  end

So there's an easy fix but it's seems a bit wasteful. One wuould expect
undef to work and save a call to a noop. Butmaybe it's more efficeint
to just make the call to the noop then it is to see if it's present? I
somehow doubt it though. In whihc case I say it's a minor bug.

T.