Question about the behavior of reopening a module and including another module

Hello,

Recently a colleague and I discovered that our understanding of how
modules work, with regards to reopening a module after being included
in a class, seems to be at odds with how Ruby actually handles the
situation.

I am providing an example of code that highlights the situation.
What do you think will happen?
My expectations are given after the code.

···

------------------------------
module LangDefault
   def foo
     :LangDefault
   end
end

module XLang
   include LangDefault
end

module JLang
   def foo
     :JLang
   end
end

class Talk
   include XLang
end

tlk = Talk.new
puts tlk.foo

module XLang
   include JLang
end

puts tlk.foo
puts Talk.new.foo

class Write
   include XLang
end

puts Write.new.foo

puts Talk.included_modules.join(",")
puts Write.included_modules.join(",")

class Talk
   include XLang
end

puts Talk.new.foo

------------------------------

I assumed that once XLang included JLang, after the first time Talk
included XLang, that Talk would also recognize this change. Thus, an
instance of Talk's invocation of foo after XLang included JLang would
return :JLang instead of :LangDefault. This is what an instance of
Write's invocation does. Unfortunately, Talk does not do this until I
include XLang in Talk.

Is this a design decision or an implementation issue?
I ask, because I would like to further refine my understanding of
modules and I am looking for techniques for run time extension of a
program. Currently, the above works except that I have to make sure
that a module is extended before it is included in any classes.

Best,
Zev Blut

Zev Blut schrieb:

Recently a colleague and I discovered that our understanding of how
modules work, with regards to reopening a module after being included
in a class, seems to be at odds with how Ruby actually handles the
situation.

(example snipped)

Is this a design decision or an implementation issue?

You can find a description here: Programming Ruby: The Pragmatic Programmer's Guide (if you have the paper version see also figure 19.4 on page 247).

By including a module, anonymous proxy classes pointing to the module and its ancestors are added to the ancestors of the including class. If you alter a module's ancestors AFTER including the module in a class, the proxy classes don't reflect this change.

I think it's an implementation issue.

Regards,
Pit

Hello,

You can find a description here: Programming Ruby: The Pragmatic Programmer's Guide (if you have the paper version see also figure 19.4 on page 247).

Thanks for the link, it certainly helps describe how it is implemented.

By including a module, anonymous proxy classes pointing to the module and its ancestors are added to the ancestors of the including class. If you alter a module's ancestors AFTER including the module in a class, the proxy classes don't reflect this change.

I think it's an implementation issue.

Yeah probably so.
Are there plans to change this in Ruby 2.0?

Best,
Zev

···

On Wed, 24 Nov 2004 06:31:18 +0900, Pit Capitain <pit@capitain.de> wrote:

It is a rather fundamental problem, so is not likely to get addressed.
Thankfully, it is extremely rare for it to be a problem.

There has been some talk of this on suby-ruby, with a possible solution or
two, but they have performace downsides.

T.

···

On Wednesday 24 November 2004 05:24 am, Zev Blut wrote:

Hello,

On Wed, 24 Nov 2004 06:31:18 +0900, Pit Capitain <pit@capitain.de> wrote:
> You can find a description here:
> Programming Ruby: The Pragmatic Programmer's Guide (if
> you have the paper version see also figure 19.4 on page 247).

Thanks for the link, it certainly helps describe how it is implemented.

> By including a module, anonymous proxy classes pointing to the module
> and its ancestors are added to the ancestors of the including class. If
> you alter a module's ancestors AFTER including the module in a class,
> the proxy classes don't reflect this change.
>
> I think it's an implementation issue.

Yeah probably so.
Are there plans to change this in Ruby 2.0?