Why the lack of mixing-in support for Class methods?


#141

removed_email_address@domain.invalid wrote:

I assume you are doing this for the challenge / learning expience…

That, and it’s nice to have an implementation that fits with the
interface we have pretty much agreed on (well, matz has).

end
Thanks for the feedback, here’s the updated version.

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

 def append_features(mod)
   mod.extend(class_extension)
   if mod.instance_of? Module and mod.respond_to? :class_extension
     mod.send(:class_extension).send(:include, class_extension)
   end
 end

end

class Class
undef_method :class_extension
end

#class_extension should probably be private, right?

Daniel


#142

Daniel S. wrote:

 def included(mod)
   mod.extend(class_extension)
   if mod.instance_of? Module and mod.respond_to? :class_extension
     mod.send(:class_extension).send(:include, class_extension)
   end
 end

end

The code might need a change if we decide to make #class_extension private.

Daniel,

I assume you are doing this for the challenge / learning expience…

#included is not the best method to use since it is a callback. While
you could override #include itself, probably the most appropriate
method to use is #append_features. This is the method include calls to
do it’s “magic”.

Also, after defining the class_extension method for Module, you’ll want
to undefine it for Class, since it has no relevance there:

class Class
undef_method :class_extension
end

HTH,
T.


#143

Hi,

In message “Re: Why the lack of mixing-in support for Class methods?”
on Thu, 15 Jun 2006 23:38:24 +0900, Daniel S.
removed_email_address@domain.invalid writes:

|That, and it’s nice to have an implementation that fits with the
|interface we have pretty much agreed on (well, matz has).

Yes, and there’s something that only working code can prove.

|#class_extension should probably be private, right?

I think so. Besides, I am thinking of class/module separation in the
future (both of them will become subclass of Object), so that users
won’t confuse modules with classes.

						matz.

#144

On Fri, 16 Jun 2006, Yukihiro M. wrote:

Hi,

In message “Re: Why the lack of mixing-in support for Class methods?”
on Thu, 15 Jun 2006 23:38:24 +0900, Daniel S. removed_email_address@domain.invalid writes:

|That, and it’s nice to have an implementation that fits with the
|interface we have pretty much agreed on (well, matz has).

Yes, and there’s something that only working code can prove.

do you think this is important?

 harp:~ > cat b.rb
 require 'class_extension'
 module M
   class_extension do
     p const_get(:File)                  # File
     p File                              # File
     class File
       def self.inspect() 'my_file' end
     end
     p const_get(:File)                  # File
     p File                              # my_file
   end
 end

 p M::File                               # my_file
 p M::const_get(:File)                   # my_file
 p M::class_extension::const_get(:File)  # File
 p M::class_extension::File              # exception!


 harp:~ > ruby b.rb
 File
 File
 File
 my_file
 my_file
 my_file
 File
 b.rb:18: uninitialized constant #<Module:0xb75cdf08>::File 

(NameError)

i am in the minority, but it bothers me. don’t get me wrong, i like the
interface - but the semantics seem odd.

regards.

-a


#145

#class_extension is now private, the magic has been moved to
#append_features, and #class_extension has been undefined in Class, per
T’s request.

class Module
alias_method :append_features, :append_features

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

 private :class_extension

 def append_features(mod)
   __append_features__(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

#send must of course be replaced with #funcall in 1.9 – has there been
any progress with the naming of that? I checked the archives, but
couldn’t find anything never than August '05… it sounds like a “fun
call”, if you know what I mean… hopefully you don’t.

Daniel


#146

This seems to have been resolved in the latest version.

Daniel


#147

On Fri, 16 Jun 2006, Daniel S. wrote:

     __append_features__(mod)
 mod.extend(class_extension)

#send must of course be replaced with #funcall in 1.9 – has there been any
progress with the naming of that? I checked the archives, but couldn’t find
anything never than August '05… it sounds like a “fun call”, if you know
what I mean… hopefully you don’t.

Daniel

hi daniel-

is this by design?

harp:~ > cat b.rb
require ‘class_extension’
module M
class_extension{ attr_accessor ‘a’ }
end
M.a # exception!

harp:~ > ruby b.rb
b.rb:6: undefined method `a’ for M:Module (NoMethodError)

i lost track of whether the module should respond to this or not… (the
thread
is looooong).

regards.

-a


#148

Daniel S. wrote:

       __append_features__(mod)
   mod.extend(class_extension)

#send must of course be replaced with #funcall in 1.9 – has there been
any progress with the naming of that? I checked the archives, but
couldn’t find anything never than August '05… it sounds like a “fun
call”, if you know what I mean… hopefully you don’t.

Isn’t #funcall now called #instance_exec?

T.


#149

Hi,

In message “Re: Why the lack of mixing-in support for Class methods?”
on Fri, 16 Jun 2006 01:10:53 +0900, removed_email_address@domain.invalid writes:

|is this by design?
|
| harp:~ > cat b.rb
| require ‘class_extension’
| module M
| class_extension{ attr_accessor ‘a’ }
| end
| M.a # exception!

Yes. class_extension add features to the target class but not to the
module itself.

class C
include M
end
M.a = 42
p M.a # => 42

						matz.

#150

Hi,

In message “Re: Why the lack of mixing-in support for Class methods?”
on Fri, 16 Jun 2006 00:50:43 +0900, removed_email_address@domain.invalid writes:

| p M::class_extension::const_get(:File) # File
| p M::class_extension::File # exception!

The difference here is caused because a class statement with in
module_eval defines a constant in the innermost surrounding class /
module (M, this case) in 1.8, and const_get looks ancestors for
constants by default, where double colons do not.

In 1.9, a class statement in module_eval defines a constant in the
target module (anonymous class_extension module in this case). So
that it gives:

File
File
my_file
my_file
/tmp/c.rb:42: warning: toplevel constant File referenced by M::File
File
File
my_file
my_file

for 1.9 that means the new File class is defined under anonymous
class_extension module. It seems more consistent and simple.

						matz.

#151

removed_email_address@domain.invalid wrote:

harp:~ > ruby b.rb
b.rb:6: undefined method `a’ for M:Module (NoMethodError)

i lost track of whether the module should respond to this or not… (the
thread
is looooong).

Hi,

Yes, it’s by design. Originally I extended the class that defined the
class extension, but per the request of some, I removed it again. This
should sort it out

module M
class_extension{ attr_accessor :a, :b }
extend class_extension
end

M.a = 42

Cheers,
Daniel


#152

removed_email_address@domain.invalid wrote:

Isn’t #funcall now called #instance_exec?

I think #instance_exec is an eval method.

I liked the #send!' and#instance_send’ names.

Cheers,
Daniel


#153

Hi,

In message “Re: Why the lack of mixing-in support for Class methods?”
on Fri, 16 Jun 2006 01:16:08 +0900, removed_email_address@domain.invalid writes:

|> #send must of course be replaced with #funcall in 1.9 – has there been
|> any progress with the naming of that? I checked the archives, but
|> couldn’t find anything never than August '05… it sounds like a “fun
|> call”, if you know what I mean… hopefully you don’t.

I don’t. Luckily or not. For your information, ‘funcall’ is a lisp
function name that has its own history.

|Isn’t #funcall now called #instance_exec?

No, they are different.

						matz.

#154

On Fri, 16 Jun 2006, Yukihiro M. wrote:

module (M, this case) in 1.8, and const_get looks ancestors for
/tmp/c.rb:42: warning: toplevel constant File referenced by M::File
File
File
my_file
my_file

for 1.9 that means the new File class is defined under anonymous
class_extension module. It seems more consistent and simple.

yes it does. that makes me feel better. thanks for the explanation.

-a


#155

Yukihiro M. wrote:

… ‘funcall’ is a lisp
function name that has its own history.

Ahh, the Ruby Collage of Inspiration. Cool.

Cheers,
Daniel


#156

On Fri, 16 Jun 2006, Yukihiro M. wrote:

Yes. class_extension add features to the target class but not to the
module itself.

class C
include M
end
M.a = 42
p M.a # => 42

code.gsub! /M/, ‘C’

??

-a


#157

Yukihiro M. wrote:

I don’t. Luckily or not. For your information, ‘funcall’ is a lisp
function name that has its own history.

|Isn’t #funcall now called #instance_exec?

No, they are different.

I see. I wouldn’t otherwise have a problem with the name ‘funcall’ but
it’s a meta-programming method and as such it’s something important to
always have available. I have BasicObject class (basically the same as
BlankSlate) which clears out the Kernel methods. But some methods are
too important to remove. Thankfully all the important ones (except #dup
and #clone) start with either ‘__’ or ‘instance_’ (eg. send). But
#funcall will add another exception. It would be nicer to see a
consistant pattern in the naming of these meta-methods.

T.


#158

Hi,

In message “Re: Why the lack of mixing-in support for Class methods?”
on Fri, 16 Jun 2006 01:51:32 +0900, removed_email_address@domain.invalid writes:

|> class C
|> include M
|> end
|> M.a = 42
|> p M.a # => 42

| code.gsub! /M/, ‘C’

Yes, thank you.

						matz.

#159

On 6/15/06, removed_email_address@domain.invalid removed_email_address@domain.invalid wrote:

i am in the minority, but it bothers me. don’t get me wrong, i like the
interface - but the semantics seem odd.

Well, I agree with you on both counts - I like your semantics and
Daniel’s interface. I certainly think you’re right to raise the
scoping issues of this implementation in 1.8.

Luckily, it seems we can have our cake and eat it with ruby 1.9! :slight_smile:

And if people use Daniel’s implementation as a shim for 1.8, we now
have a clear explanation of the differences between this and what will
eventually be the official behaviour.

Gotta love this list.

Regards,
Sean


#160

Sean O’Halpin wrote:

And if people use Daniel’s implementation as a shim for 1.8, we now
have a clear explanation of the differences between this and what will
eventually be the official behaviour.

Right on. I and the Nitro project have been despretely needing a
standardized approach to this. I’ll be providing a distribution of
Daniel’s implementation in Facets until it makes its way into Ruby.

Thanks Matz, Daniel, Ara, Sean and everyone that participated in this
thread! Oh and Alder G. for starting it! (Did you get your answer?
:wink:

BTW Is this possibly the longest ruby-talk thread in history? Sheesh!
:wink:

Gotta love this list.

Indeed.

T.