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

B780ee0ee1480454a85df58536702f63?d=identicon&s=25 Alder Green (Guest)
on 2006-06-08 08:23
(Received via mailing list)
Hi

I'm confused as to why class methods aren't include'd by default along
with instance methods when mixing-in modules.

It obstructs the important orthoganility between modules and classes,
and - among other problems - thus undermines the position of mixins as
an alternative to class-based multiple inheritance.

In short, I can see a lot of poor consequence to that lack of support,
while on the other hand no good reason for it. Maybe someone would
care to elighten me?

(I'm aware of the various hacks for fudging such support, and in fact
use some of them in my code. But there are readability and
maintainability issues with those hacks for something that's supposed
to be a core feature).
D3944ff4e8bc05067a615579b6ef599b?d=identicon&s=25 Phil Tomson (Guest)
on 2006-06-08 09:20
(Received via mailing list)
On 6/7/06, Alder Green <alder.green@gmail.com> wrote:
> while on the other hand no good reason for it. Maybe someone would
> care to elighten me?
>
> (I'm aware of the various hacks for fudging such support, and in fact
> use some of them in my code. But there are readability and
> maintainability issues with those hacks for something that's supposed
> to be a core feature).
>

The main reason is because a different 'self' is involved, I would
guess.
You can use extend to mixin class methods.  Also, there's a nice idiom
for getting include to mixin both class and instance methods of a
module (though the class methods are actually in another sub-module):

module A
  def self.included receiver
    receiver.extend ClassMethods
  end

  module ClassMethods
    def foo
      "foo"
    end
  end
  def inst_method
    "instance method"
  end
end

class B
  include A
end

B.foo #=> "foo"
B.new.inst_method #=> "instance method"
B780ee0ee1480454a85df58536702f63?d=identicon&s=25 Alder Green (Guest)
on 2006-06-08 10:03
(Received via mailing list)
On 6/8/06, Phil Tomson <rubyfan@gmail.com> wrote:
> > In short, I can see a lot of poor consequence to that lack of support,
> You can use extend to mixin class methods.  Also, there's a nice idiom
>       "foo"
>
> B.foo #=> "foo"
> B.new.inst_method #=> "instance method"
>
>

Yes, I'm using this idiom in my code. Note, however, that if you want
to use A'd "class methods" from A itself, you have to add the  extra
line:

self.extend(ClassMethods)

after A::ClassMethods's definition.

Still, it's unclear to me why this very natural functionality isn't
built into the default append_features. It hinders the ease of going
from a module to a class or vice-versa, which Ruby seems to encourage.
In any case, every other aspect of switching between those two is
well-handled, so why not this one as well?  Are there plans to add it
for Ruby 2?
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-06-08 12:57
(Received via mailing list)
Hi --

On Thu, 8 Jun 2006, Alder Green wrote:

> while on the other hand no good reason for it. Maybe someone would
> care to elighten me?

It's actually a fairly specialized case.  In the general case, if a
module has a method of its own, there's no particular reason to think
that every class that mixes it in should also have that method.

For example:

   module Edible
     def self.definition
       "able to be eaten without ill effect"
     end
   end

   class Bread
     include Edible
   end

   class Bagel < Bread
   end

You don't really want Bread or Bagel reporting back their definitions
as being the same as Edible's definition.  You can arrange for that to
happen quite easily (see Phil's answer) if you want to, but you also
want to be able to have it not happen.

There's a huge amount of discussion of this in the mailing list
archives and on RCRchive.  People disagree, irreconcilably, and it's
not worth rehashing the whole thing.  But have a look at the archives
if you're interested.


David
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-08 13:00
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Thu, 8 Jun 2006 17:02:35 +0900, "Alder Green"
<alder.green@gmail.com> writes:

|Still, it's unclear to me why this very natural functionality isn't
|built into the default append_features.

Mix-in is used for several purposes and some of them can be hindered
by inheriting class methods, for example, I don't want to spill
internal methods when including the Math module.  I am not against for
some kind of inclusion that inherits class methods as well, but it
should be separated from the current #include behavior.

							matz.
567898c496278341be69087507d5ed24?d=identicon&s=25 Jeff Rose (Guest)
on 2006-06-08 13:43
(Received via mailing list)
Alder Green wrote:
> while on the other hand no good reason for it. Maybe someone would
> care to elighten me?
>
> (I'm aware of the various hacks for fudging such support, and in fact
> use some of them in my code. But there are readability and
> maintainability issues with those hacks for something that's supposed
> to be a core feature).
>


You can do this without too much trouble.  This is what I use, which is
based off some code _why posted on his blog a while back.

---- meta.rb ----


# A set of methods to help create meta-programming gizmos.
class Object
   # The metaclass is the singleton behind every object.
   def metaclass
     class << self
       self
     end
   end

   # Evaluates the block in the context of the metaclass
   def meta_eval &blk
     metaclass.instance_eval &blk
   end

   # Acts like an include except it adds the module's methods
   # to the metaclass so they act like class methods.
   def meta_include mod
     meta_eval do
       include mod
     end
   end

   # Adds methods to a metaclass
   def meta_def name, &blk
     meta_eval { define_method name, &blk }
   end

   # Defines an instance method within a class
   def class_def name, &blk
     class_eval { define_method name, &blk }
   end
end

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

require 'meta'

module Foo
   def test
     puts "test method"
   end
end

class Bar
   meta_include Foo
end

Bar.test
# >> "test method\n"


-Jeff
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-08 14:59
(Received via mailing list)
On Thu, 8 Jun 2006, Alder Green wrote:

> while on the other hand no good reason for it. Maybe someone would
> care to elighten me?
>
> (I'm aware of the various hacks for fudging such support, and in fact
> use some of them in my code. But there are readability and
> maintainability issues with those hacks for something that's supposed
> to be a core feature).
>
> --
> -Alder


module M
   def self.new
     'yikes!'
   end
   def self.alloc
     'even worse'
   end
   def self.name
     'this is getting bad'
   end
   def self.is_a?
     'i hope you did not override this'
   end
end

class C
   include M
end

-a
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-08 15:02
(Received via mailing list)
Jeff Rose wrote:

Not the same thing.

> end
>
> Bar.test
> # >> "test method\n"

Why? You can just do

  class Bar
     extend Foo
  end

   Bar.test
  # >> "test method\n"

T.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-08 15:08
(Received via mailing list)
ara.t.how...@noaa.gov wrote:

>    def self.is_a?
>      'i hope you did not override this'
>    end
> end
>
> class C
>    include M
> end

Sigh. We've been through this Ara. It's a silly example --don't use
those methods if you don;t want to override them --and what if you do?

Nonethesless, I agree with Matz. I think a simple alternative call is
the prefect compromising solution. Perhaps:

 class C
    inherit M
 end

Also, This post is kind of timely, I'be been preparing a post with
example's from Nitro on the extensive need of this behavior --you
should see the many "hacks" being used to accomplish this there --I
think at least three different techinqes are being used throughout
dozens of components.

T.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-08 15:27
(Received via mailing list)
On Thu, 8 Jun 2006 transfire@gmail.com wrote:


> Sigh. We've been through this Ara. It's a silly example --don't use those
> methods if you don;t want to override them --and what if you do?

indeed.  still - i see it being a bit anti POLS from someone's
perspective,
that's all.

> Nonethesless, I agree with Matz. I think a simple alternative call is
> the prefect compromising solution. Perhaps:
>
> class C
>   inherit M
> end

i have my own impl ;-)

> Also, This post is kind of timely, I'be been preparing a post with example's
> from Nitro on the extensive need of this behavior --you should see the many
> "hacks" being used to accomplish this there --I think at least three
> different techinqes are being used throughout dozens of components.

the one issue i see is with stateful methods - we don't currently have
'inheritable state'.  eg

   module M
     class << self
       attr 'foo'
     end
     @foo = 42
   end

   class A
     inherit M
   end

   class B < A
   end


   p M.foo #=> 42
   p A.foo #=> nil
   p B.foo #=> nil

   A.foo = 'forty-two'

   p M.foo #=> 42
   p A.foo #=> 'forty-two'
   p B.foo #=> nil


traits addresses this.  eg this works

   require 'traits'

   class M
     class_trait 'foo' => 42
   end

   class A < M
   end

   class B < A
   end


   p M.foo #=> 42
   p A.foo #=> 42
   p B.foo #=> 42

   A.foo = 'forty-two'

   p M.foo #=> 42
   p A.foo #=> 'forty-two'
   p B.foo #=> 'forty-two'


not a deal breaker - but i've found in that in many designs relying on
class
inheritence it's precisely this kind of information sharing one is
trying to
acheive via inheritence or mixing in class methods.

just food for thought.  if we start mixing in class methods then the
strange
behaviour of ruby's 'class variables' and 'class instance variables'
will
become a popular topic on this list.

cheers.

-a
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-08 16:50
(Received via mailing list)
ara.t.howard@noaa.gov wrote:
> indeed.  still - i see it being a bit anti POLS from someone's perspective,
> that's all.

Fair enough. No doubt it will come with it's own set of considerations
with which we progammers will have to become familiar.

> > from Nitro on the extensive need of this behavior --you should see the many
>      @foo = 42
>    p M.foo #=> 42
>    p A.foo #=> nil
>    p B.foo #=> nil
>
>    A.foo = 'forty-two'
>
>    p M.foo #=> 42
>    p A.foo #=> 'forty-two'
>    p B.foo #=> nil
>

I think one would need to set that up oneself using a class variable.
Rather I would expext this it to behave like it does, just as with a
class:

  class X
    def self.x
      @x
    end
    @x = 10
  end

  class Z < X
  end

  X.x  #=> 10
  Z.x  #=> nil

>
>    p M.foo #=> 42
>    p A.foo #=> 'forty-two'
>    p B.foo #=> 'forty-two'
>

You bring up your traits library all the time ;) Actually all-in-all I
think it's pretty good. Unfortuately I have this one nagging problem
with it. I think the term 'traits' is a terrible misnomer. That may
seem silly but having done some study of prototype-base OOPS,
especially Self, traits are just a totlatlly different concept to me.

T.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-08 17:09
(Received via mailing list)
On Thu, 8 Jun 2006 transfire@gmail.com wrote:

>  class Z < X
>  end
>
>  X.x  #=> 10
>  Z.x  #=> nil

right.  it's just that 'inheritence' with object generally follows this
pattern

   class B
     attr :b
     def initialize() @b = 'bar' end
   end

   class C < B
   end

   p C.new.b #=> 'bar'

which is to say there are mechanisms, namely initialize and super, for
propagating state.  no such mechanisms exist for class based state.  if
one is
proposing an 'inherit' method (which i think is a great idea) then i
think
it's important to also toss around ideas for things like
Class.class_init
and/or Module.module_init - eg hooks that are provided to accomplish
this.  my
preferred approach now is this

   module M
     module ClassMethods
       attr 'a'
       attr 'b'
     end
     module InstanceMethods
     end
     def self.included other
       other.extend ClassMethods
       other.module_eval{ include InstaneMethods }
       init other
     end
     def self.init other
       other.a = 42
       other.b = 'forty-two'
     end
   end

if we don't also consider this then the situation you describe in Nitro,
where
there a muliple ways of implimenting class method mixins, will more or
less
remain if any of those methods require state - that is to say it'd be a
shame
to make every ruby developer roll his is own way of initializing the
required
state for the module methods he could mix into his classes so easily.

> You bring up your traits library all the time ;)

yeah, not on purpose though: it just fills a lot of meta-programming and
class
inheritence niches which seems to come up often on this list.

> Actually all-in-all I think it's pretty good. Unfortuately I have this one
> nagging problem with it. I think the term 'traits' is a terrible misnomer.
> That may seem silly but having done some study of prototype-base OOPS,
> especially Self, traits are just a totlatlly different concept to me.

well - you can use the 'has' interface

   class C
     has 'c' => 42
     class_has 'b'
   end

it's just an alias - but if you hate the name...

cheers.

-a
B780ee0ee1480454a85df58536702f63?d=identicon&s=25 Alder Green (Guest)
on 2006-06-08 17:50
(Received via mailing list)
On 6/8/06, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:
> internal methods when including the Math module.  I am not against for
> some kind of inclusion that inherits class methods as well, but it
> should be separated from the current #include behavior.
>
>                                                         matz.

Hi Matz :)

I see your and Dblack's point about the need for an #include that
won't inherit the class methods. And I agree that it's probably a good
idea to keep #include behaving as it does right now. So adding a
separate #inherit seems like a very good idea.

I encountered the need for #inherit when I wrote Foo as a class, and
then later discovered I needed to have Foo features in class Bar that
already has parent Baz. It seems Ruby would be much more flexible if I
could simply:

module Fooable  # instead of class Foo
  ...
end

class Foo
  inherit Fooable
end

class Bar < Baz
  inherit Fooable
end

This is not a rare need, at least not for me. I'm pretty new to Ruby,
and alredy needed to do this 5 times. Also I'd argue current lack of
support of this encourages programmers to encapuslate functionality in
classes even when they don't need to instantiate it, and a module
would be more appropriate.

Since you don't seem averse to the idea, and there are others (below,
in this thread, and earlier in other threads) who share the same need,
what do we need to do to have #inherit added as feature?
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-08 19:38
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Fri, 9 Jun 2006 00:49:19 +0900, "Alder Green"
<alder.green@gmail.com> writes:

|I see your and Dblack's point about the need for an #include that
|won't inherit the class methods. And I agree that it's probably a good
|idea to keep #include behaving as it does right now. So adding a
|separate #inherit seems like a very good idea.

I don't like the name #inherit.  Since it is not a inheritance.

							matz.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-08 19:48
(Received via mailing list)
On Fri, 9 Jun 2006, Yukihiro Matsumoto wrote:

> I don't like the name #inherit.  Since it is not a inheritance.
i've suggested 'mixin' in the past

   module M
   end

   class C
     mixin M
   end

??

-a
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2006-06-08 19:52
(Received via mailing list)
On Jun 8, 2006, at 12:45 PM, ara.t.howard@noaa.gov wrote:

>> good
>   class C
>     mixin M
>   end

I like that.

James Edward Gray II
31ab75f7ddda241830659630746cdd3a?d=identicon&s=25 Austin Ziegler (Guest)
on 2006-06-08 20:08
(Received via mailing list)
On 6/8/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:
> On Fri, 9 Jun 2006, Yukihiro Matsumoto wrote:
> > I don't like the name #inherit.  Since it is not a inheritance.
> i've suggested 'mixin' in the past
>
>    module M
>    end
>
>    class C
>      mixin M
>    end

Um. I think that's too confusing. The problem is that we want to be
clear that:

  * #include only deals with the inclusion of instance-level methods
at the instance level.
  * #extend only deals with inclusion of instance-level methods at the
class/object level.
  * #??? includes both instance- and class-level methods at the
instance/class level.

In my mind, #mixin does not capture that, since the process of
#include *or* #extend is called mixing-in.

No, I don't have a better name. I thought of #blend, but that's just
too ... ugly.

-austin
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-08 20:27
(Received via mailing list)
ara.t.howard@noaa.gov wrote:

>
>      module ClassMethods
>      def self.init other
>        other.a = 42
>        other.b = 'forty-two'
>      end
>    end
>
> if we don't also consider this then the situation you describe in Nitro, where
> there a muliple ways of implimenting class method mixins, will more or less
> remain if any of those methods require state - that is to say it'd be a shame
> to make every ruby developer roll his is own way of initializing the required
> state for the module methods he could mix into his classes so easily.

Okay. I see what you're saying. Thouhg, I guess I'm thinking class
variables might help as far as carrying inheritable class level state.
Class variables are going to be "fixed" and made local to the
class/module right? So they will be able to be used for a class state
state. Is that right? And I think we all agree some sort of
module-based initialization could be helpful (though *I think* it's
hard to say how you do that for instance variables without thwarting
proper OOP).

> well - you can use the 'has' interface
>
>    class C
>      has 'c' => 42
>      class_has 'b'
>    end
>
> it's just an alias - but if you hate the name...

Better! *nodes head approvingly* :)

T.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-08 20:33
(Received via mailing list)
Yukihiro Matsumoto wrote:
> I don't like the name #inherit.  Since it is not a inheritance.
I knew you were going to say that ;) I actually hesitated to suggest
it, but I haven't thought of anything better. But I would like to point
out an interesting (albiet currently illegal) equivalency:

  module Beanable
    def self.pod
      "oooooo"
    end
  end

  class Beanbag
    extend (class << Beanable; self; end)
  end

T.
B780ee0ee1480454a85df58536702f63?d=identicon&s=25 Alder Green (Guest)
on 2006-06-08 22:10
(Received via mailing list)
On 6/8/06, Austin Ziegler <halostatue@gmail.com> wrote:
> ...
> No, I don't have a better name. I thought of #blend, but that's just
> too ... ugly.

I like #blend. Goes well with #blend? etc.

Some other nice alternatives from the thesaurus: meld, merge, mingle,
fuse, combine, integrate, compound.
Ad7805c9fcc1f13efc6ed11251a6c4d2?d=identicon&s=25 Alex Young (regularfry)
on 2006-06-08 22:25
(Received via mailing list)
Alder Green wrote:
> On 6/8/06, Austin Ziegler <halostatue@gmail.com> wrote:
>> ...
>> No, I don't have a better name. I thought of #blend, but that's just
>> too ... ugly.
>
> I like #blend. Goes well with #blend? etc.
>
> Some other nice alternatives from the thesaurus: meld, merge, mingle,
> fuse, combine, integrate, compound.
>
A few others:

derive (a little obscure)
evolve (I quite like that)
elaborate (too long?)
develop
gather (gets the dual nature quite nicely)
invoke (seems too active to me)
follow (like evolve, but less so)

This could go on all night :-)
Bbc4b3fca1ae3161257a8636145b424d?d=identicon&s=25 Elliot Temple (Guest)
on 2006-06-08 22:50
(Received via mailing list)
On Jun 8, 2006, at 1:23 PM, Alex Young wrote:

> derive (a little obscure)
> evolve (I quite like that)

evolve seems vague and makes people think of monkeys

-- Elliot Temple
http://www.curi.us/blog/
Bc6d88907ce09158581fbb9b469a35a3?d=identicon&s=25 James Britt (Guest)
on 2006-06-08 23:28
(Received via mailing list)
Elliot Temple wrote:
>>>
> evolve seems vague and makes people think of monkeys
Sure.  Monkey patching.



--
James Britt

"Blanket statements are over-rated"
Ff63c03fd68754adbadd2c6314646bef?d=identicon&s=25 Bill Guindon (agorilla)
on 2006-06-09 00:49
(Received via mailing list)
On 6/8/06, Elliot Temple <curi@curi.us> wrote:
> >> fuse, combine, integrate, compound.
> > A few others:
> >
> > derive (a little obscure)
> > evolve (I quite like that)
>
> evolve seems vague and makes people think of monkeys

What's wrong with that? ;)

Ok, now I have to toss some out...

engulf (seems bigger than include or extend)
completes (give me the complete list of methods)
clobber (silly, but it's likely to do that to some methods, and has
CLass/OBject mnemonic).
4feed660d3728526797edeb4f0467384?d=identicon&s=25 Bill Kelly (Guest)
on 2006-06-09 02:11
(Received via mailing list)
From: "Bill Guindon" <agorilla@gmail.com>
>> >> I like #blend. Goes well with #blend? etc.
>
> Ok, now I have to toss some out...
>
> engulf (seems bigger than include or extend)
> completes (give me the complete list of methods)
> clobber (silly, but it's likely to do that to some methods, and has
> CLass/OBject mnemonic).

enchant ?  enliven ?  enfold ?  incorporate ?  induct ?  ;)

What about import ?


Regards,

Bill
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-09 02:23
(Received via mailing list)
transfire@gmail.com wrote:
>     end
>   end
>
>   class Beanbag
>     extend (class << Beanable; self; end)
>   end

Considering the above (which by the way should also have an 'include
Beanable'), a notation that has some similarity and is available for
use:

   class Beanbag
     self << Beanable
   end

T.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-09 02:48
(Received via mailing list)
On Fri, 9 Jun 2006, Bill Kelly wrote:

> What about import ?

i like it.  i think i may have come up with that one a while back too.
that,
along with 'mixin' - are my favourites so far.

cheers.

-a
31ab75f7ddda241830659630746cdd3a?d=identicon&s=25 Austin Ziegler (Guest)
on 2006-06-09 03:22
(Received via mailing list)
On 6/8/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:
> On Fri, 9 Jun 2006, Bill Kelly wrote:
> > What about import ?
> i like it.  i think i may have come up with that one a while back too.  that,
> along with 'mixin' - are my favourites so far.

Sensible. You include functionality from a module, you extend an
object with a module, and you import a module wholesale.

Or something nonsensical like that. ;)

-austin
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-09 04:26
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Fri, 9 Jun 2006 09:22:55 +0900, transfire@gmail.com writes:

|Considering the above (which by the way should also have an 'include
|Beanable'), a notation that has some similarity and is available for
|use:
|
|   class Beanbag
|     self << Beanable
|   end

I like this more than others, but I worry about that this is less
descriptive than other at the same time.  For example, how one can
know whether "include" does not injects module methods, where "<<"
does.

							matz.
C1bcb559f87f356698cfad9f6d630235?d=identicon&s=25 Hal Fulton (Guest)
on 2006-06-09 04:38
(Received via mailing list)
Yukihiro Matsumoto wrote:
> |     self << Beanable
> |   end
>
> I like this more than others, but I worry about that this is less
> descriptive than other at the same time.  For example, how one can
> know whether "include" does not injects module methods, where "<<"
> does.


     class Beanbag
       include! Beanable
     end


;)

Hal
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-06-09 04:41
(Received via mailing list)
On Jun 8, 2006, at 10:25 PM, Yukihiro Matsumoto wrote:

> |     self << Beanable
> |   end
>
> I like this more than others, but I worry about that this is less
> descriptive than other at the same time.  For example, how one can
> know whether "include" does not injects module methods, where "<<"
> does.
>
> 							matz.
>

well we have class << self, which involves singleton methods

why not
class Beanbag
  include << Beanable
end

which would also involve singleton methods? (Of course then include
has to be a keyword (or "include <<" at least))
D3944ff4e8bc05067a615579b6ef599b?d=identicon&s=25 Phil Tomson (Guest)
on 2006-06-09 08:53
(Received via mailing list)
On 6/8/06, Austin Ziegler <halostatue@gmail.com> wrote:
> >    end
> In my mind, #mixin does not capture that, since the process of
> #include *or* #extend is called mixing-in.
>
> No, I don't have a better name. I thought of #blend, but that's just
> too ... ugly.
>


What about a this approach:

module A
  def A.foo
    "this method wouldn't get mixed in"
  end
  def self.bar
    "this method would get mixed in"
  end
end

class B
  include A
end

B.bar #=> "this method would get mixed in"
B.foo #=> no method error

So the idea would be that if you use 'def self.<method_name>'  the
method would be mixed in, but if you use 'def <module name>.<method
name>' it would not be mixed in.


...I'm not sure how easy/hard/possible this would be to implement,
though, or if it's even practical.

Another approach would be to so something like:

module A
  def self.not_mixable
    "not mixed in"
  end

  mixable
  def self.mixed
    "mixed in"
   end
end

class B
  include A
end

B.mixed #=> "mixed in"
B.not_mixable #=> no method error

Phil
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-06-09 12:45
(Received via mailing list)
Hi --

On Fri, 9 Jun 2006, Phil Tomson wrote:

>
>
>
> ...I'm not sure how easy/hard/possible this would be to implement,
> though, or if it's even practical.

I think that's a dangerous path to go down.  self is really just an
alias for a particular object at a particular time, and having it be
more "magic" than that could get messy.


David
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-06-09 13:00
(Received via mailing list)
Hi --

On Fri, 9 Jun 2006, Logan Capaldo wrote:

>> |use:
>> 							matz.
>>
>
> well we have class << self, which involves singleton methods
>
> why not
> class Beanbag
> include << Beanable
> end
>
> which would also involve singleton methods?

I'm not sure << really evokes "connected in some way with singleton
methods", though.  Then again, I'm not sure what's wrong with
"extend", so I'm probably a bit out of the loop on this discussion.

> (Of course then include has to be a keyword (or "include <<" at
> least))

Not necessarily:

class MyModule
   def initialize
     @list = []
   end

   def include(*args)
     if args.size.zero?
       @list
     else
       @list.concat(args)
     end
   end
end

m = MyModule.new
m.instance_eval {

   include "a", "b"
   include << "c"

   p @list      # ["a", "b", "c"]
}


David
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2006-06-09 14:44
(Received via mailing list)
On Jun 9, 2006, at 5:58 AM, dblack@wobblini.net wrote:

> Then again, I'm not sure what's wrong with
> "extend", so I'm probably a bit out of the loop on this discussion.

Well, extend takes the instance methods of a module and makes them
class methods on the receiver.  People are asking for a natural way
to mix in the class methods of a module, preferably while mixing in
the instance methods as well (as include currently does).  In short,
they want to turn this idiom into a one liner:

module MixinForInstanceAndClassMethods
   module ClassMethods
     # ... class methods ...
   end

   extend ClassMethods

   def self.included(receiver)
     receiver.extend(ClassMethods)
   end

   # ... instance methods ...
end

class Receiver
   include MixinForInstanceAndClassMethods
end

Hope that helps.

James Edward Gray II
Ba2582cd50a59359ac3f7305ad2a0429?d=identicon&s=25 ReggW (Guest)
on 2006-06-09 15:08
Hal Fulton wrote:

>
>
>      class Beanbag
>        include! Beanable
>      end

I like this and it fits into the current scheme.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-09 16:18
(Received via mailing list)
Yukihiro Matsumoto wrote:

> I like this more than others, but I worry about that this is less
> descriptive than other at the same time.  For example, how one can
> know whether "include" does not injects module methods, where "<<"
> does.

Unfortuantly, as it is, we cannot know. I have seen some bad practices
in the overriding of #include which do not ever inject the module. It's
weird becuase Ruby reports the module as an ancestor though the module
is totaly devoid of any content, i.e. The #include call was just used
as a "trick" to do something else (usually using class_eval to add
methods directly to the base class/module).

Short of turning include and extend into keywords, I'm not sure there's
any way to ensure proper behavior. And if that were done, it would
likely create other limitations that may have been useful to more
experienced Rubyists.

T.
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-06-09 16:22
(Received via mailing list)
Hi --

On Fri, 9 Jun 2006, James Edward Gray II wrote:

> On Jun 9, 2006, at 5:58 AM, dblack@wobblini.net wrote:
>
>> Then again, I'm not sure what's wrong with
>> "extend", so I'm probably a bit out of the loop on this discussion.
>
> Well, extend takes the instance methods of a module and makes them class
> methods on the receiver.  People are asking for a natural way to mix in the
> class methods of a module, preferably while mixing in the instance methods as
> well (as include currently does).  In short, they want to turn this idiom
> into a one liner:

I know (believe me, I've been through many iterations of this
discussion :-)  What I really mean is: I don't see what's wrong with:

   module SomeMethodsIWantSomeClassesToHave
   end

   module SomeInstanceMethods
   end

   class C
     extend SomeMethodsIWantSomeClassesToHave
     include InstanceMethods
   end

In other words, I prefer a module design that doesn't fuse different
modularities together in the first place.


David
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-06-09 16:22
(Received via mailing list)
On Fri, 9 Jun 2006, dblack@wobblini.net wrote:

>  module SomeMethodsIWantSomeClassesToHave
>  end
>
>  module SomeInstanceMethods
>  end
>
>  class C
>    extend SomeMethodsIWantSomeClassesToHave
>    include InstanceMethods

s/Instance/SomeInstance/ :-)


David
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-09 16:57
(Received via mailing list)
On Fri, 9 Jun 2006 dblack@wobblini.net wrote:

>    extend SomeMethodsIWantSomeClassesToHave
>    include InstanceMethods
>  end
>
> In other words, I prefer a module design that doesn't fuse different
> modularities together in the first place.

sometimes they belong together logically:

   module Sync
     require 'sync'

     def self.sync m, which = :EX
       module_eval <<-code
         alias_method "__#{ m }__", "#{ m }"

         def #{ m }(*a, &b)
           sync_init
           synchronize(:#{ which }){ __#{ m }__(*a, &b) }
         end
       code
     end

     def sync_init
       extend Sync_m unless Sync_m === self
     end
   end

   class C
     import Sync
     sync 'method_that_needs_to_be_thread_safe'
     sync 'another_method_that_needs_to_be_thread_safe', :SH
   end

obviously one can break them apart, but it's un-natural.  in general
anytime
the imported module introduced instance methods which rely on class
state or
class methods or, as this case does, introduces class methods which rely
in
instance state/methods, it makes logical sense to keep it all in one
bundle.
for me logical orthogonality is by far ruby's greatest asset and i hate
doing
illogical things in my ruby code - i save that for fortran.

in any case i don't think anyone thinks anything is 'wrong' with
splitting it
up, but it clearly violates DRY to do this

   module M
     module ClassMethods
     end
     module InstanceMethods
     end
   end
   class A
     include M::InstanceMethods
     extend M::ClassMethods
   end
   class B
     include M::InstanceMethods
     extend M::ClassMethods
   end
   class C
     include M::InstanceMethods
     extend M::ClassMethods
   end

vs this

   module M
     module ClassMethods
     end
     module InstanceMethods
     end
     def self.included other
       other.extend ClassMethods
       other.module_eval{ include InstanceMethods }
     end
   end
   class A
     include M
   end
   class B
     include M
   end
   class C
     include M
   end

plus, the first case is annoying.  if it weren't, people wouldn't be
rolling
their own shortcuts left and right - which is kind of what this thread
is
about.

kind regards.

-a
B780ee0ee1480454a85df58536702f63?d=identicon&s=25 Alder Green (Guest)
on 2006-06-09 20:00
(Received via mailing list)
On 6/9/06, transfire@gmail.com <transfire@gmail.com> wrote:
> >     def self.pod
> use:
>
>    class Beanbag
>      self << Beanable
>    end
>
> T.
>
>
>

You can say in a comment or a discussion: "check if Fooable is
imported* into Bar". But can you "check if Fooable is
double-lessed-than into Bar"?

Having both module and instance methods imported* is a concept. Just
like inclusion is right now. Concepts should have a name, imho.

* integrated/combined/merged/...
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-09 20:07
(Received via mailing list)
On Sat, 10 Jun 2006, Alder Green wrote:

> You can say in a comment or a discussion: "check if Fooable is
> imported* into Bar". But can you "check if Fooable is
> double-lessed-than into Bar"?
>
> Having both module and instance methods imported* is a concept. Just
> like inclusion is right now. Concepts should have a name, imho.
>
> * integrated/combined/merged/...

assimilated?  borged?

;-)

-a
Ff63c03fd68754adbadd2c6314646bef?d=identicon&s=25 Bill Guindon (agorilla)
on 2006-06-09 20:17
(Received via mailing list)
On 6/9/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:
>
> assimilated?  borged?

incorporated!  _then_ Ruby will be Enterprise-ready ;)
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2006-06-09 20:38
(Received via mailing list)
ara.t.howard@noaa.gov wrote:
...
> plus, the first case is annoying.  if it weren't, people wouldn't be
> rolling
> their own shortcuts left and right - which is kind of what this thread is
> about.

Here's another shortcut, dunno how original it is. I don't like the
#import (or #include!) suggestions because they take control away from
the module. In most cases, the module will know best which (if any)
class methods to contribute.

class Module
  def included_class_methods(&bl)
    if bl
      included_class_methods_module.module_eval(&bl)
    else
      included_class_methods_module.instance_methods
    end
  end

  def included(cl)
    cl.extend included_class_methods_module
  end

  private
  def included_class_methods_module
    @included_class_methods_module ||= Module.new
  end
end

module M
  included_class_methods do
    def bar; "BAR"; end
  end
  def self.zap; "ZAP"; end
  def foo; "FOO"; end
end

class C
  include M

  p bar

  begin
    zap
  rescue
    puts "Can't call C.zap"
  end
end

p C.new.foo

p M.included_class_methods

__END__

Output:

"BAR"
Can't call C.zap
"FOO"
["bar"]
B780ee0ee1480454a85df58536702f63?d=identicon&s=25 Alder Green (Guest)
on 2006-06-09 21:45
(Received via mailing list)
On 6/9/06, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:
> Here's another shortcut, dunno how original it is. I don't like the
> #import (or #include!) suggestions because they take control away from
> the module. In most cases, the module will know best which (if any)
> class methods to contribute.

Assuming #import would have a callback-hook like #included
(#imported?), how would the locus of control shift from where it is
right now?

In a somewhat related note:

Perhaps #import should call #include. Or maybe they would be entirely
seperate: #import for module-level methods, #include for
instance-level methods. Of course, this means that in the most common
case you'd have the unDRYish idiom:

import  Fooable
include Fooable

But it's still much better than the mass of boilerplate code we need
to paste there right now. Another suggestion:

import Fooable, :include => false

To import only the module level methods. I.e. :include => true by
default.
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2006-06-09 22:02
(Received via mailing list)
Alder Green wrote:
> On 6/9/06, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:
>> Here's another shortcut, dunno how original it is. I don't like the
>> #import (or #include!) suggestions because they take control away from
>> the module. In most cases, the module will know best which (if any)
>> class methods to contribute.
>
> Assuming #import would have a callback-hook like #included
> (#imported?), how would the locus of control shift from where it is
> right now?

The #imported callback might help (and it would inevitably be requested
if it were not provided), but then the module author has to decide how
to handle each of #included, #imported, and #extended.

I'm still leaning towards having just one method, include, that is
available to client classes to "use" the module in typical cases. The
module decides what gets included at the instance and class levels.
B780ee0ee1480454a85df58536702f63?d=identicon&s=25 Alder Green (Guest)
on 2006-06-09 23:19
(Received via mailing list)
On 6/9/06, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:

> I'm still leaning towards having just one method, include, that is
> available to client classes to "use" the module in typical cases. The
> module decides what gets included at the instance and class levels.

The major lack right now is a way to "include" module methods. Even if
the module is to be the one deciding which methods get exported, it
does not have a straightforward way to export its own self-methods.
The lack of such a way right now forces us to various underhanded
hacks, e.g. to first ill-define those module-methods as instance
methods, and then use #extend in various unnatural ways, ending up
with a lot of boilerplate code and duplicated, redundant instance
methods no-one is ever going to use directly (the ugly ClassMethods
module with all its krufty instance-methods would remain in the
namespace).

> The #imported callback might help (and it would inevitably be requested
> if it were not provided), but then the module author has to decide how
> to handle each of #included, #imported, and #extended.

I agree, the need to handle 3 cases is somewhat icky. It's also icky
right now with both #included and #extended to block.

I'm not sure how prevalent is the need to limit the ways functionality
in a module can be exported. I never had it, and most of the responses
in the thread are about the opposite need (which I did share several
times) - to allow functionality in the module to propagate more
freely.

So I hope we're not providing here for some hypothetical need absent
from reality. Also, arguably, if you're doing something unnatural like
limiting access to your module's functionality, you should be the one
bothering to secure all hatches (not that it would actually prevent
anyone from hacking it out quite easily... what you're talking about
is more like a warning-system really, a sort of recommendation).

I suspect it should also be possible to easily define macro methods
for auto-generating #included, #imported, and #extended. Which is
better than the state for #import, whose lack cannot be filled by
macros alone, and requires copy-pasting code chunks to each module,
and/or unnatural changes to the way those modules are defined.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-10 04:16
(Received via mailing list)
Joel VanderWerf wrote:
> class methods to contribute.
Hey, Joel. Have a look at Facets' class_inherit.rb. It is a complete
implementation of what you suggest.

T.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-10 14:25
(Received via mailing list)
>> I'm still leaning towards having just one method, include, that is
>> available to client classes to "use" the module in typical cases. The
>> module decides what gets included at the instance and class levels.
>
> The major lack right now is a way to "include" module methods. Even if
> the module is to be the one deciding which methods get exported, it
> does not have a straightforward way to export its own self-methods.

I am suddenly reminded of the idea non-inherited methods --a way to
sepcify that a method is not be inherited through sublcassing or
inclusion. The idea being that some methods might just exist to serve
other methods and should not be apart of the class/module's interface
at all, not even for subclasses --sort of a "superprivate". So if we
further extrapolate, this concept allows control of what a module will
provide upon inclusion at the instance level. Might we not do the same
at the class level, but in the the case of a module we need the
opposite control (because the default is not to "extend") --a sort of
"superpublic".

  module M
    class << self
      def foo ; end
      extensible
      def bar ; end
    end
    def bar ; end
    uninheritable
    def foo ; end
  end

  Class X
    include M
  end

  X.foo  #=> error
  X.bar  #=> nil
  X.new.foo  #=> error
  X.new.bar  #=> nil

This way then we need only use #include for all forms of "bevahiorial
importing" and it is up to the module/class to decide what it provides
--where the responsibility really belongs.

T.
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-10 18:28
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Fri, 9 Jun 2006 11:25:53 +0900, Yukihiro Matsumoto
<matz@ruby-lang.org> writes:

||   class Beanbag
||     self << Beanable
||   end
|
|I like this more than others, but I worry about that this is less
|descriptive than other at the same time.  For example, how one can
|know whether "include" does not injects module methods, where "<<"
|does.

But I am still not sure if we need to provide the way to inject module
methods to a class's singleton class at the same time instance methods
are inherited to the class.  Could somebody elaborate?  It seems that
having two separate modules (one to include for instance methods and
another to extend for class methods) is more natural for me.

							matz.
Ced5fff44ff8929fc974012ea108b284?d=identicon&s=25 Sergey Volkov (rf-vsv)
on 2006-06-11 05:34
(Received via mailing list)
----- Original Message -----
From: "Yukihiro Matsumoto" <matz@ruby-lang.org>
To: "ruby-talk ML" <ruby-talk@ruby-lang.org>
Sent: Saturday, June 10, 2006 12:28 PM
Subject: Re: Why the lack of mixing-in support for Class methods?


> [skip]
>
> But I am still not sure if we need to provide the way to inject module
> methods to a class's singleton class at the same time instance methods
> are inherited to the class.  Could somebody elaborate?  It seems that
> having two separate modules (one to include for instance methods and
> another to extend for class methods) is more natural for me.
>
> matz.

It's natural and more "perfect".
Perfect means "nothing can be removed", not "everything was added",
so why complicate the language by adding one more shortcut if required
functionality is already available and can be implemented in library?
Who likes Ruby to follow C++, CommonLisp, Java, Perl way?
May be it's time to remove extra features to make Ruby flawless?

Sergey
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-11 08:13
(Received via mailing list)
Yukihiro Matsumoto wrote:

> But I am still not sure if we need to provide the way to inject module
> methods to a class's singleton class at the same time instance methods
> are inherited to the class.  Could somebody elaborate?  It seems that
> having two separate modules (one to include for instance methods and
> another to extend for class methods) is more natural for me.

I think the clearest use is with DSLs that also has useful instance
methods. Currently DSLs of this sort can only be provided via
subclasses. As you say, you can split it into two modules but if the
methods go together inextrobaly, then this is very inconvenient --and
unacceptably so when building frameworks and asking others to make use
of such tools. But sometimes it goes beyond mere inconvenience b/c an
instance method might call on a class method. The most basic example of
this kind of inter-relationship looks like this:

  module M
    class << self
      attr_accessor :foo
    end
    def foo
      self.class.foo
    end
  end

  class X
    self << M
  end

It's a class level setting, but with a way to easily access it from the
instance level. To split this up into two modules is clearly a forced
concession.

  module Mc
      attr_accessor :foo
  end

  module Mi
    def foo
      self.class.foo
    end
  end

  class X
    extend Mc
    include Mi
  end

T.
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-11 14:24
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Sun, 11 Jun 2006 15:09:51 +0900, transfire@gmail.com writes:

|I think the clearest use is with DSLs that also has useful instance
|methods. Currently DSLs of this sort can only be provided via
|subclasses.

I still have difficulties to imagine the concrete situation.

|  module M
|    class << self
|      attr_accessor :foo
|    end
|    def foo
|      self.class.foo
|    end
|  end

Do we have to allow M.foo?  I fell like you need to a way to add class
methods and instance methods at once, but it doesn't have to (or maybe
it shouldn't) be module methods inclusion.

|It's a class level setting, but with a way to easily access it from the
|instance level. To split this up into two modules is clearly a forced
|concession.
|
|  module Mc
|      attr_accessor :foo
|  end
|
|  module Mi
|    def foo
|      self.class.foo
|    end
|  end
|
|  class X
|    extend Mc
|    include Mi
|  end

If you don't need M.foo and M.foo= in above example (while you
definitely need X.foo and X.foo=), Mc and Mi solution is the way to
go.  Redundancy can be removed by some kind of meta programming.

							matz.
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-11 14:42
(Received via mailing list)
Yukihiro Matsumoto wrote:
> Redundancy can be removed by some kind of meta programming.

This could do the job:

   class Module
     def class_methods(&block)
       @class_methods = block
     end

     def included(mod)
       (class << mod; self; end).module_eval(&@class_methods)
     end
   end

   module Mod
     class_methods do
       def foo
         "FOO"
       end
     end

     def bar
       "BAR"
     end
   end

   class Test
     include Mod
   end

   Test.foo      #=> "FOO"
   Test.new.bar  #=> "BAR"


Cheers,
Daniel
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-11 15:44
(Received via mailing list)
Yukihiro Matsumoto wrote:
>
> |  end
> |  end
>
> If you don't need M.foo and M.foo= in above example (while you
> definitely need X.foo and X.foo=), Mc and Mi solution is the way to
> go.  Redundancy can be removed by some kind of meta programming.

The problem runs deeper than this. Having to depend on "some kind of
meta programming" is not as simple as it might seem. The complexity can
grow. Take for example my implementation of Annotations. Ex-

  module M
    def x ; "foo" ; end
    ann :x, :type => String
  end

  class X
    include M
  end

An annotation stores metadata about instance methods and hence accessed
at the class-level. They are also "inheritable", ie. class X refers
back to M's annotations:

  X.a_x  #=> #<Annotation type=String>

This is a clear example of where the instance-level is tied to the
class-level in such a way that they must both go along with each other.

In my experience the main thing that drives us to use ClassMethods and
like "hacks" is not  that it can't be done using a two module
extend/include approach, but becuase we don't want to trouble our users
with the differentiation -- docs like:

  NOTE: This module is designed to be used with #extend (not #include)
  when  "extending" classes (though you must use #include when
  "extending" it to modules which subsequently must then also use
  #extend).

This may seem excessive, but not everyone is a Ruby expert. And it only
becomes worse to tell someone thay have to both #include the module AND
#extend it's extensible counter-part module to get full functionality.

As you say, meta-programming can take care of it, but the biggest
problem with meta-programming approaches is that everyone is using
there own variation. They may use #included, they may override
#append_features, they may override #include itself, or some other
trick. And like I've said I've seen code go so far as to paste methods
directly into a class via the included callback --all becuase this
distiinctin between extend and include and how to handle it (or hack it
as the case may be) was clear to the programmer.

T.
F0223b1193ecc3a935ce41a1edd72e42?d=identicon&s=25 zdennis (Guest)
on 2006-06-11 15:54
(Received via mailing list)
Yukihiro Matsumoto wrote:
> I don't like the name #inherit.  Since it is not a inheritance.
>

Why change the name of include, why not just give it some options. The
behavior is still the same, it is just the scope (singleton or instance
level methods) that is changing.

  include Foo # current behavior
              # (more explicitly 'include Foo, :instance_methods
  include Foo, :singleton_methods # include only singleton methods
  include Foo, :all # include both instance and singleton methods

I think it makes more sense to reuse the name include for this rather
then a new name, since the behavior isn't changing. Only the scope it
applies to.

One possible drawback of this is that it would always include singleton
methods at the class-level for the including class. And someone wouldn't
be able to use this to include a singleton method as an instance method
on a class. I personally wouldn't want to do this (seems way to
confusing), but perhaps someone else does.

Zach
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-11 15:54
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Sun, 11 Jun 2006 22:43:11 +0900, transfire@gmail.com writes:

|As you say, meta-programming can take care of it, but the biggest
|problem with meta-programming approaches is that everyone is using
|there own variation.

Don't get me wrong.  I didn't say that I wouldn't do nothing, and let
you help yourself using meta-programming features.  I'd happy to add
the standard feature to achieve your goal, if it really is a generic
requirement.  I like the solution that Daniel has shown in
[ruby-talk:196730].

The point is I want to make sure which approach is the way to go.

							matz.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-11 16:04
(Received via mailing list)
Daniel Schierbeck wrote:
>      def included(mod)
>
>    Test.new.bar  #=> "BAR"
Daniel! I think you actually make my point! Matz, see what Daniel has
done here? --dumping the class methods directly into the class. This is
the kind of thing I see happening in other peoples code.

This really has nothing to do with the *capability* to meta-code a
solution (I have done so myself, of coure), it's that people don't
fully understand what really needs to happen, or understand the
distinctinctive use of extend vs. include. It may seem "intuitive" for
you since you have a complete understanding of Ruby underthehood. But
it's far from intuitive for others.

BTW, Daniel, have a look as Facets' classmethods.rb or class_inherit.rb
for a better idea of how to do what you are suggesting.

T.
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-06-11 16:51
(Received via mailing list)
Hi --

On Sun, 11 Jun 2006, Yukihiro Matsumoto wrote:

> you help yourself using meta-programming features.  I'd happy to add
> the standard feature to achieve your goal, if it really is a generic
> requirement.  I like the solution that Daniel has shown in
> [ruby-talk:196730].

It looks reasonable though I would recommend not calling the method
"class_methods".  That has the effect of freezing, in the language,
the status and purpose of singleton methods on module and class
objects.  I know that "class methods" is of course a conventional way
to refer to those methods, but I'd be sorry to see it introduced at
the language level at the expense of the generality of the current
design.


David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

See what the readers are saying about "Ruby for Rails"!
http://www.rubypowerandlight.com/quotes
B780ee0ee1480454a85df58536702f63?d=identicon&s=25 Alder Green (Guest)
on 2006-06-11 16:57
(Received via mailing list)
On 6/11/06, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:
> you help yourself using meta-programming features.  I'd happy to add
> the standard feature to achieve your goal, if it really is a generic
> requirement.  I like the solution that Daniel has shown in
> [ruby-talk:196730].
>
> The point is I want to make sure which approach is the way to go.
>
>                                                         matz.
>
>

IMHO, the best approach in this thread is the access-control style
notation suggested by transfire:

>
> importing" and it is up to the module/class to decide what it provides
> --where the responsibility really belongs.

While this certainly needs to be thought about and refined, I think a
good implementation will not only answer the need at hand, but also
contribute to the cohesiveness of the mixin concept, while planting
the locus of control firmly within the mixin module.

I.e. it's a very elegant way for the mixin module to determine exactly
what functionality gets included in the reciever, whether it is the
default instance methods, a combination of instance methods and class
methods, maybe even just the class methods, or some subset of instance
methods and class methods. Very nice in and of itself, if provided
with a sensible default which would implicitly do the right thing for
common uses.

It also avoids what I see as the major problem with adding #import:
the degradation of the cohesiveness of the inclusion concept. We
understand what it means when a class #includes Enumerable right now.
But what meaning would we ascribe to it #importing Enumerable? How is
#import different from #include?  Would we now need to check both
where we before checked only for inclusion?  And what if we allow the
reciever to ask only for the class methods?  Thus the neat mixin
concept risks sprouting too many special cases so as to become
meaningless. Transfire's suggestion keeps it cohesive.

Another nice thing: it resembles the access control syntax
(public/protected/private) which is conceptually similar to inclusion
control.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-11 17:01
(Received via mailing list)
Yukihiro Matsumoto wrote:
> you help yourself using meta-programming features.  I'd happy to add
> the standard feature to achieve your goal, if it really is a generic
> requirement.

> I like the solution that Daniel has shown in [ruby-talk:196730].

He he. That's ironic. Yes, Daniels solution is the right direction for
the best meta-programming approach, but it still has some problems (as
I pointed out in my last post).

> The point is I want to make sure which approach is the way to go.

Ah, I see. Cool. Well, Maybe that approach is the best way then. You
can look at Facets, classmethod.rb or classinherit.rb for a full
rendition of that techinque. The two are identical, BTW. They just
differ in terminology (though I'm now thinking 'extensible' might be a
much better term).

On the other hand, I can't help but wonder if a module's "class-level"
were instead a "module-level", --a module instead of a class. Or at
least if those methods were delegated to an extending module but
transaprently, underthehood. Then this might actually make sense:

  module M
    module << self
      ...
    end
  end

And it would be easy enough to write:

  def include_and_extend( mod )
    include mod
    extend (module << mod; self; end)
  end

An interesting thought.

Thanks,
T.
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2006-06-11 17:08
(Received via mailing list)
On Jun 11, 2006, at 7:42 AM, Daniel Schierbeck wrote:

> Yukihiro Matsumoto wrote:
>> Redundancy can be removed by some kind of meta programming.
>
> This could do the job:

Here's another idea:

 >> class Module
 >>   def included(receiver)
 >>     receiver.extend(const_get(:ClassMethods)) if
const_defined? :ClassMethods
 >>   end
 >> end
=> nil
 >> module Test
 >>   module ClassMethods
 >>     def test
 >>       "I'm a class method."
 >>     end
 >>   end
 >>   def test
 >>     "I'm an instance method."
 >>   end
 >> end
=> nil
 >> class MyTest
 >>   include Test
 >> end
=> MyTest
 >> MyTest.test
=> "I'm a class method."
 >> MyTest.new.test
=> "I'm an instance method."

James Edward Gray II
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-11 17:42
(Received via mailing list)
James Edward Gray II wrote:
>  >>   module ClassMethods
>  >>   include Test
>  >> end

I'm not too fond of the nested module approach -- I think it's cleaner
to use a method. But that's a matter of opinion, of course.


Daniel
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-11 17:42
(Received via mailing list)
transfire@gmail.com wrote:
> BTW, Daniel, have a look as Facets' classmethods.rb or class_inherit.rb
> for a better idea of how to do what you are suggesting.

Actually, that solution seems overly complicated -- that may be for
performance reasons, but if we were to disregard those (as we have a
tendency to do,) I like my solution better.


Daniel
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-11 17:46
(Received via mailing list)
dblack@wobblini.net wrote:
> It looks reasonable though I would recommend not calling the method
> "class_methods".  That has the effect of freezing, in the language,
> the status and purpose of singleton methods on module and class
> objects.  I know that "class methods" is of course a conventional way
> to refer to those methods, but I'd be sorry to see it introduced at
> the language level at the expense of the generality of the current
> design.

I thought the same when I wrote it, but I couldn't come up with a better
name. It's actually hard to pinpoint a reasonable one...


Daniel
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2006-06-11 18:11
(Received via mailing list)
On Jun 11, 2006, at 10:40 AM, Daniel Schierbeck wrote:

>>  >>   module ClassMethods
>>  >>   include Test
>>  >> end
>
> I'm not too fond of the nested module approach -- I think it's
> cleaner to use a method. But that's a matter of opinion, of course.

Oh well, to each their own.

I prefer the nested module approach because:

1.  I can envision the threads here where we try to explain when to
define class methods with and without the method.
2.  It has a been a common Ruby idiom for literally years, so history
works in our favor.

James Edward Gray II
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-11 18:26
(Received via mailing list)
Daniel Schierbeck wrote:
> transfire@gmail.com wrote:
> > BTW, Daniel, have a look as Facets' classmethods.rb or class_inherit.rb
> > for a better idea of how to do what you are suggesting.
>
> Actually, that solution seems overly complicated -- that may be for
> performance reasons, but if we were to disregard those (as we have a
> tendency to do,) I like my solution better.

I'm not sure if you understand the important difference though --it's
not just a differnce in coding, but in actuall functionality. Your
approach has a side effect you might not have considered. You see
you're evaluating the code directly into the base class/module. In
effect you copy the methods rather than include/extend. What happens is
that if you were to define the same method in your class, you would
over-write it completely. You could not use #super to "call-up" to the
module version. In other words your approach might seem less complicate
and thus more elegant, but it actually thwarts the use of
"inheritance".

T.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-11 18:51
(Received via mailing list)
On Mon, 12 Jun 2006, James Edward Gray II wrote:

> Oh well, to each their own.
>
> I prefer the nested module approach because:
>
> 1.  I can envision the threads here where we try to explain when to define
> class methods with and without the method.
> 2.  It has a been a common Ruby idiom for literally years, so history works
> in our favor.
>
> James Edward Gray II

+1

i use this already, it's very flexible and does 'the right thing':


     harp:~ > cat inheritable.rb
     module Inheritable
       Inherit = lambda do |this, other|
         cm = this.const_get 'ClassMethods' rescue nil
         im = this.const_get 'InstanceMethods' rescue nil
         other.extend cm if cm
         other.module_eval{
           include im if im
           extend RecursiveInherit
         }
       end

       module RecursiveInherit
         def included other
           Inherit[self, other]
           super
         end
       end

       extend RecursiveInherit
     end


     if $0 == __FILE__
       module M
         include Inheritable
         module ClassMethods
           def foo() 42 end
         end
       end
       class C
         include M
       end
       p C.foo



       module A
         include Inheritable
         module ClassMethods
           def bar() 'forty-two' end
         end
         module InstanceMethods
           def foobar() 42.0 end
         end
       end
       module B
         include A
       end
       class K
         include B
       end
       p K.bar
       p K.new.foobar
     end


     harp:~ > ruby inheritable.rb
     42
     "forty-two"
     42.0


perhaps a simple RCR for inheritable.rb?

-a
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-06-11 19:07
(Received via mailing list)
Hi --

On Mon, 12 Jun 2006, Daniel Schierbeck wrote:

> name. It's actually hard to pinpoint a reasonable one...
Which might be telling us something.... :-)


David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

See what the readers are saying about "Ruby for Rails"!
http://www.rubypowerandlight.com/quotes
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-11 20:49
(Received via mailing list)
transfire@gmail.com wrote:
> I'm not sure if you understand the important difference though --it's
> not just a differnce in coding, but in actuall functionality. Your
> approach has a side effect you might not have considered. You see
> you're evaluating the code directly into the base class/module. In
> effect you copy the methods rather than include/extend. What happens is
> that if you were to define the same method in your class, you would
> over-write it completely. You could not use #super to "call-up" to the
> module version. In other words your approach might seem less complicate
> and thus more elegant, but it actually thwarts the use of
> "inheritance".

What I like about my solution is the interface -- the implementation was
something I just jotted down. This would of course be better (feel free
to point out any errors):

   class Module
     def class_methods(&block)
       @class_methods ||= Module.new
       @class_methods.module_eval(&block)
     end

     def included(mod)
       mod.extend(@class_methods)
     end
   end

That way you don't need to have a constant (which clutters the
namespace.)


Cheers,
Daniel
Bf6862e2a409078e13a3979c00bba1d6?d=identicon&s=25 Gregory Seidman (Guest)
on 2006-06-11 21:35
(Received via mailing list)
On Mon, Jun 12, 2006 at 03:48:14AM +0900, Daniel Schierbeck wrote:
[...]
} What I like about my solution is the interface -- the implementation
was
} something I just jotted down. This would of course be better (feel
free
} to point out any errors):
}
}   class Module
}     def class_methods(&block)
}       @class_methods ||= Module.new
}       @class_methods.module_eval(&block)
}     end
}
}     def included(mod)
}       mod.extend(@class_methods)
}     end
}   end
}
} That way you don't need to have a constant (which clutters the
namespace.)

That has two problems. First off, if you don't call class_methods before
you first include the module (e.g. you want to reopen the module later
to
add class methods), the included method will fail since @class_methods
is
nil. Also, including the module in another module will not behave as
expected.

See http://redcorundum.blogspot.com/2006/06/mixing-in-...
for code and an explanation. It's similar to what you have, except:

- a little more bulletproof
- manages inclusion in modules gracefully
- requires an explicit directive to provide the
  class method mixin functionality
- provides a hook to put code in included()

} Cheers,
} Daniel
--Greg
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-11 22:15
(Received via mailing list)
Gregory Seidman wrote:
> ... if you don't call class_methods before
> you first include the module (e.g. you want to reopen the module later to
> add class methods), the included method will fail since @class_methods is
> nil.

Wouldn't this fix it?

   class Module
     def class_methods(&block)
       @class_methods ||= Module.new
       @class_methods.module_eval(&block)
     end

     def included(mod)
       mod.extend(@class_methods ||= Module.new)
     end
   end

I'm not saying this implementation is perfect; I only wrote it for this
thread.


Daniel
Bf6862e2a409078e13a3979c00bba1d6?d=identicon&s=25 Gregory Seidman (Guest)
on 2006-06-11 22:31
(Received via mailing list)
On Mon, Jun 12, 2006 at 05:14:20AM +0900, Daniel Schierbeck wrote:
} Gregory Seidman wrote:
} >... if you don't call class_methods before
} >you first include the module (e.g. you want to reopen the module
later to
} >add class methods), the included method will fail since
@class_methods is
} >nil.
}
} Wouldn't this fix it?
}
}   class Module
}     def class_methods(&block)
}       @class_methods ||= Module.new
}       @class_methods.module_eval(&block)
}     end
}
}     def included(mod)
}       mod.extend(@class_methods ||= Module.new)
}     end
}   end
}
} I'm not saying this implementation is perfect; I only wrote it for
this
} thread.

Sure, I understand. And yes, that would fix it. Take a look at the
complete
solution I posted at
http://redcorundum.blogspot.com/2006/06/mixing-in-...

} Daniel
--Greg
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-12 03:07
(Received via mailing list)
In message "Re: Why the lack of mixing-in support for Class methods?"
    on Sun, 11 Jun 2006 23:59:17 +0900, transfire@gmail.com writes:

|> I like the solution that Daniel has shown in [ruby-talk:196730].
|
|He he. That's ironic. Yes, Daniels solution is the right direction for
|the best meta-programming approach, but it still has some problems (as
|I pointed out in my last post).

Which is your "last post"?  Is it [ruby-talk:196751]?
If so, I agree with Daniel's reply in [ruby-talk:196770].

I have to mention I am not a big fan of the name "class_methods"
though.

|On the other hand, I can't help but wonder if a module's "class-level"
|were instead a "module-level", --a module instead of a class. Or at
|least if those methods were delegated to an extending module but
|transaprently, underthehood. Then this might actually make sense:

It may make sense from some aspect, but not from others.  Language
design is the very complicated task. ;-)  In this case, it introduces
full multiple inheritance, which I avoided for years.

							matz.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-12 06:40
(Received via mailing list)
Yukihiro Matsumoto wrote:

> It may make sense from some aspect, but not from others.  Language
> design is the very complicated task. ;-)

I concur with that. It is certainly not a simple thing, and I can only
admire the work you have done in the field. That's for sure.

> In this case, it introduces full multiple inheritance, which I avoided for years.

Does it really introduce multiple inheritance? It's still a linear
heirarchy. I always thought of MI as a means to route calls to
ancestors in arbitrarily defined ways, more like a tree graph. So I'm
not sure how the modularization of a module's "class methods" is
multiple inheritance other than the fact that a class is gaining new
behaviors from the module, making it something more than it was before.
But we can do that already with #extend.

I guess what I don't understand is this: If I can manully separate the
"class-level" into it's own module and resuse that, why can't I just
reusue the class-level to begin with?

T.
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-12 11:10
(Received via mailing list)
Yukihiro Matsumoto wrote:
> It may make sense from some aspect, but not from others.  Language
> ... In this case, it introduces
> full multiple inheritance, which I avoided for years.

I'm wondering why it's not possible to #include a class into a
module/class -- making the only difference between classes and modules
the ability to instantiate (#allocate). That way, you could do something
like this:

   class Module
     def included(mod)
       mod.extend(class << self; self; end)
     end
   end

i.e. extend the receiver with the methods and constants of the singleton
class. It sure would make this whole problem a lot easier to solve, and
avoid those pesky hacks we're all but fond of.


Cheers,
Daniel
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-12 12:20
(Received via mailing list)
Gregory Seidman wrote:
> Sure, I understand. And yes, that would fix it. Take a look at the complete
> solution I posted at
> http://redcorundum.blogspot.com/2006/06/mixing-in-...

Still think it's rather complicated. Here's what I've got so far, using
a slightly different approach than you:

   class Module
     def meta_module(&block)
       @meta_module ||= Module.new
       @meta_module.module_eval(&block)
       extend(@meta_module)
     end

     def included(mod)
       mod.extend(@meta_module ||= Module.new)
       if mod.kind_of? Module
         if mod.instance_variables.include? "@meta_module"
           other_meta_module = mod.instance_variable_get(:@meta_module)
           other_meta_module.send(:include, @meta_module)
         else
           mod.instance_variable_set(:@meta_module, @meta_module)
         end
       end
     end
   end

There may still be flaws, but I don't think it's too bad. Notice the use
of `meta_module' -- thought it was better than `class_methods', though
I'm not sure it's perfect, either.


Cheers,
Daniel
Bf6862e2a409078e13a3979c00bba1d6?d=identicon&s=25 Gregory Seidman (Guest)
on 2006-06-12 14:54
(Received via mailing list)
On Mon, Jun 12, 2006 at 07:19:10PM +0900, Daniel Schierbeck wrote:
} Gregory Seidman wrote:
} >Sure, I understand. And yes, that would fix it. Take a look at the
complete
} >solution I posted at
} >http://redcorundum.blogspot.com/2006/06/mixing-in-...
}
} Still think it's rather complicated. Here's what I've got so far,
using
} a slightly different approach than you:
}
}   class Module
}     def meta_module(&block)
}       @meta_module ||= Module.new
}       @meta_module.module_eval(&block)
}       extend(@meta_module)

Why should the module extend the meta_module?

}     end
}
}     def included(mod)
}       mod.extend(@meta_module ||= Module.new)

Again, if it's a module why should it extend the meta_module?

}       if mod.kind_of? Module

This definitely won't work. You need to check for Class, not Module.
Check
it out:

% irb
irb(main):001:0> Object.kind_of? Module
=> true

}         if mod.instance_variables.include? "@meta_module"
}           other_meta_module = mod.instance_variable_get(:@meta_module)
}           other_meta_module.send(:include, @meta_module)

Pretty much what I have.

}         else
}           mod.instance_variable_set(:@meta_module, @meta_module)
}         end
}       end
}     end
}   end

That last line is dangerous. Consider the following usage:

module M
  meta_module {
    def bar
      "class method bar() was defined in M"
    end
  }
end

class Foo
  include M
end

module N
  include M

  meta_module {
    def bar
      "pwn3d!"
    end
  }
end

puts Foo.bar

By setting the including module's instance variable to be the same as
the
included module's instance variable you allow the including module to
overwrite methods unexpectedly. That's why I give the including module
its
own new module and have it include the included module's module. It
preserves the inclusion semantics.

} There may still be flaws, but I don't think it's too bad. Notice the
use
} of `meta_module' -- thought it was better than `class_methods', though
} I'm not sure it's perfect, either.

I don't see anything particularly meta about it, but that may just be
me.

} Cheers,
} Daniel
--Greg
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-12 16:51
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Mon, 12 Jun 2006 13:37:25 +0900, transfire@gmail.com writes:

|I guess what I don't understand is this: If I can manully separate the
|"class-level" into it's own module and resuse that, why can't I just
|reusue the class-level to begin with?

Because it makes thing more complex, I guess.  Mere #include should
not inherit class/module-level methods, since there are cases like
Math module.  So we need to prepare two different method for module
inclusion instead of one, if we reuse class-level.

							matz.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-12 17:04
(Received via mailing list)
On Mon, 12 Jun 2006, Yukihiro Matsumoto wrote:

> not inherit class/module-level methods, since there are cases like
> Math module.  So we need to prepare two different method for module
> inclusion instead of one, if we reuse class-level.

what did you think about my solution matz?  it's solves the issue
cleanly and
is leverages existing practices.  here it is again:



     harp:~ > cat inheritable.rb
     module Inheritable
       Inherit = lambda do |this, other|
         cm = this.const_get 'ClassMethods' rescue nil
         im = this.const_get 'InstanceMethods' rescue nil
         other.extend cm if cm
         other.module_eval{
           include im if im
           extend RecursiveInherit
         }
       end

       module RecursiveInherit
         def included other
           Inherit[self, other]
           super
         end
       end

       extend RecursiveInherit
     end


     #
     # example
     #
     if $0 == __FILE__
       module M
         include Inheritable
         module ClassMethods
           def foo() 42 end
         end
       end
       class C
         include M
       end
       p C.foo



       module A
         include Inheritable
         module ClassMethods
           def bar() 'forty-two' end
         end
         module InstanceMethods
           def foobar() 42.0 end
         end
       end
       module B
         include A
       end
       class K
         include B
       end
       p K.bar
       p K.new.foobar
     end



     harp:~ > ruby inheritable.rb
     42
     "forty-two"
     42.0


this way the module itself exports specific class methods in a
deliberate
fashion and no new keyword need be introduced to support it.

regards.

-a
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-06-12 17:42
(Received via mailing list)
On Jun 12, 2006, at 5:09 AM, Daniel Schierbeck wrote:

>
> i.e. extend the receiver with the methods and constants of the
> singleton class. It sure would make this whole problem a lot easier
> to solve, and avoid those pesky hacks we're all but fond of.

Then you have multiple inheritance.
E1d641bfe4071a5413bac781f06d3fd1?d=identicon&s=25 Sean O'halpin (sean)
on 2006-06-12 17:55
(Received via mailing list)
On 6/12/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:
> what did you think about my solution matz?  it's solves the issue cleanly and
> is leverages existing practices.  here it is again:

I for one like it - pragmatic and straightforward. However, I'm not
sure why you want the InstanceMethods module (unless it's to be
explicit).

Regards,
Sean
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-12 18:05
(Received via mailing list)
Logan Capaldo wrote:
>>       mod.extend(class << self; self; end)
>>     end
>>   end
>>
>> i.e. extend the receiver with the methods and constants of the
>> singleton class. It sure would make this whole problem a lot easier to
>> solve, and avoid those pesky hacks we're all but fond of.
>
> Then you have multiple inheritance.

Yes.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-12 18:09
(Received via mailing list)
On Tue, 13 Jun 2006, Sean O'Halpin wrote:

> Sean
module M
     include Inheritable
     module ClassMethods
       def foo() 'foo' end
     end
     module InstanceMethods
       def bar() 'bar' end
     end
   end

   class A
     include M # here we get everything due to overridden self.include
   end

   class B
     include M::InstanceMethods # here we cherry pick
   end

   class C
     extend M::ClassMethods # also cherry picking
   end


if, instead we were to do

   module M
     include Inheritable
     module ClassMethods
       def foo() 'foo' end
     end

     def bar() 'bar' end
   end

then this also works with Inheritable

   class A
     include M # here we get everything due to overridden self.include
   end

since the overridden self.include calls super, but you lose the ability
to
cherry pick the instance methods.  Note that the InstanceMethods modules
is
totally optional and only makes sense if you plan on cherry picking
later -
which i've actually done three for four times every.  in pratice my own
inheritable.rb looks like this:

   module Inheritable
     Inherit = lambda do |this, other|
       cm = this.const_get 'ClassMethods' rescue nil
       im = this.const_get 'InstanceMethods' rescue nil
       m = this.const_get 'Methods' rescue nil
       other.extend cm if cm
       other.extend m if m
       other.module_eval{
         include im if im
         include m if m
         extend RecursiveInherit
       }
     end

     module RecursiveInherit
       def included other
         Inherit[self, other]
         super
       end
     end

     extend RecursiveInherit
   end


so the rules are

   ClassMethods    => class methods only
   InstanceMethods => instance methods only
   Methods         => methods that can be called at class or instance
level
   (none)          => 'normal' instance methods, no cherry picking

this covers all the bases and make sense even to newbies reading the
code.
90% of all cases will only use ClassMethods, however.

cheers.


-a
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-06-12 18:28
(Received via mailing list)
On Jun 12, 2006, at 12:04 PM, Daniel Schierbeck wrote:

>>>     end
>>>   end
>>>
>>> i.e. extend the receiver with the methods and constants of the
>>> singleton class. It sure would make this whole problem a lot
>>> easier to solve, and avoid those pesky hacks we're all but fond of.
>> Then you have multiple inheritance.
>
> Yes.
>

That's why it's not possible. matz. has strong feelings about MI.
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-12 18:38
(Received via mailing list)
Gregory Seidman wrote:
> On Mon, Jun 12, 2006 at 07:19:10PM +0900, Daniel Schierbeck wrote:
> }   class Module
> }     def meta_module(&block)
> }       @meta_module ||= Module.new
> }       @meta_module.module_eval(&block)
> }       extend(@meta_module)
>
> Why should the module extend the meta_module?

Because I'd like the meta-module methods to act as module methods -- if
you don't like that, remove that line.

> it out:
>
> % irb
> irb(main):001:0> Object.kind_of? Module
> => true

Or `instance_of? Module'

Again, I haven't had time to fully test this implementation -- please
focus on the interface.


Cheers,
Daniel
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-12 18:44
(Received via mailing list)
Logan Capaldo wrote:
>>>>   class Module
>> Yes.
>>
>
> That's why it's not possible. matz. has strong feelings about MI.

I'm not saying we should add it to core -- but I don't understand why we
shouldn't allow people to do it themselves.

If it was possible to include classes into modules/classes, it would
still just be the instance methods and constants of the included class
-- so it isn't full inheritance. If the coder overwrites
Module#included, full inheritance can be achieved. I don't think it
should be up to us whether or not we will allow people to do that.

I'm sorry if I don't make much sense right now, I'm a bit drunk (sorry).


Cheers,
Daniel
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-12 19:17
(Received via mailing list)
Daniel Schierbeck wrote:
> Logan Capaldo wrote:
> > Then you have multiple inheritance.
>
> Yes.

Not really. Mulitple Inheritance provides orthogonal heirarchies.
Ruby's is strictly linear. If what you say were true then Ruby would
already be MI since modules can be used to add behavior to both class
and instance levels, and readily associated together as well, as Ara's
example clearly demonstrates. To think this consititutes MI and thus
making specialized restrictions of code separation to repress it, only
serves to complixify the situation, not the other way around. It's like
trying to prevent someone from getting to their destinatin by not
allowing them to turn right --they'll still get there, they'll just
turn left three times.

T.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-12 19:31
(Received via mailing list)
On Tue, 13 Jun 2006 transfire@gmail.com wrote:

> and instance levels, and readily associated together as well, as Ara's
> example clearly demonstrates. To think this consititutes MI and thus
> making specialized restrictions of code separation to repress it, only
> serves to complixify the situation, not the other way around. It's like
> trying to prevent someone from getting to their destinatin by not
> allowing them to turn right --they'll still get there, they'll just
> turn left three times.
>
> T.

in my mind it's this that makes it __not__ mi

     harp:~ > cat a.rb
     module A
       def foo() 'foo' end
     end
     module B
       def bar() 'bar' end
     end
     module C
       def bar() foo() end
     end

     class D
       include A
       include B
       include C
     end

     p D.new.foo


     harp:~ > ruby a.rb
     "foo"

now, if ruby was truely mi then i could write something (imagined) like

   class D < (A, B, C)
   end

   p D.new.foo

and ruby would be free to print either 'foo' or 'bar'.  clearly it would
be
one or the other and a ruleset would exist to make it un-ambiguous, but
the
difference between ruby deciding and having built-in rules vs me
deciding and
have explicit call hierachies aranged manually is a rather large one.

so, to me, this is the crucial thing which prevents me from considering
ruby
to be a true mi lang.  the cool thing, of course, is that it's only a
few
lines of code to make is behave as if it was.

cheers.


-a
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-12 19:35
(Received via mailing list)
This thread led me to write this:

  # = capsule.rb
  #
  # == Copyright (c) 2006 Thomas Sawyer
  #
  #   Ruby License
  #
  #   This module is free software. You may use, modify, and/or
redistribute this
  #   software under the same terms as Ruby.
  #
  #   This program is distributed in the hope that it will be useful,
but WITHOUT
  #   ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS
  #   FOR A PARTICULAR PURPOSE.
  #
  # == Authors & Contributors
  #
  # * Thomas Sawyer

  # Author::    Thomas Sawyer
  # Copyright:: Copyright (c) 2005 Thomas Sawyer
  # License::   Ruby License

  # = Capsule
  #
  # A Capsule encapsulates reusable code and is an analog to the Module
class,
  # but rather than storing it's own methods it simply stores modules.
These
  # modules are divided into two groups: extensions and inclusions. A
capsule
  # is reused via the Kernel#inherit method.
  #
  # == Usage
  #
  #   module Foo
  #     def foo ; "foo" ; end
  #   end
  #
  #   module Bar
  #     def bar ; "bar" ; end
  #   end
  #
  #   C = Capsule.new do
  #     extend Foo
  #     include Bar
  #   end
  #
  #   class X
  #     inherit X
  #   end
  #
  #   X.foo      #=> "foo"
  #   X.new.bar  #=> "bar"
  #
  # Use #[] as a shortcut for grouping one inclusion and one extension
together into
  # a new capsule.
  #
  #   C = Capsule[ Foo, Bar ]
  #

  class Capsule

    attr_reader :extensions, :inclusions

    def initialize( &template )
      @extensions = []
      @inclusions = []
      instance_eval &template if template
    end

    # Shortcut for creating an inclusion-extension pair capsule.

    def self.[]( e, i )
      new << e < i
    end

    # Add modules to the inclusions group.

    def include( *inclusions )
      @inclusions.concat inclusions
    end

    # Add modules to the extensions group.

    def extend( *extensions )
      @extensions.concat extensions
    end

    # Add a module to the inclusions group.

    def <( inclusion )
      @inclusions << inclusion
      self
    end

    # Add a module to the extensions group.

    def <<( extension )
      @extensions << extension
      self
    end

    # Append this capsules features to a given base module or class.

    def append_features( base )
      # use #instance_exec in Ruby 1.9+
      base.send( :extend,  *@extensions )
      base.send( :include, *@inclusions )
    end

  end

  class Module

    # Inherit behavior from other modules or capsules.

    def inherit( *capsules )
      capsules.each do |c|
        c.append_features( self )
      end
    end

  end

No doubt it can be improved on, but it clearly ties together what Ruby
presently does and the behvior some of us would like to achieve.

T.
18d8b0c948dd7b3d39c9667cfd4e817c?d=identicon&s=25 Andrew Stone (Guest)
on 2006-06-12 20:23
(Received via mailing list)
I've read most of this thread and still am a little confused.  I'm no
ruby
guru by any stretch of the imagination, but I use modules to house code
that
can be utilized in various classes.  If I need class methods then I use
inheritance.  IMO, this is simple and clean.

So far, there doesn't seem to be a clean/simple way to have mixin
support
for class methods.  Until that epiphany is reached, I would think it
would
be better to leave things as is.

I will give a novice suggestion:

Maybe instead of trying to work in this feature to modules, why not
introduce "ClassModule"?  Or has this been said?  This way it is clear
what
they use is and they can, in turn, have features specific to class
method
inheritance (if any are needed).

Therefore you could mix and match ClassModules with regular Modules.
Seems
pretty flexible to me.  I have no idea how difficult this would be to
implement.
B780ee0ee1480454a85df58536702f63?d=identicon&s=25 Alder Green (Guest)
on 2006-06-12 23:47
(Received via mailing list)
On 6/12/06, transfire@gmail.com <transfire@gmail.com> wrote:
> and instance levels, and readily associated together as well, as Ara's
>
Exactly.

1. Multiple module inclusion is not multiple inheritance. Even if you
think it is - Ruby already has it. So unless you're arguing for its
removal - and nobody seems to want that - it's a moot point.

2. You may debate whether mixing-in class methods is a "bad" practice
in some sense, and should therefore be discouraged - or at least not
encouraged by adding elegant, clear and standard language support for
it.

But:

2a. It can't be that bad, since nobody is arguing that it should be
disallowed completely.

2b. It doesn't seem to be widely considered "bad", at least not by
several skilled Ruby hackers. Rails is highly regarded codebase, and
the ClassMethods hack is all over it. Rails is the only codebase I'm
(vaguely) familiar with, but posts in this thread indicate that other
good codebases use similar hacks to accomplish the same programming
strategy.

2c. Of course, one may argue that even if mixing-in of class methods
is done by many skilled Ruby hackers, and is a vital programming
strategy in many high quality Ruby programs, it is still "bad" in some
theoretical sense. This is a subjective argument that cannot be
resolved. But one of the major attractions of Ruby for me is the
TIMTOWDI philosophy. I did not think Ruby would try to discipline its
coders by inconveniencing them. Not that it would matter much - mixins
would continue to be used for classs method inclusion.

So in short, since it seems many people are mixin class methods, it
would be nice if it were handled by a standard - hopefully convenient,
elegant - language feature.
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-06-13 00:09
(Received via mailing list)
On Jun 12, 2006, at 5:43 PM, Alder Green wrote:

>> already be MI since modules can be used to add behavior to both class
>>
>
> 2b. It doesn't seem to be widely considered "bad", at least not by
> resolved. But one of the major attractions of Ruby for me is the
>
I think a little context has been lost in this conversation, if I may
be permitted to go back and quote Mr. Schierbeck again:
> I'm wondering why it's not possible to #include a class into a
> module/class -- making the only difference between classes and
> modules the ability to instantiate (#allocate). That way, you could
> do something like this:
>

I do not see how straight up #include-ing a _class_ would _not_ be
multiple inheritance.

I'm was not talking including class methods, I'm talking about writing

class A
end

class B
end

class C
end

class D < A
   include B
   include C
end

IOW, erasing the distinction between classes and modules, which is
what Mr. Scheirbeck suggested, and what I took exception to.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-13 04:41
(Received via mailing list)
Logan Capaldo wrote:

> I think a little context has been lost in this conversation, if I may
> be permitted to go back and quote Mr. Schierbeck again:
> > I'm wondering why it's not possible to #include a class into a
> > module/class -- making the only difference between classes and
> > modules the ability to instantiate (#allocate). That way, you could
> > do something like this:
> >
>
> I do not see how straight up #include-ing a _class_ would _not_ be
> multiple inheritance.

Techincally it isn't. Multiple inheritance can have iheritance
structures like so:

M   N
 \ /
  C

Single inheritance (like Ruby) is strictly like this:

  N
  |
  M
  |
  C

With Ruby, it doesn't matter how many modules you include, it's still
just a line of single inheritance. What's unique about mixins is that
they allow us to slip "ancesotors" in between a class and it's
superclass, thus augmenting behavior in a way similar to MI, but
wiithout many of the additional complexities of MI.

>
> class D < A
>    include B
>    include C
> end
>
> IOW, erasing the distinction between classes and modules, which is
> what Mr. Scheirbeck suggested, and what I took exception to.

Fair enough. But let me make clear that MI is not a wholly satisfactory
answer to Mr. Scheirbeck query. The answer is more subtle, a
distinction between module and class help promote two different forms
of behavioral inheritance, one primary (class) and the other secondary
(module). This is actually quite realistic. Think of a Car (class) with
optional feature like FullyLoaded (module). I don't think anyone is
suggesting we remove that disticition, even if it is *technically*
debatable.

What _was_ suggested though, is that the "class-level" of a module
might be more appropriately a "module-level". Classes would still have
class-levels, but by giving modules their "own kind" in this role, the
difficulty of extending a class via a module's "module-level" is easily
solved --a solution which is the hope of this thread. And such a
solution, I reitererate, does not in any way constitute MI.

T.
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-13 10:23
(Received via mailing list)
transfire@gmail.com wrote:
> What _was_ suggested though, is that the "class-level" of a module
> might be more appropriately a "module-level". Classes would still have
> class-levels, but by giving modules their "own kind" in this role, the
> difficulty of extending a class via a module's "module-level" is easily
> solved --a solution which is the hope of this thread. And such a
> solution, I reitererate, does not in any way constitute MI.

I agree with you throughout the post, and I do enjoy being called Mr.
Schierbeck (we seldom use such formalities where I am from,) but I'm
still not sure if we have the same idea about the "module-level". Are
you suggesting we replace module objects' singleton classes with such a
"module-level", or would the singleton methods and constants be defined
in both?

What I thought would be great about allowing #include and #extend to
accept Class objects is that it would make it much easier for a module
(or, well, class) author to decide for himself whether or not he wishes
to have the module methods included as well. I agree with you that
multiple inheritance would mean a non-linear line of inheritance, and
that allowing Class objects to be included would not have such a
consequence. Basically, I think module authors should be able to write
this:

   module MyModule
     def self.included(mod)
       mod.extend(class << self; self; end)
     end

     def self.foo
       "a class method"
     end

     def bar
       "an instance method"
     end
   end

   class Test
     include MyModule
   end

   Test.foo      #=> "a class method"
   Test.new.bar  #=> "an instance method"

I think module authors should be able to make that decision (as they do
now, with the hacks and all.) This would also allow module "users" to
opt-in on the module methods:

   class Module
     def inherit(*mods)
       include *mods
       mods.each{|mod| extend(class << mod; self; end)}
     end
   end

(geez, it sure would be nice with a shorthand for singleton classes...)


Cheers,
Daniel
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-13 15:37
(Received via mailing list)
Daniel Schierbeck wrote:

> you suggesting we replace module objects' singleton classes with such a
> "module-level", or would the singleton methods and constants be defined
> in both?

You have to understand a little about how modules are tied into the
inhertiance chain. Modules are linked via virtual classes. (There are
some good diagrams of this in the Pickaxe, I believe it's under
"Classes and Objects").  The idea is then to replace a module's current
"metaclass" with a virtual class linking in a "metamodule". Anything in
a module's "class << self" then is defined in this metamodule instead.

> What I thought would be great about allowing #include and #extend to
> accept Class objects is that it would make it much easier for a module
> (or, well, class) author to decide for himself whether or not he wishes
> to have the module methods included as well.

Well, one can argue the merits for or against that. But it goes beyond
the need at hand. The division between module and class I think suits
Ruby. Allowing classes to be included outright, while not MI
underthehood, nonetheless appears as such on the surface b/c a class
than appears to be a child of a more than one class. But having modules
distinct, it can only be the child of one class and instead agumented
with extra modular behaviors.

>      def self.foo
>    end
>
>    Test.foo      #=> "a class method"
>    Test.new.bar  #=> "an instance method"
>
> I think module authors should be able to make that decision (as they do
> now, with the hacks and all.)

While I'm for 'mod.extend(class << AModule; self; end)'. I think the
use of #included is done nowadays b/c there is no other obvious way to
achieve the same thing. I think it's unfortuate to have to depend on a
callback --and as things stand it goes beyond what a module user
generally expects from #include. So in that respect it's not really a
good practice. What we really need is a good practice to replace this
callback pattern.

> This would also allow module "users" to
> opt-in on the module methods:
>
>    class Module
>      def inherit(*mods)
>        include *mods
>        mods.each{|mod| extend(class << mod; self; end)}
>      end
>    end

Yes, I think that's a fair option. And IMHO would say that it's the 2nd
best choice, behind the ability to specify 'extensible' and
'uninheritable' sections in ones modules. I still tend to think that
the the control is best left to a module itself. But short of that,
then this would be a good way. Of course, matz, doesn't like the term
"inherit" bc/ it invokes ideas of MI, but any name will do.

> (geez, it sure would be nice with a shorthand for singleton classes...)

I agree. I've been toying with "own" and "owner" lately myself.

T.
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-13 16:04
(Received via mailing list)
transfire@gmail.com wrote:
> ... Modules are linked via virtual classes. (There are
> some good diagrams of this in the Pickaxe, I believe it's under
> "Classes and Objects").  The idea is then to replace a module's current
> "metaclass" with a virtual class linking in a "metamodule". Anything in
> a module's "class << self" then is defined in this metamodule instead.

All I wanted to know.

> distinct, it can only be the child of one class and instead agumented
> with extra modular behaviors.

So the functionality of modules repressed in order to preserved their
secondary nature? Why should we limit the power of modules just so that
we can say Ruby doesn't allow MI?

I think it's a plus if Ruby had the ability to be *like* an MI language,
just like it can appear to be functional.


> Yes, I think that's a fair option. And IMHO would say that it's the 2nd
> best choice, behind the ability to specify 'extensible' and
> 'uninheritable' sections in ones modules. I still tend to think that
> the the control is best left to a module itself.

I think the use of sections is annoying -- I'd much rather just define
in the module whether or not the module methods and constants should be
included, too. If you only want certain methods to be included, I think
the nested module approach is better.


>> (geez, it sure would be nice with a shorthand for singleton classes...)
> I agree. I've been toying with "own" and "owner" lately myself.

I still like "metaclass" the best -- it may not be the most precise, but
it flips off the tongue and keyboard. In the end, it's up to matz; I
don't don't really care what name it'll get, as long as it's there.
`class << self; self; end' is not the prettiest piece of code...


Daniel aka Mr. Schierbeck :)
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-13 16:39
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Tue, 13 Jun 2006 22:35:14 +0900, transfire@gmail.com writes:

|> you suggesting we replace module objects' singleton classes with such a
|> "module-level", or would the singleton methods and constants be defined
|> in both?
|
|You have to understand a little about how modules are tied into the
|inhertiance chain. Modules are linked via virtual classes. (There are
|some good diagrams of this in the Pickaxe, I believe it's under
|"Classes and Objects").  The idea is then to replace a module's current
|"metaclass" with a virtual class linking in a "metamodule". Anything in
|a module's "class << self" then is defined in this metamodule instead.

I don't think I understand you.  Do you want to allow #include to
include classes?  Without making it MI?  Hmm.

							matz.
E7559e558ececa67c40f452483b9ac8c?d=identicon&s=25 unknown (Guest)
on 2006-06-13 18:45
(Received via mailing list)
On Jun 13, 2006, at 10:38 AM, Yukihiro Matsumoto wrote:
> I don't think I understand you.  Do you want to allow #include to
> include classes?  Without making it MI?  Hmm.

It isn't altogether obvious to me why a class passed to #include
couldn't be interpreted as a module (since instances of Class are
instances of Module via inheritance). That is to say the superclass
ancestors a class should not be considered by #include but any
included modules should be as well as any directly defined instance
methods. To illustrate:

module M; end
class A; end
class B < A; end
class C < A; include M; end
class D
   include B
   include C
end

M.ancestors => [M]
A.ancestors => [A, Object, Kernel]
B.ancestors => [B, A, Object, Kernel]
C.ancestors => [C, M, A, Object, Kernel]
D.ancestors => [D, C, M, B, Object, Kernel]

In the last example, A isn't an ancestor because the superclass
relationship is ignored by my fictitious 'include'.

While I think this behavior could be well-defined, I'm not sure the
subtlety is worth it nor do I think it suggests any particular answer
to the question of how singleton methods should be handled by
#include or some companion method that has been discussed.  On that
point I'm in Matz camp.  I don't see an inherent relationship between
the instance methods of a module and the singleton methods of the
module object. In particular situations I can see the relationship
but it isn't always guaranteed to be there. Instance methods are the
raison d'etre of modules but singleton methods may exist for any
object whatsoever.  I'm not sure why they (singleton methods) should
be considered by #include at all.

I'm not sure I understand why singleton methods are tucked away in a
pseudo-class object since none of the Class instance methods (new,
superclass, allocate) seem to be applicable.  The container for
singleton methods seems much more like a module than a class to me.
There is a relationship between the singleton classes of related
parent/child classes but couldn't that be modeled as module
inclusion?  I'm probably missing some subtlety.  I am often reminded
of the maze in Adventure ("You are in a maze of twisty little
passages, all alike") when I think about this stuff.

Gary Wright
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-13 18:51
(Received via mailing list)
On Wed, 14 Jun 2006 gwtmp01@mac.com wrote:

>
> On Jun 13, 2006, at 10:38 AM, Yukihiro Matsumoto wrote:
>> I don't think I understand you.  Do you want to allow #include to
>> include classes?  Without making it MI?  Hmm.
>
> It isn't altogether obvious to me why a class passed to #include couldn't be
> interpreted as a module (since instances of Class are instances of Module
> via inheritance).

   module M
     def initialize
       'ha'
     end
   end

   module N
     def initialize
       'ha ha'
     end
   end

   class C
     include M
     include N
     def initialize
       'hmmm'
     end
   end

with classes, this is __always__ the situation.  obviously it can be
dealt
with - but it's a little less straight forward than the 'normal' mixin
effect.

not for or against here - but i do believe being able to mixin classes,
without some really slick handling of super/initialize, state, and
class_init
on ruby's part would be confusing for most.  in otherwords, ruby would
need to
become mi to do so.

regards.

-a
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-13 19:33
(Received via mailing list)
Yukihiro Matsumoto wrote:

> I don't think I understand you.  Do you want to allow #include to
> include classes?  Without making it MI?  Hmm.

No no. You'd still only be able to include modules. I'm thinking a
module's "singleton class" could be a "singleton module", so to speak,
instead. It's a bit difficult to communicate b/c the terminology is
caught up in how it curently works. But it's a lot less fancy than I
think it sounds. I'll use a diagram to make it clearer. Lets say we
have this code.

  class Foo
    include Moo
  end

  foo = Foo.new

A basic diagram of that currently looks like this:

     object foo
        ||
        \/
     class foo'  -> class Foo -> (vclass Moo)
                        ||            //
                        \/        module Moo
                    class Foo'        ||
                                      \/
                                   class Moo'

I'm thinking that instead it could be like this.

     object foo
        ||
        \/
     class foo'  -> class Foo -> (vclass Moo)
                        ||            //
                        \/        module Moo
                    class Foo'        ||
                                      \/
                                 (vclass Moo')
                                      //
                                  module Moo'

In this way the so-called "class-level" of a _module_  is instead a
"module-level". Essentially:

  module Moo
    class << self
      self.class  #=> Module
    end
  end

Which is why I earlier used "module << self".

Of course, in the implmentation you might be able omit the vclass Moo'
altogether. I just conceived of it that way becuase it readly
"plugs-in" to the current design.

T.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-13 19:46
(Received via mailing list)
On Wed, 14 Jun 2006 transfire@gmail.com wrote:

<snip ascii art>

tom - you'll love this

   http://www.jave.de/

cheers.

-a
E7559e558ececa67c40f452483b9ac8c?d=identicon&s=25 unknown (Guest)
on 2006-06-13 21:17
(Received via mailing list)
On Jun 13, 2006, at 12:50 PM, ara.t.howard@noaa.gov wrote:
>   end
> be dealt
> with - but it's a little less straight forward than the 'normal'
> mixin effect.

I don't see how your example is any different than the problem
presented by
nested includes.  The ordering of ancestors and thus the resolution
of method
lookup is well defined in either case, no?

> not for or against here - but i do believe being able to mixin
> classes,
> without some really slick handling of super/initialize, state, and
> class_init
> on ruby's part would be confusing for most.  in otherwords, ruby
> would need to
> become mi to do so.

Isn't this already an issue with module-only includes?  There was some
discussion on this recently I think.

We got to this point in the discussion because of the desire to auto-
mixin
module methods, which happen to reside inside a singleton *class*.
So this
raised the question of what does it mean to include a class? I still
don't
like the idea of auto-mixin of module methods but to make sense of
that idea
you must somehow grapple with the notion that instance methods can
be implicitly extracted from a singleton class object (i.e. an
instance of Class).
Once you go down that road, it just begs the question of why you
can't do that
with any class object.


Gary Wright
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-13 21:18
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Wed, 14 Jun 2006 02:31:00 +0900, transfire@gmail.com writes:

|> I don't think I understand you.  Do you want to allow #include to
|> include classes?  Without making it MI?  Hmm.
|
|No no. You'd still only be able to include modules. I'm thinking a
|module's "singleton class" could be a "singleton module", so to speak,
|instead. It's a bit difficult to communicate b/c the terminology is
|caught up in how it curently works. But it's a lot less fancy than I
|think it sounds.

That makes modules too "special".  Every object has its own "singleton
class" (aka eigenclass) no matter what class it belongs to, under the
current implementation.  After your proposal, modules should be
treated specially not to have ordinary singleton classes.  I know its
purpose (to allow injecting a module's singleton methods using
#include), but I am not sure if it's worth making object model
complex.

It seems Daniel's _API_ is good enough.  What's wrong with the idea?
Except for implementation issues, of course.

							matz.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-13 21:57
(Received via mailing list)
On Wed, 14 Jun 2006 gwtmp01@mac.com wrote:

> I don't see how your example is any different than the problem presented by
> nested includes.  The ordering of ancestors and thus the resolution of
> method lookup is well defined in either case, no?

yes.  the problem is that mixin modules, by design, seldom have name
collisions with important instance methods, while mixin classes, if they
existed, always would.  it's a matter of degrees.

regards.

-a
36958dd94ca666a38483df282a5214d5?d=identicon&s=25 Pete (Guest)
on 2006-06-13 23:38
(Received via mailing list)
are you looking for that here?

module MixInClassMethods
   def test
      puts "test"
   end
end

try using 'extend'

class MyClass
   extend MixInClassMethods
end

 > MyClass.test
"test"



Andrew Stone schrieb:
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-14 04:55
(Received via mailing list)
Yukihiro Matsumoto wrote:

> That makes modules too "special".  Every object has its own "singleton
> class" (aka eigenclass) no matter what class it belongs to, under the
> current implementation.  After your proposal, modules should be
> treated specially not to have ordinary singleton classes.  I know its
> purpose (to allow injecting a module's singleton methods using
> #include), but I am not sure if it's worth making object model
> complex.

I see your point. This solution is kind of drastic in that respect.
Although I sort of liked the symmetry of a module being a module from
"head-to-toe" ;) And it's knid of too bad too, b/c this solution
limited the capability just to module's class-level, where it's needed
and no where else. Other solutions tend to be much broader and/or
hackish.

> It seems Daniel's _API_ is good enough.  What's wrong with the idea?
> Except for implementation issues, of course.

Well, that's what I've been using already. In fact, as far as I can
tell the Facets' implementation is the most complete around (not to say
it can't be improved). But even so, it is hackish, inefficient, and
fragile, and that really can;t be hellped because of the naturr of
implementing it. And its' made worse in that the techinque is without
standard, so nayone can run roughshod right over it. These are the
reasons why I've asked you directly about the issue. I'm essentially at
my wits end with it. I've spent more hours on this one problem than I
care to admit.

This evening is sadly no exception. I attempted another implementation,
which I think has a better overall interface (not as good as just being
able to include the singleton, but...)

  module M
    def meta.x
       self
     end
  end

  class X
    meta_include M
  end

  X.x #=> X

Alas, an implementation of this appears to be impossible. Again those
singleton methods are just out of reach and it is frustrating to no
end.

T.
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-14 05:10
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Wed, 14 Jun 2006 11:53:32 +0900, transfire@gmail.com writes:

|> It seems Daniel's _API_ is good enough.  What's wrong with the idea?
|> Except for implementation issues, of course.
|
|Well, that's what I've been using already. In fact, as far as I can
|tell the Facets' implementation is the most complete around (not to say
|it can't be improved). But even so, it is hackish, inefficient, and
|fragile, and that really can;t be hellped because of the naturr of
|implementing it. And its' made worse in that the techinque is without
|standard, so nayone can run roughshod right over it. These are the
|reasons why I've asked you directly about the issue. I'm essentially at
|my wits end with it. I've spent more hours on this one problem than I
|care to admit.

You got me wrong again.  I asked you what if I'd add Daniel's API to
the core.

							matz.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-14 06:38
(Received via mailing list)
Yukihiro Matsumoto wrote:
> |it can't be improved). But even so, it is hackish, inefficient, and
> |fragile, and that really can;t be hellped because of the naturr of
> |implementing it. And its' made worse in that the techinque is without
> |standard, so nayone can run roughshod right over it. These are the
> |reasons why I've asked you directly about the issue. I'm essentially at
> |my wits end with it. I've spent more hours on this one problem than I
> |care to admit.
>
> You got me wrong again.  I asked you what if I'd add Daniel's API to
> the core.

Ah yea, sorry for rambling. As I said, I already use that API, so, yea,
that works. I just don't know the best solution and have been throwing
out ideas. I was hoping maybe you could tell us.

So if you did this, would #include handle the extending? Or would
another method need to be used?

T.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-14 07:25
(Received via mailing list)
Well, I hate to throw a wrench in the works at this point, but (by
God's grace) I may have managed a better solution. It can be
implemented in either of two ways. Either by extending module with some
special methods like so:

  class Module

    def propagating_extensions
      @propagating_extensions ||= []
    end

    def propagate( *mods )
      propagating_extensions.concat mods
    end

    def extend_and_propagate( *mods )
      propagate *mods
      extend *mods
    end

    alias_method :append_features_without_propagation, :append_features

    def append_features( base )
      unless propagating_extensions.empty?
        base.extend_and_propagate *propagating_extensions
      end
      append_features_without_propagation( base )
    end

  end

Or alternatively sepearating the capability into a subclass of module:

  class Capsule < Module

    def extensions
      @extensions ||= []
    end

    def propagate( *mods )
      extensions.concat mods
    end

    def extend( *mods )
      propagate *mods
      super
    end

    def append_features( base )
      unless extensions.empty?
        base.extend *extensions
      end
      super
    end

  end

The later is a little more elegant in implementation but requires the
use of the specialized class to continue the propogating behavior. The
former doesn't need the special class, but does require an additional
special method.

Here's an example of using the first implementation.

  module Foo
    def foo ; "foo" ; end
  end

  module Bar
    extend_and_propagate Foo
  end

  class X
    include Bar
  end

  p X.foo      #=> "foo"

And here's an example of the second:

  module Foo
    def foo ; "foo" ; end
  end

  Bar = Capsule.new do
    extend Foo
  end

  class X
    include Bar
  end

  p X.foo       #=> "foo"

T.
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-14 08:28
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Wed, 14 Jun 2006 13:36:34 +0900, transfire@gmail.com writes:

|So if you did this, would #include handle the extending? Or would
|another method need to be used?

I thinking of something like the following:

  module Moo
    def im
    end

    class_extension do
      def cm
      end
    end
  end

  class Foo
    include Foo
  end
  foo = Foo.new
  foo.im
  Foo.im

The name 'class_extension' may be changed in the real implementation,
or maybe it would be a new visibility.

							matz.
D3944ff4e8bc05067a615579b6ef599b?d=identicon&s=25 Phil Tomson (Guest)
on 2006-06-14 08:37
(Received via mailing list)
On 6/13/06, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:
>   module Moo
>     def im
>     end
>
>     class_extension do

Maybe it could be called class_methods ?

>   Foo.im
Do you mean Foo.cm ?

> The name 'class_extension' may be changed in the real implementation,
> or maybe it would be a new visibility.
>

Is this just a more automatic/nicer way to do:

module Moo
   def self.included mod
      mod.extend ClassMethods
   end
   module ClassMethods
     def cm
     end
   end
   def im
   end
end

class Foo
  include Moo
end

?

It does seem a bit more convenient.

Phil
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-14 08:50
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Wed, 14 Jun 2006 15:34:43 +0900, "Phil Tomson"
<rubyfan@gmail.com> writes:

|>     class_extension do
|
|Maybe it could be called class_methods ?

I thought of the name first, but I changed my mind because it is too
similar to methods with different behavior e.g. private_methods.
Besides that class_extension can be used for something other than
methods, for example, constant definition.

|>   Foo.im
|
|Do you mean Foo.cm ?

Yes.  What a shame.

|Is this just a more automatic/nicer way to do:
|
|module Moo
|   def self.included mod
|      mod.extend ClassMethods
|   end
|   module ClassMethods
|     def cm
|     end
|   end
|   def im
|   end
|end
|
|class Foo
|  include Moo
|end
|
|?

Maybe.  I am not opposing to this style.

|It does seem a bit more convenient.

How is it more convenient?

							matz.
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-14 11:06
(Received via mailing list)
transfire@gmail.com wrote:
>   X.x #=> X
I've been down that road myself, trying something like this:

   module A
     def this.foo
       "foo"
     end
   end

But sadly, I found it impossible. Maybe I'll give it another try today.


Cheers,
Daniel
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2006-06-14 13:57
(Received via mailing list)
On Jun 14, 2006, at 1:34 AM, Phil Tomson wrote:

>>
>>   module Moo
>>     def im
>>     end
>>
>>     class_extension do
>
> Maybe it could be called class_methods ?

I think that name misrepresents what the method does.

James Edward Gray II
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2006-06-14 14:26
(Received via mailing list)
On Jun 14, 2006, at 1:48 AM, Yukihiro Matsumoto wrote:

> |      mod.extend ClassMethods
> |  include Moo
> |end
> |
> |?
>
> Maybe.  I am not opposing to this style.

I think I still prefer this approach, though the method thing is OK
with me too (as long as we don't call it class_methods()).

James Edward Gray II
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-14 15:39
(Received via mailing list)
James Edward Gray II wrote:
> > |module Moo
> > |
> > |class Foo
> > |  include Moo
> > |end
> > |
> > |?
> >
> > Maybe.  I am not opposing to this style.
>
> I think I still prefer this approach, though the method thing is OK
> with me too (as long as we don't call it class_methods()).

If you allow #class_extension (or whatever you want to call it) to also
take a list of modules in addition to the block, then you'd effectively
have it both ways. Ex-

  module Moo
    module ClassMethods
      def cm
      end
    end
    class_extension ClassMethods
  end

T.
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-14 16:18
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Wed, 14 Jun 2006 22:37:24 +0900, transfire@gmail.com writes:

|If you allow #class_extension (or whatever you want to call it) to also
|take a list of modules in addition to the block, then you'd effectively
|have it both ways. Ex-
|
|  module Moo
|    module ClassMethods
|      def cm
|      end
|    end
|    class_extension ClassMethods
|  end

I think class_extension (or whatever) plus and include will do.

module Moo
  module ClassMethods
    def cm
    end
  end
  class_extension do
    include ClassMethods
  end
end

|T.
|
|
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-14 16:31
(Received via mailing list)
Yukihiro Matsumoto wrote:

> I think class_extension (or whatever) plus and include will do.

Nice point.

Okay, so I'm wondering, will the annonymous module this creates get a
name of some sort instead of the ususal "#<Module:0xb7ca7e1c>" and if
the class_extension method is used more than once will it create an
additional new module or just reuse the first?

Thanks,
T.
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-14 16:41
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Wed, 14 Jun 2006 23:30:25 +0900, transfire@gmail.com writes:

|Okay, so I'm wondering, will the annonymous module this creates get a
|name of some sort instead of the ususal "#<Module:0xb7ca7e1c>" and if
|the class_extension method is used more than once will it create an
|additional new module or just reuse the first?

I am not thinking about implementation detail yet.  What do you think
how it should behave?

							matz.
E7559e558ececa67c40f452483b9ac8c?d=identicon&s=25 unknown (Guest)
on 2006-06-14 16:54
(Received via mailing list)
On Jun 14, 2006, at 10:30 AM, transfire@gmail.com wrote:
> Okay, so I'm wondering, will the annonymous module this creates get a
> name of some sort instead of the ususal "#<Module:0xb7ca7e1c>"

I was thinking that the block would just be evaluated in the context of
the targeted singleton class as vs. the context of a new anonymous
module which is *then* included into the targeted singleton class.



Gary Wright
D3944ff4e8bc05067a615579b6ef599b?d=identicon&s=25 Phil Tomson (Guest)
on 2006-06-14 18:08
(Received via mailing list)
On 6/13/06, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:
> similar to methods with different behavior e.g. private_methods.
> |
> |end
>
> How is it more convenient?
>

I mean your proposal seems more convenient than the common idiom I
showed.

Phil
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-14 19:26
(Received via mailing list)
Yukihiro Matsumoto wrote:

> I am not thinking about implementation detail yet.  What do you think
> how it should behave?

It's not as simple as it seems. After manuevering past the potential
for infinite recursion on #include, I've see another issue: the old
Dynamic Module Inclusion problem. This is what I'm playing with:

  class Module

    def class_extension( *mods, &blk )
      unless @class_extension
        @class_extension = Module.new
        def @class_extension.append_features( base )
          append_features_without_extension( base )
        end
        extend @class_extension
      end
      @class_extension.module_eval(&blk) if blk
      @class_extension
    end

    alias_method :append_features_without_extension, :append_features

    def append_features( base )
      ce = class_extension
      base.class_extension { include ce }
      append_features_without_extension( base )
    end

  end

Problem is that 'extend @class_extension' doesn't work unless it occurs
_after_ the module_eval(&blk). Which means later changes to the
extensions module will have no effect on modules that have already
included it. Not good. So unless I've misanalyzed this, I think keeping
a running list of extension modules, more like my previous
implementation post, is going to be neccessary.

T.
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-14 19:46
(Received via mailing list)
gwtmp01@mac.com wrote:
>
> On Jun 14, 2006, at 10:30 AM, transfire@gmail.com wrote:
>> Okay, so I'm wondering, will the annonymous module this creates get a
>> name of some sort instead of the ususal "#<Module:0xb7ca7e1c>"
>
> I was thinking that the block would just be evaluated in the context of
> the targeted singleton class as vs. the context of a new anonymous
> module which is *then* included into the targeted singleton class.

Then inheritance problems will arise --  I think we need to use modules.


Daniel
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-14 20:11
(Received via mailing list)
On Thu, 15 Jun 2006, Daniel Schierbeck wrote:

> Then inheritance problems will arise --  I think we need to use modules.
can someone point out to me what's wrong with this impl?  it's simple,
works
in a recursive way, is self documenting, is already used, and is 34
lines
long.  as far as i can tell it already does every required and it very
simple
and robust.


module Mixable
   Mixin = lambda do |this, other|
     cm = this.const_get 'ClassMethods' rescue nil
     im = this.const_get 'InstanceMethods' rescue nil
     other.extend cm if cm
     other.module_eval{
       include im if im
       extend RecursiveMixin
     }
   end
   module RecursiveMixin
     def included other
       Mixin[self, other]
       super
     end
   end
   extend RecursiveMixin
end
class Object
   def mixin other
     sc =
       class << self
         self
       end
     sc.module_eval{ mixin other }
   end
end
class Module
   def mixin other
     other.module_eval{ include Mixable } unless
       Mixable > other
     include other
   end
end



if __FILE__ == $0
#
# example 1 - simple usage
#
   module M
     include Mixable
     module ClassMethods
       def foo() 42 end
     end
   end
   class C
     include M
   end
   p C.foo #=> 42

#
# example 2 - note the how it works recursively
#
   module A
     include Mixable
     module ClassMethods
       def bar() 'forty-two' end
     end
     module InstanceMethods
       def foobar() 42.0 end
     end
   end
   module B
     include A
   end
   class K
     include B # and recurively add ClassMethods from A!
   end
   p K.bar        #=> 'forty=two'
   p K.new.foobar #=> 42.0

#
# example 3 - we needn't both with Mixable if the 'includee' specifies
that it
# wants to to a mixin
#
   module M
     module ClassMethods
       def bar() 42.0 end
     end
     def foo() 42 end
   end
   class C
     mixin M
   end
   p C.bar     #=> 42.0
   p C.new.foo #=> 42

#
# and, of course, it works with objects
#
   mixin M
   p foo #=> 42
   class << self
     p bar #=> 42.0
   end

end


-a
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2006-06-14 21:19
(Received via mailing list)
transfire@gmail.com wrote:
> Problem is that 'extend @class_extension' doesn't work unless it occurs
> _after_ the module_eval(&blk). Which means later changes to the
> extensions module will have no effect on modules that have already
> included it. Not good. So unless I've misanalyzed this, I think keeping
> a running list of extension modules, more like my previous
> implementation post, is going to be neccessary.

Why should the order of calling extend and adding methods matter? It
doesn't seem to in this example, but this is much simpler than
class_extension:

module M
  def foo; p "FOO"; end
end

class C
  extend M
end

module M
  def bar; p "BAR"; end
end

C.foo
C.bar

__END__

"FOO"
"BAR"
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-14 21:28
(Received via mailing list)
Joel VanderWerf wrote:

> Why should the order of calling extend and adding methods matter? It
> doesn't seem to in this example, but this is much simpler than
> class_extension:

It's a little more subtle than that, because it has to do with modules
included in modules.

irb(main):001:0> module M
irb(main):002:1>   def foo; p "FOO"; end
irb(main):003:1> end
=> nil
irb(main):004:0> module N
irb(main):005:1>   def bar; p "BAR"; end
irb(main):006:1> end
=> nil
irb(main):007:0> module O
irb(main):008:1>   def baz; p "BAZ"; end
irb(main):009:1> end
=> nil
irb(main):010:0> module M
irb(main):011:1>   include N
irb(main):012:1> end
=> M
irb(main):013:0> class C
irb(main):014:1>   extend M
irb(main):015:1> end
=> C
irb(main):016:0> C.foo
"FOO"
=> nil
irb(main):017:0> C.bar
"BAR"
=> nil
irb(main):018:0> module M
irb(main):019:1>   include O
irb(main):020:1> end
=> M
irb(main):021:0> C.baz
NoMethodError: undefined method `baz' for C:Class
        from (irb):21
        from :0

T.
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2006-06-14 21:49
(Received via mailing list)
transfire@gmail.com wrote:
> Joel VanderWerf wrote:
>
>> Why should the order of calling extend and adding methods matter? It
>> doesn't seem to in this example, but this is much simpler than
>> class_extension:
>
> It's a little more subtle than that, because it has to do with modules
> included in modules.

Yes, I see your point. Two questions:

1. Are chained inclusions of modules a good way to propagate class
methods? (Do we really need this feature, for good design?)

2. Do we really want the modules to respond to the class methods that
they provide to classes? (I think that's the way your class_extension
works, but in my own test implementation I avoided that.)
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-14 21:59
(Received via mailing list)
Joel VanderWerf wrote:
> Yes, I see your point. Two questions:
>
> 1. Are chained inclusions of modules a good way to propagate class
> methods? (Do we really need this feature, for good design?)

Yes, b/c if you don't you won't be able to propogate data/control
through the hierarcy. i.e. calling #super.

> 2. Do we really want the modules to respond to the class methods that
> they provide to classes? (I think that's the way your class_extension
> works, but in my own test implementation I avoided that.)

In some cases one will, so it important to have the ability. In
contrast, I could not think of any benefit of not having the modules
respond, nor any adverse effect from having them always respond. So I'd
say yes here as well.

Make sense?

T.
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-14 23:37
(Received via mailing list)
ara.t.howard@noaa.gov wrote:
> can someone point out to me what's wrong with this impl?  it's simple,
> works
> in a recursive way, is self documenting, is already used, and is 34 lines
> long.  as far as i can tell it already does every required and it very
> simple
> and robust.

I can of course only speak for myself, but I'm not fond of the idea of
reserving constant names when it's really not needed -- "class
extension", as it seemingly has come to be named, should be handled
internally, within the module that defines such an extension. Even if
the ClassMethods and InstanceMethods modules are private, they would
still clutter the namespace. By using anonymous modules in instance
variables you avoid collisions (not completely of course.)

Furthermore, I feel that it's redundant to have an entire "child" module
for the instance methods.

Not that the implementation is bad at all; I just don't think it's
streamlined enough to make it to the core, although that obviously isn't
my call to make.


Cheers,
Daniel
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-15 02:19
(Received via mailing list)
On Thu, 15 Jun 2006, Daniel Schierbeck wrote:

hi daniel-

> I can of course only speak for myself, but I'm not fond of the idea of
> reserving constant names when it's really not needed -- "class extension",
> as it seemingly has come to be named, should be handled internally, within
> the module that defines such an extension. Even if the ClassMethods and
> InstanceMethods modules are private, they would still clutter the namespace.
> By using anonymous modules in instance variables you avoid collisions (not
> completely of course.)
>
> Furthermore, I feel that it's redundant to have an entire "child" module for
> the instance methods.

indeed.  read the code though, it's not needed - it's just for symmtry.

> Not that the implementation is bad at all; I just don't think it's
> streamlined enough to make it to the core, although that obviously isn't my
> call to make.

here's my complaint against any non-module based solution: it wildly
violates
POLS due to the change in scoping.  i'm not saying it can't be done, but
read
over these tests/demos carefully and you'll see it's not quite as
straightforward as you're suggesting - espcially if you want 'normal'
class
method definition semantics.

i think you may be able to work around some of these issues, but some
are part
of ruby.



harp:~ > ruby a.rb
_______________________________________________________________________________
recursive inclusion : meta_module
_______________________________________________________________________________
a.rb:140:in `included': stack level too deep (SystemStackError)
 	from a.rb:140:in `included'
 	from a.rb:9
 	from a.rb:197:in `show'
 	from a.rb:194:in `show'
 	from a.rb:4


_______________________________________________________________________________
recursive inclusion : mixable
_______________________________________________________________________________
success


_______________________________________________________________________________
double inclusion : meta_module
_______________________________________________________________________________
a.rb:140:in `append_features': cyclic include detected (ArgumentError)
 	from a.rb:140:in `included'
 	from a.rb:37
 	from a.rb:197:in `show'
 	from a.rb:194:in `show'
 	from a.rb:23


_______________________________________________________________________________
double inclusion : mixable
_______________________________________________________________________________
success


_______________________________________________________________________________
namespace pollution : meta_module
_______________________________________________________________________________
a.rb:73: N polluted! (RuntimeError)
 	from a.rb:197:in `show'
 	from a.rb:194:in `show'
 	from a.rb:60


_______________________________________________________________________________
namespace pollution : mixable
_______________________________________________________________________________
success


_______________________________________________________________________________
constant scoping : meta_module
_______________________________________________________________________________
a.rb:104:in `const_get': uninitialized constant #<Module:0xb75ccc50>::C
(NameError)
 	from a.rb:104
 	from a.rb:131:in `meta_module'
 	from a.rb:102
 	from a.rb:197:in `show'
 	from a.rb:194:in `show'
 	from a.rb:100


_______________________________________________________________________________
constant scoping : mixable
_______________________________________________________________________________
success



harp:~ > cat a.rb
#
# recursive inclusion
#
   show('recursive inclusion', :meta_module){
     module M
       meta_module{
         def foo() :foo end
       }
       include M
     end
   }
   show('recursive inclusion', :mixable){
     module M
       module ClassMethods
         def foo() :foo end
       end
       mixin M
     end
   }
#
# double inclusion
#
   show('double inclusion', :meta_module){
     module M
       meta_module{
         def foo() :foo end
       }
     end
     module N
       meta_module{
         def bar() :bar end
       }
       include M
     end
     class C
       include M
       include N
     end
   }
   show('double inclusion', :mixable){
     module M
       module ClassMethods
         def foo() :foo end
       end
     end
     module N
       module ClassMethods
         def bar() :bar end
       end
       mixin M
     end
     class C
       mixin M
       mixin N
     end
   }
#
# namespace pollution
#
   show('namespace pollution', :meta_module){
     module N
       meta_module{
         def foo() :foo end
       }
     end
     module M
       include N
       meta_module{
         def bar() :foo end  # defined in N!
       }
     end
     if N.respond_to? 'bar'
       raise 'N polluted!'
     else
       true
     end
   }
   show('namespace pollution', :mixable){
     module N
       module ClassMethods
         def foo() :foo end
       end
     end
     module M
       mixin N
       module ClassMethods
         def bar() :foo end
       end
     end
     if N.respond_to? 'bar'
       raise 'N polluted!'
     else
       true
     end
   }

#
# constant scoping
#
   show('constant scoping', :meta_module){
     module N
       meta_module{
         C = true
         const_get :C
       }
     end
     true
   }
   show('constant scoping', :mixable){
     module N
       module ClassMethods
         C = true
         const_get :C
       end
     end
     true
   }





BEGIN {
#
# define two impls of class method mixin
#
   META_MODULE_IMPL = lambda {
     class Module
       def meta_module(&block)
         @meta_module ||= Module.new
         @meta_module.module_eval(&block)
         extend(@meta_module)
         @meta_module
       end
       def included(mod)
         mod.extend(@meta_module ||= Module.new)
         if mod.kind_of? Module
           if mod.instance_variables.include? "@meta_module"
             other_meta_module =
mod.instance_variable_get(:@meta_module)
             other_meta_module.send(:include, @meta_module)
           else
             mod.instance_variable_set(:@meta_module, @meta_module)
           end
         end
       end
     end
   }

   MIXABLE_IMPL = lambda {
     module Mixable
       Mixin = lambda do |this, other|
         cm = this.const_get 'ClassMethods' rescue nil
         im = this.const_get 'InstanceMethods' rescue nil
         other.extend cm if cm
         other.module_eval{
           include im if im
           extend RecursiveMixin
         }
       end
       module RecursiveMixin
         def included other
           Mixin[self, other]
           super
         end
       end
       extend RecursiveMixin
     end
     class Object
       def mixin other
         sc =
           class << self
             self
           end
         sc.module_eval{ mixin other }
       end
     end
     class Module
       def mixin other
         other.module_eval{ include Mixable } unless
           Mixable > other
         include other
       end
     end
   }
#
# demonstrate implications of two implimentations of class method mixin
#
   def show label, which, &code
     div = '_' * 79
     puts div
     puts "#{ label } : #{ which }"
     puts div
     impl = Object.const_get(which.to_s.upcase << '_IMPL')
     fork {
       STDOUT.sync = STDERR.sync = true
       impl.call
       ret = code.call
       puts(ret ? 'success' : 'failed')
     }
     Process.wait
   ensure
     2.times{ puts }
   end


}






regards.

-a
E1d641bfe4071a5413bac781f06d3fd1?d=identicon&s=25 Sean O'halpin (sean)
on 2006-06-15 05:14
(Received via mailing list)
On 6/15/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:
>
> here's my complaint against any non-module based solution: it wildly violates
> POLS due to the change in scoping.  i'm not saying it can't be done, but read
> over these tests/demos carefully and you'll see it's not quite as
> straightforward as you're suggesting - espcially if you want 'normal' class
> method definition semantics.
>
> i think you may be able to work around some of these issues, but some are part
> of ruby.
>

[snip persuasive code examples]

You ~could~ get round the constant scoping problem with:

    module N
      meta_module{
        self::C = true
        const_get :C
      }
    end

which is similar to the way we deal with locals shadowing attributes
(and just as likely to catch us out). Also, using:

  mod.instance_variable_set(:@meta_module, @meta_module.clone)

seems to avoid the double inclusion and namespace pollution problems.
I can't see a way to avoid the 'stack level too deep' in recursive
inclusion though.

However, as I said earlier, I think your implementation is the most
straightforward (though I also think that having the InstanceMethods
module in there is obscuring your argument in the present discussion).

Regards,
Sean
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-15 09:57
(Received via mailing list)
ara.t.howard@noaa.gov wrote:
> here's my complaint against any non-module based solution: it wildly
> violates
> POLS due to the change in scoping.  i'm not saying it can't be done, but
> read
> over these tests/demos carefully and you'll see it's not quite as
> straightforward as you're suggesting - espcially if you want 'normal' class
> method definition semantics.

I'm not saying it'll be easy, but I do think it's possible to use
anonymous modules. I'll see if I can find time today to further develop
the existing implementation. There'll be flaws at first, of course, but
if we could avoid the whole "in your face" mentality I think has sprung
up a bit in this thread, I'm sure we'll prevail, as George junior
would've said :)


Daniel
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-15 09:58
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Thu, 15 Jun 2006 04:59:18 +0900, transfire@gmail.com writes:

|> 2. Do we really want the modules to respond to the class methods that
|> they provide to classes? (I think that's the way your class_extension
|> works, but in my own test implementation I avoided that.)
|
|In some cases one will, so it important to have the ability. In
|contrast, I could not think of any benefit of not having the modules
|respond, nor any adverse effect from having them always respond. So I'd
|say yes here as well.

I consider a module as a place holder of methods to be injected into
classes.  From that view, a module does not have to have same methods
that classes will have; it is not a class.  If you consider a module
as a ripped off class, you need to go for multiple inheritance.

							matz.
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-15 09:58
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Thu, 15 Jun 2006 02:25:14 +0900, transfire@gmail.com writes:

|Problem is that 'extend @class_extension' doesn't work unless it occurs
|_after_ the module_eval(&blk). Which means later changes to the
|extensions module will have no effect on modules that have already
|included it. Not good. So unless I've misanalyzed this, I think keeping
|a running list of extension modules, more like my previous
|implementation post, is going to be neccessary.

It's how modules work, at least under the current implementation.
If you want/have to fix it, you should fix it all.

|  class Module
|
|    def class_extension( *mods, &blk )
|      unless @class_extension
|        @class_extension = Module.new
|        def @class_extension.append_features( base )
|          append_features_without_extension( base )
|        end
|        extend @class_extension
|      end
|      @class_extension.module_eval(&blk) if blk
|      @class_extension
|    end

I am not going to call "extend @class_extension" for the target
module.  That's not necessary, even bad from my eyes.  I think this is
where our opinions differ.

							matz.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-15 10:13
(Received via mailing list)
Yukihiro Matsumoto wrote:
> |implementation post, is going to be neccessary.
> |          append_features_without_extension( base )
> |        end
> |        extend @class_extension
> |      end
> |      @class_extension.module_eval(&blk) if blk
> |      @class_extension
> |    end
>
> I am not going to call "extend @class_extension" for the target
> module.  That's not necessary, even bad from my eyes.  I think this is
> where our opinions differ.

You mean to say you are going to eval the code directly into the target
module instead?

T.
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-15 10:47
(Received via mailing list)
Okay, I've sorted out a few of the problems, and I hope I haven't
created new ones.

   1 class Module
   2   def class_extension(&block)
   3     @class_extension ||= Module.new
   4     @class_extension.module_eval(&block)
   5   end
   6
   7   def included(mod)
   8     if not @class_extension.nil?
   9       case mod
  10       when Class
  11         mod.extend(@class_extension)
  12       when Module
  13         unless mod.instance_variables.include? "@class_extension"
  14           mod.instance_variable_set(:@class_extension, Module.new)
  15         end
  16         other = mod.instance_variable_get(:@class_extension)
  17         other.send(:include, @class_extension)
  18       end
  19     end
  20   end
  21 end


Please report any errors here, sans bashing.


Daniel
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-15 11:15
(Received via mailing list)
Update:

   class Module
     def class_extension(&block)
       @class_extension ||= Module.new
       @class_extension.module_eval(&block)
     end

     def included(mod)
       if not @class_extension.nil?
         mod.extend(@class_extension)
         if mod.instance_of? Module # better way?
           unless mod.instance_variables.include? "@class_extension"
             mod.instance_variable_set(:@class_extension, Module.new)
           end
           other = mod.instance_variable_get(:@class_extension)
           other.send(:include, @class_extension)
         end
       end
     end
   end


Cheers,
Daniel
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-15 13:22
(Received via mailing list)
This should fix the recursion issue:

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

     def included(mod)
       mod.extend(class_extension)
       if mod.instance_of? Module
         unless mod.instance_variables.include? "@class_extension"
           mod.send(:class_extension)
         end
         other = mod.instance_variable_get(:@class_extension)
         other.send(:include, class_extension)
       end
     end
   end

I'm sure there are more issues, but I'll fix them as they come.


Cheers,
Daniel
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-15 14:11
(Received via mailing list)
Simplification. Tell me if I should stop spamming.

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

     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
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-15 14:48
(Received via mailing list)
Daniel Schierbeck 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.
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-15 16:39
(Received via mailing list)
transfire@gmail.com 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
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-15 17:13
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Thu, 15 Jun 2006 23:38:24 +0900, Daniel Schierbeck
<daniel.schierbeck@gmail.com> 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.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-15 17:52
(Received via mailing list)
On Fri, 16 Jun 2006, Yukihiro Matsumoto 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 Schierbeck <daniel.schierbeck@gmail.com> 
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
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-15 18:02
(Received via mailing list)
#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
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-15 18:12
(Received via mailing list)
This seems to have been resolved in the latest version.


Daniel
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-15 18:12
(Received via mailing list)
On Fri, 16 Jun 2006, Daniel Schierbeck 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
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-15 18:19
(Received via mailing list)
Daniel Schierbeck 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.
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-15 18:20
(Received via mailing list)
ara.t.howard@noaa.gov 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
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-15 18:23
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Fri, 16 Jun 2006 01:10:53 +0900, ara.t.howard@noaa.gov 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.
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-15 18:33
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Fri, 16 Jun 2006 00:50:43 +0900, ara.t.howard@noaa.gov 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.
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-15 18:33
(Received via mailing list)
transfire@gmail.com 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
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-15 18:34
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Fri, 16 Jun 2006 01:16:08 +0900, transfire@gmail.com 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.
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-15 18:50
(Received via mailing list)
Yukihiro Matsumoto wrote:
> ... 'funcall' is a lisp
> function name that has its own history.

Ahh, the Ruby Collage of Inspiration. Cool.


Cheers,
Daniel
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-15 18:50
(Received via mailing list)
On Fri, 16 Jun 2006, Yukihiro Matsumoto 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
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-15 18:53
(Received via mailing list)
On Fri, 16 Jun 2006, Yukihiro Matsumoto 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
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-15 19:03
(Received via mailing list)
Yukihiro Matsumoto 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.
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-16 02:05
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Fri, 16 Jun 2006 01:51:32 +0900, ara.t.howard@noaa.gov writes:

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

|   code.gsub! /M/, 'C'

Yes, thank you.

							matz.
E1d641bfe4071a5413bac781f06d3fd1?d=identicon&s=25 Sean O'halpin (sean)
on 2006-06-16 03:18
(Received via mailing list)
On 6/15/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> 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! :)

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
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-16 04:04
(Received via mailing list)
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 Green for starting it! (Did you get your answer?
;)

BTW Is this possibly the longest ruby-talk thread in history? Sheesh!
;)

> Gotta love this list.

Indeed.

T.
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-16 04:38
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Fri, 16 Jun 2006 02:01:53 +0900, transfire@gmail.com writes:

|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.

Good point.  We will have __funcall__ as well.  Thank you.

							matz.
31ab75f7ddda241830659630746cdd3a?d=identicon&s=25 Austin Ziegler (austin)
on 2006-06-16 05:41
(Received via mailing list)
On 6/15/06, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:
> |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.
> Good point.  We will have __funcall__ as well.  Thank you.

Should we have __dup__ and __clone__ and __class__ and __object_id__?

I am already using #__send__ in preference to #send when I need the
functionality, but it would be nice to know that for those methods we
literally cannot get along without ... we have access to without
rebind hacks.

-austin
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-06-16 06:36
(Received via mailing list)
On Jun 15, 2006, at 11:40 PM, Austin Ziegler wrote:

> Should we have __dup__ and __clone__ and __class__ and __object_id__?
>
> I am already using #__send__ in preference to #send when I need the
> functionality, but it would be nice to know that for those methods we
> literally cannot get along without ... we have access to without
> rebind hacks.

I can definitely see __class__ and __object_id__. #dup and #clone
though it seems to me that there would be plently of situations that
someone would want to override those, and you would want the
overridden versions. Failing that maybe add a #copy method that would
default to an alias of #dup but would be for the express purpose of
overriding for "deeper" copies. I guess it's a judgement call. (One I
thankfully don't have to make).
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-16 09:14
(Received via mailing list)
Austin Ziegler wrote:
> functionality, but it would be nice to know that for those methods we
> literally cannot get along without ... we have access to without
> rebind hacks.

I agree. And I did add __class__ in basic object, though I find it's
not so often needed b/c of 'X === x'.  Nonetheless it certainly seems
like one of the fundamentals. BTW, we have __id__ already, so I don't
think __object_id__ is needed.

I've also expiremented with two other methods, #__self__ (alias
#object) which is a Functor that binds subsequent calls to Object. Eg.
x.__self__.class will return the class of x even if x.class won't. I
took it a step further with #as / #__as__, in which one can specify
which ancestor to bind to instead of just Object.
x.__as__(Enumerble).each, for instance.

Food for thought.

T.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-16 09:21
(Received via mailing list)
Logan Capaldo wrote:

> I can definitely see __class__ and __object_id__. #dup and #clone
> though it seems to me that there would be plently of situations that
> someone would want to override those, and you would want the
> overridden versions. Failing that maybe add a #copy method that would
> default to an alias of #dup but would be for the express purpose of
> overriding for "deeper" copies. I guess it's a judgement call. (One I
> thankfully don't have to make).

Of course __dup__ and __clone__ can be overridden too. But I imagine
that would create quite a bit of additional work, so maybe these two
are just better left as exceptions ...not sure.

T.
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-06-16 11:58
(Received via mailing list)
Hi --

On Fri, 16 Jun 2006, Yukihiro Matsumoto wrote:

> |     class_extension{ attr_accessor 'a' }
>  p M.a # => 42
Will this happen if the module is included in another module?  If so,
I'm wondering whether a more generic name, without "class" in it,
could be used instead of "class_extension".


David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

See what the readers are saying about "Ruby for Rails"!
http://www.rubypowerandlight.com/quotes
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-06-16 12:14
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Fri, 16 Jun 2006 18:56:23 +0900, dblack@wobblini.net writes:

|>  class C
|>    include M
|>  end
|>  M.a = 42
|>  p M.a # => 42
|
|Will this happen if the module is included in another module?  If so,
|I'm wondering whether a more generic name, without "class" in it,
|could be used instead of "class_extension".

That's where I am wondering.  Using the Daniel's code:

  module M
    class_extension do
      def foo
      end
    end
  end
  module M2
    include M
  end
  class C
    include M2
  end

  M.foo   # => NoMethodError
  M2.foo  # => Error? (should it affect modules?)
  C.foo   # => Error? (should class_extension be propagated?)

If 'class_extension' affects modules as well, do you think of any
more generic name, in place of "class" extension?

							matz.
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-16 12:48
(Received via mailing list)
Yukihiro Matsumoto wrote:
>     include M2
>   end
>
>   M.foo   # => NoMethodError
>   M2.foo  # => Error? (should it affect modules?)

No, the class extension should be included into both modules and
classes. I think this'll get too complex otherwise, with users wondering
why #include works differently in classes and modules.


> C.foo   # => Error? (should class_extension be propagated?)

I'm not sure on that one, though I'd default to say yes, it should be
propagated.


> If 'class_extension' affects modules as well, do you think of any
> more generic name, in place of "class" extension?

I temporarily used #metamodule or something similar, as I saw the class
extension as a "module above the module", that got included into the
"class above the class". That may be rubbish, but it's how I think of
it.


Cheers,
Daniel
C2cd72c24873556e278b44b5b3c7ef33?d=identicon&s=25 Carlos (Guest)
on 2006-06-16 13:03
(Received via mailing list)
Yukihiro Matsumoto wrote:

> |
>     end
>   end
>   module M2
>     include M
>   end
>   class C
>     include M2
>   end
>
>   M.foo   # => NoMethodError
>   M2.foo  # => Error? (should it affect modules?)

I'd say yes.

>   C.foo   # => Error? (should class_extension be propagated?)

I'd say no, but maybe there should be another function to import it.

   module M
     class_extension do
       def foo
       end
     end
   end
   module M2
     include_class_extension M
   end
   module M3
     include M2
   end

   M.foo  #=> error
   M2.foo #=> error
   M3.foo #=> no error

> If 'class_extension' affects modules as well, do you think of any
> more generic name, in place of "class" extension?

module_extension, included_module_features, define_module_features, ...?
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-16 14:53
(Received via mailing list)
Yukihiro Matsumoto wrote:

>   M2.foo  # => Error? (should it affect modules?)
>
> If 'class_extension' affects modules as well, do you think of any
> more generic name, in place of "class" extension?

The name is not really incorrect because

  class << Module.new ; self.class ; end  #=> Class

>   C.foo   # => Error? (should class_extension be propagated?)

It needs to propagate.  Otherwise it defeats much of the purpose.
Without propapation we could not create module adapters, or use #super,
which is absolutely vital when using it to track meta information, like
a method annotation for example.

T.
04a0f1074e1b621746954ccc73eec7d7?d=identicon&s=25 Matthew Harris (kuja)
on 2006-06-16 14:57
(Received via mailing list)
Heh, soon we'll end up adding other __*__ methods for the sake of it.

I don't see this as a benefit, and I've never really got down and
said, "Gee, I wish this method wasn't overridable!", and if I have, it
would have been for `send' which was easily remedied with `__send__'.

Also, for #object_id, there's already a #__id__.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-16 16:18
(Received via mailing list)
On Fri, 16 Jun 2006, Yukihiro Matsumoto wrote:

>  end
>  class C
>    include M2
>  end
>
>  M.foo   # => NoMethodError
>  M2.foo  # => Error? (should it affect modules?)
>  C.foo   # => Error? (should class_extension be propagated?)
>
> If 'class_extension' affects modules as well, do you think of any more
> generic name, in place of "class" extension?

   singleton_methods &block

-a
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-16 16:40
(Received via mailing list)
ara.t.howard@noaa.gov wrote:
>> If 'class_extension' affects modules as well, do you think of any more
>> generic name, in place of "class" extension?
>
>   singleton_methods &block

Except it's not restricted to methods. Here's a couple of spinoffs:

   * singleton_module
   * singleton_extension


Cheers,
Daniel
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-16 17:07
(Received via mailing list)
Daniel Schierbeck wrote:
>
Eeek! Please, no "singleton". Anything but "singleton".

T.
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-06-16 17:26
(Received via mailing list)
transfire@gmail.com wrote:
>
> Eeek! Please, no "singleton". Anything but "singleton".

`beer_module'?
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-16 17:45
(Received via mailing list)
On Sat, 17 Jun 2006 transfire@gmail.com wrote:

>
> Eeek! Please, no "singleton". Anything but "singleton".
>

what's wrong with singleton?  alternatives?

-a
E7559e558ececa67c40f452483b9ac8c?d=identicon&s=25 unknown (Guest)
on 2006-06-16 18:04
(Received via mailing list)
On Jun 16, 2006, at 11:43 AM, ara.t.howard@noaa.gov wrote:
> On Sat, 17 Jun 2006 transfire@gmail.com wrote:
>>
>> Eeek! Please, no "singleton". Anything but "singleton".
>>
>
> what's wrong with singleton?  alternatives?

Uh oh.  Here we go again...

Gary Wright
7264fb16beeea92b89bb42023738259d?d=identicon&s=25 Christian Neukirchen (Guest)
on 2006-06-16 18:29
(Received via mailing list)
"Austin Ziegler" <halostatue@gmail.com> writes:

> On 6/15/06, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:
>> |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.
>> Good point.  We will have __funcall__ as well.  Thank you.
>
> Should we have __dup__ and __clone__ and __class__ and __object_id__?

Instead of further pythonizing the language (sorry, couldn't resist),
I'd rather prefer a non-OO way for the tricky cases:

Object.object_id_of myobj
Object.class_of myobj
Object.send_to myobj, :foo

Maybe it's not optimal to make them singleton methods of Object, a
module would probably be better.
31ab75f7ddda241830659630746cdd3a?d=identicon&s=25 Austin Ziegler (austin)
on 2006-06-16 20:00
(Received via mailing list)
On 6/16/06, Christian Neukirchen <chneukirchen@gmail.com> wrote:
> module would probably be better.
I could get behind that. Probably worth an RCR, I think.

-austin
E1d641bfe4071a5413bac781f06d3fd1?d=identicon&s=25 Sean O'halpin (sean)
on 2006-06-16 21:02
(Received via mailing list)
On 6/16/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:
> On Sat, 17 Jun 2006 transfire@gmail.com wrote:
>
> >
> > Eeek! Please, no "singleton". Anything but "singleton".
> >
>
> what's wrong with singleton?  alternatives?
>
> -a
> --
Off the top of my head:

extension &block
inheritance &block
effects &block (in both senses - i.e. this is what it makes happen and
this is what it 'bequeathes' to its inheritors)

Regards,
Sean
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-06-16 23:31
(Received via mailing list)
Hi--

On Fri, 16 Jun 2006, Yukihiro Matsumoto wrote:

> |
>    end
>  end
>  module M2
>    include M
>  end
>  class C
>    include M2
>  end
>
>  M.foo   # => NoMethodError
>  M2.foo  # => Error? (should it affect modules?)

Yes, I think so.

>  C.foo   # => Error? (should class_extension be propagated?)

I think not.  The call to class_extension in M registers a policy on
the part of M.  The policy affects M2, but it should not be shared by
M2.

> If 'class_extension' affects modules as well, do you think of any
> more generic name, in place of "class" extension?

Sean O'H. mentioned "extension", which I think is as good as it will
get.  (I'm still not a fan of this whole thing.)


David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

See what the readers are saying about "Ruby for Rails"!
http://www.rubypowerandlight.com/quotes
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-17 15:02
(Received via mailing list)
Austin Ziegler wrote:
> > Maybe it's not optimal to make them singleton methods of Object, a
> > module would probably be better.
>
> I could get behind that. Probably worth an RCR, I think.

I expiremented with that idea a while back when I was doing some work
on the BasicObject class. I expirementd with offering a variety of
"extenal" meta-programming methods as module methods of ObjectSpace.
And I also tried using global variable lambas, eg. $object_id[myobj].
While the former was more POLS, the globals actually proved nicer to
use.

Yet I'm not sure its the right approach. Is it that big a deal to have
a handful of __ methods? If so then maybe the milder appraoch of a
single non-overwriteable "self knowledge" method would be a good way,
'myobj.self(:id)' or even 'myobj.self.id' for instance.

T.
4674615d2cf231975c741731be9a8685?d=identicon&s=25 why the lucky stiff (Guest)
on 2006-06-17 17:22
(Received via mailing list)
On Sat, Jun 17, 2006 at 01:28:12AM +0900, Christian Neukirchen wrote:
> Instead of further pythonizing the language (sorry, couldn't resist),
> I'd rather prefer a non-OO way for the tricky cases:
>
> Object.object_id_of myobj
> Object.class_of myobj
> Object.send_to myobj, :foo

So, it quacks like a dog, but if we really press it, we can get a proper
fowlsome noise?

  >> duck.quack
  >> #<CryOfAlarm("GAA! GAA!")>
  # .. uh.. let's try this again, that was a bit noisey
  >> Animal.come_on_gimme_the_real_duck_quack duck
  => #<BasicQuack>

I'm not saying it's a totally bad idea.  I just don't think I'd be able
to spot
when Object.object_id_of is necessary.  I mean when in advance do you
know
you're getting nasty mangled objects that don't behave?  I generally try
to use
__send__ right now.  I figure if __send__ is overridden, then someone
has
figured out a better way to dispatch methods.  Hey, let's let them try.

_why
7264fb16beeea92b89bb42023738259d?d=identicon&s=25 Christian Neukirchen (Guest)
on 2006-06-17 20:31
(Received via mailing list)
why the lucky stiff <ruby-talk@whytheluckystiff.net> writes:

>
> figured out a better way to dispatch methods.  Hey, let's let them try.
And what if I still feel more meta than you? ;-)

Note that e.g. Ruby itself won't call the updated definition of
__send__...
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-06-18 03:40
(Received via mailing list)
why the lucky stiff wrote:
>
> figured out a better way to dispatch methods.  Hey, let's let them try.
I was looking over the Kernel methods, thinking about which one's are
vital and and/or meta in nature. And really it seems like almost all of
them are, which probably accounts for why they are in Kernel to begin
with. They are (v1.8.4):

["==", "===", "=~", "__id__", "__send__", "class", "clone", "display",
"dup", "eql?", "equal?", "extend", "freeze", "frozen?", "hash", "id",
"inspect", "instance_eval", "instance_of?", "instance_variable_get",
"instance_variable_set", "instance_variables", "is_a?", "kind_of?",
"method", "methods", "nil?", "object_id", "private_methods",
"protected_methods", "public_methods", "respond_to?", "send",
"singleton_methods", "taint", "tainted?", "to_a", "to_s", "type",
"untaint"]

Looking through these, it really becomes hard to say what should stay
and what should go in forming a  near empty class. And given their
nature one might be inclined to think that most of these should be
external to the object anyway. I mean, should the class really have the
"right" to override #object_id?

After thinking about this further. I started to wonder if maybe the
__foo__ notation could be a special syntax Ruby would always take as a
method call bound to Kernel, analogous to:

  def method_missing( meth, *args, &blk )
    if md = /^__(.*)__$/.match( meth.to_s )
      Kernel.instance_method( md[1] ).bind(self).call(*args, &blk)
    end
    super
  end

This example implmentation still allows them to be overridden. Whether
that should be so is debatible, though _why makes a good point. If you
think you can make a better quack than go for it.

Also interesting, If you look as Ruby 1.9 specs you'll see there is now
a BasicObject that lies behind Object and Kernel. These are the methods
it isolates:

  [ "__send__", "funcall", "__id__", "==", "send", "respond_to?",
"equal?", "object_id"]

I'm all for the idea of a BasicObject b/c it will make OpenStruct and
classes of that ilk more standardized and robust. But I was wondering
what if you wanted to make a subclass of BasicObject but there were one
or perhaps a few other Kernel methods you needed to include. Say for
instance you needed #instance_variables. How would you be able to
include that since Kernel is not even in the class hiearchy? Maybe it
isn't that important, but it doesn't seem like it should be out the
question.

Of course, we take another step back we see that all of this crops up
b/c the OpenStruct pattern is just too damn nice not use, even though
Hash will usually work just as well. But who wants to do
foo[:a][:b][:c] when they can do foo.a.b.c? Moreover an OpenStruct can
quack like any duck; a hash can't. But then the little edge problems
arise, b/c an OpenStruct pattern is generally used for something that
can have completely arbitarty keys. And that's when the Kernel methods
can get in the way, not to mention any other internal methods you might
would like the class to have. So you clear out most of then methods
with BasicObject or BlankSlate or what have you and then some one elses
lib croaks b/c it can't #dup you object or whatever. Yeah, it can get
nasty.

Okay, I'm starting to rattle on, but one last thought occurs to me:
might the whole issue go away if private and public methods could have
their own separate namespaces? The public method would still be
available privately, but if a specifcally private method of the same
name were defined it would be used when called without a receiver,
rather than the public one. The even for an OpenStruct one could
generally ensure the proper response from vital methods by using
#__funcall__.

T.
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-08-03 14:23
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Thu, 15 Jun 2006 16:35:58 +0900, transfire@gmail.com writes:

|> I am not going to call "extend @class_extension" for the target
|> module.  That's not necessary, even bad from my eyes.  I think this is
|> where our opinions differ.
|
|You mean to say you are going to eval the code directly into the target
|module instead?

No.  I just said `I am not going to call "extend @class_extension" for
the target module'.

							matz.
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-08-03 14:23
(Received via mailing list)
Yukihiro Matsumoto wrote:
> ... I just said `I am not going to call "extend @class_extension" for
> the target module'.

Let me get this straight:

   module A
    class_extension do
      def foo
        :foo
      end
    end
   end

   module B
     include A
   end

   B.foo   #=> NoMethodError

Correct? It would make the implementation a whole lot easier...


Daniel
0ec4920185b657a03edf01fff96b4e9b?d=identicon&s=25 Yukihiro Matsumoto (Guest)
on 2006-08-03 14:23
(Received via mailing list)
Hi,

In message "Re: Why the lack of mixing-in support for Class methods?"
    on Thu, 15 Jun 2006 17:16:01 +0900, Daniel Schierbeck
<daniel.schierbeck@gmail.com> writes:

|Let me get this straight:
|
|   module A
|    class_extension do
|      def foo
|        :foo
|      end
|    end
|   end
|
|   module B
|     include A
|   end
|
|   B.foo   #=> NoMethodError
|
|Correct? It would make the implementation a whole lot easier...

I meant A.foo would raise NoMethodError.  Since class_extension
defines a part to inject into the inclusion target, I think B.foo
works as natural consequence of inclusion.  If B.foo raises an error,
it makes class/module separation a lot wider than it currently is.
It is an interesting idea though.

							matz.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 unknown (Guest)
on 2006-08-03 14:23
(Received via mailing list)
Yukihiro Matsumoto wrote:

> No.  I just said `I am not going to call "extend @class_extension" for
> the target module'.

Okay. Whew. Scared me for a moment. Your last comment about me going
for "multiple inheritance" threw me --that's not what I meant, I just
said I saw no adverse effect. But I see your point about the intent is
class injection. So that makes sense.

T.
5da4c52f43677f395aff5bde775593c2?d=identicon&s=25 Daniel Schierbeck (dasch)
on 2006-08-03 14:23
(Received via mailing list)
Yukihiro Matsumoto wrote:
> I meant A.foo would raise NoMethodError.  Since class_extension
> defines a part to inject into the inclusion target, I think B.foo
> works as natural consequence of inclusion.

Splendid! That was also my first hunch. I'll just fix my implementation
then...


Cheers,
Daniel
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.