Opinion on ClassInherit Include

T

T. Onoma

So I want to include a module and have methods become part of the class, not
the instance. What do others think of this approach?

class Module
alias :append_instance_features :append_features
def append_features(klass)
if constants.include?("ClassInherit")
klass.extend self::ClassInherit
end
append_instance_features(klass)
end
end

Example:

module MyMod
module ClassInherit
attr_accessor :x
def hix
puts "Hi, #{@x}."
end
end
# ...
end

class A
include MyMod
end

A.x = 'you'
A.hix #=> Hi, you.
 
T

ts

T> So I want to include a module and have methods become part of the class, not
T> the instance. What do others think of this approach?

svg% cat b.rb
#!/usr/bin/ruby
module MyMod
attr_accessor :x
def hix
puts "Hi, #{@x}."
end
end

class A
extend MyMod
end

A.x = 'you'
A.hix #=> Hi, you.
svg%

svg% b.rb
Hi, you.
svg%



Guy Decoux
 
T

T. Onoma

svg% cat b.rb
#!/usr/bin/ruby
module MyMod
attr_accessor :x
def hix
puts "Hi, #{@x}."
end
end

class A
extend MyMod
end

A.x = 'you'
A.hix #=> Hi, you.
svg%

You missed the '# ...' in the example. So that dosen't work. You end up having
to have two seperate modules, one of which is included the other of which is
extended. I want a single encapsulation. To clarify:

module MyMod
    module ClassInherit
      attr_accessor :x
      def hix
        puts "Hi, #{@x}."
      end
    end
    def hey
puts "Me, too."
end
  end

  class A
    include MyMod
  end

  A.x = 'you'
  A.hix  #=> Hi, you.
A.new.hey #=> Me, too.
 
T

ts

T> You missed the '# ...' in the example. So that dosen't work. You end up having
T> to have two seperate modules, one of which is included the other of which is
T> extended. I want a single encapsulation. To clarify:

[ryby-talk:39574] but probably this example was given previously.


Guy Decoux
 
R

Robert Klemme

T. Onoma said:
You missed the '# ...' in the example. So that dosen't work. You end up having
to have two seperate modules, one of which is included the other of which is
extended. I want a single encapsulation.

You didn't say so in your original post. And as far as I can see you have
two modules in your example, too. As you obviously noticed, you need to
identify those parts that should go into instances and those for the class
*somehow*. So having two separate modules is really the simplest way.

Kind regards

robert
 
D

David A. Black

Hi --

You missed the '# ...' in the example. So that dosen't work. You end up having
to have two seperate modules, one of which is included the other of which is
extended. I want a single encapsulation. To clarify:

module MyMod
    module ClassInherit
      attr_accessor :x
      def hix
        puts "Hi, #{@x}."
      end
    end
    def hey
puts "Me, too."
end
  end

  class A
    include MyMod
  end

  A.x = 'you'
  A.hix  #=> Hi, you.
A.new.hey #=> Me, too.

As Robert pointed out, you've already got two modules. I think that's
OK, and it's probably better just to do the most direct thing with
them (i.e., use include and extend to modify the behavior of the
objects you want to change, rather than add a special-case layer for
extending class objects).

If you want to have them nested, you could perhaps do:

module MyMod
module Inner
attr_accessor :x
def hix
puts "Hi, #{@x}."
end
end
def blah
puts "hi"
end
end

class A
include MyMod
extend Inner
end

A.x = 'you'
A.hix # => Hi, you.
A.new.blah # => hi


David
 
T

T. Onoma

You didn't say so in your original post. And as far as I can see you have
two modules in your example, too. As you obviously noticed, you need to
identify those parts that should go into instances and those for the class
*somehow*. So having two separate modules is really the simplest way.

Okay, more detail then.

Currently I have a class that can be subclassed to inherit behavior, but I
want to turn that into a mixin module instead. Problem is that the class has
class methods that need to be inherited too. Can't do that with a module, so
I had to figure out a way. Of course I could use two *seperate* modules, as
you say, but then the lib user would have to add two lines of code (an
include and an extend) to get functionality that really belongs together.

So let me ask it this way: I have class behavior and instance behavior that
needs to encapsulated into a single mixin unit. How to do it?
 
D

David A. Black

Hi --

Okay, more detail then.

Currently I have a class that can be subclassed to inherit behavior, but I
want to turn that into a mixin module instead. Problem is that the class has
class methods that need to be inherited too. Can't do that with a module, so
I had to figure out a way. Of course I could use two *seperate* modules, as
you say, but then the lib user would have to add two lines of code (an
include and an extend) to get functionality that really belongs together.

So let me ask it this way: I have class behavior and instance behavior that
needs to encapsulated into a single mixin unit. How to do it?

There's no way to redefine Ruby's sense of a mixin, which happens one
transaction at a time. But if you want to do it all in one command,
you could do:

class Module
def dual_mixin(mod)
include mod
extend mod::Inner
end
end

module MyMod
module Inner
def x
puts "hi"
end
end
def y
puts "hy"
end
end

class C
dual_mixin MyMod
end

C.x # hi
C.new.y # hy

While this carries the usual dangers of adding on to base classes, I
think it's better than actually redefining an existing method of
Module. It also draws attention to the fact that two transactions are
taking place, which in turn makes the subsequent code easier to
understand.


David
 
R

Robert Klemme

T. Onoma said:
Okay, more detail then.

Currently I have a class that can be subclassed to inherit behavior, but I
want to turn that into a mixin module instead. Problem is that the class has
class methods that need to be inherited too. Can't do that with a module, so
I had to figure out a way. Of course I could use two *seperate* modules, as
you say, but then the lib user would have to add two lines of code (an
include and an extend) to get functionality that really belongs together.

So let me ask it this way: I have class behavior and instance behavior that
needs to encapsulated into a single mixin unit. How to do it?

You probably want this which works with a single (!) module. Ha!

module Foo
class <<self
attr_accessor :foo
end

attr_accessor :bar

def self.append_features(cl)
# need a copy of me to avoid state interference
copy = dup
cls = class<<cl;self;end

copy.singleton_methods.each do |m|
cls.send:)define_method, m, copy.method(m).to_proc)
end

super
end
end
Foo.foo = "Foo.foo"
p Foo.foo

class Bar
include Foo
end

bar = Bar.new
bar.bar = "bar.bar"
p bar.bar

Bar.foo = "Bar.foo"
p Bar.foo
# ensure Foo.foo is unchanged
p Foo.foo


Regards

robert
 
R

Robert Klemme

Robert Klemme said:
module,

You probably want this which works with a single (!) module. Ha!

This is a bit nicer:

module Foo
# class code
class <<self
attr_accessor :foo

def append_features(cl)
# need a copy of me to avoid state interference
copy = dup
cls = class<<cl;self;end

copy.singleton_methods.each do |m|
cls.send:)define_method, m, copy.method(m).to_proc)
end

super
end
end

# instance code
attr_accessor :bar
end
 
A

Anders Engström

--h31gzZEtNLTqOjlF
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

=20
You missed the '# ...' in the example. So that dosen't work. You end up h= aving=20
to have two seperate modules, one of which is included the other of which= is=20
extended. I want a single encapsulation. To clarify:
=20
module MyMod
=A0 =A0 module ClassInherit
=A0 =A0 =A0 attr_accessor :x
=A0 =A0 =A0 def hix
=A0 =A0 =A0 =A0 puts "Hi, #{@x}."
=A0 =A0 =A0 end
=A0 =A0 end
=A0 =A0 def hey
puts "Me, too."
end
=A0 end
=20
=A0 class A
=A0 =A0 include MyMod
=A0 end
=20
=A0 A.x =3D 'you'
=A0 A.hix =A0#=3D> Hi, you.
A.new.hey #=3D> Me, too.
=20

The way I handle these situations is:

module MyMod
=20
class << self
def included(klass)
# Also extend the class with
# the features in ClassMixin
klass.__send__:)extend, ClassMixin)
end
end
=20
module ClassMixin
attr_accessor :x
def hix
puts "Hi, #{@x}."
end
end
=20
def hey
puts "Me, too"
end
end

class A
include MyMod
end

HTH. //Anders

--=20
=2E . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
=2E Anders Engstr=F6m (e-mail address removed)
=2E http://www.gnejs.net PGP-Key: ED010E7F
=2E [Your mind is like an umbrella. It doesn't work unless you open it.] =
=20


--h31gzZEtNLTqOjlF
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: Digital signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)

iD8DBQFBHjOkuNLLbe0BDn8RAtNsAJ9c2m9V0UVFOSkMmqrgY3h+SpgwcgCfUPTP
9uV/hErI9ZLVdK+RQPtoyxY=
=Ls06
-----END PGP SIGNATURE-----

--h31gzZEtNLTqOjlF--
 
T

T. Onoma

This is a bit nicer:

module Foo
# class code
class <<self
attr_accessor :foo
def append_features(cl)
# need a copy of me to avoid state interference
copy = dup
cls = class<<cl;self;end
copy.singleton_methods.each do |m|
cls.send:)define_method, m, copy.method(m).to_proc)
end
super
end
end
# instance code
attr_accessor :bar
end

That's pretty clever! And I think that's the kind of functionality most people
would expect. It certainly was what I was looking for... at first.

But now I'm shying away from module class-level methods. In fact, I'm putting
almost all methods into modules now and including/extending them where I need
them. Its to the point that I can clearly identify three type of modules:
mixin, service and namespace. And the service modules I've started writting
just like the mixins but with extend self:

module AService
extend self
def ameth
...
end
...
end
 
T

T. Onoma

The way I handle these situations is:

module MyMod

class << self
def included(klass)
# Also extend the class with
# the features in ClassMixin
klass.__send__:)extend, ClassMixin)
end
end

module ClassMixin
attr_accessor :x
def hix
puts "Hi, #{@x}."
end
end

def hey
puts "Me, too"
end
end

Using the callback here. That works too. I'm wondering if this kind of
functionality is desireable enough to warrent some kind of RCR.
 
R

Robert Klemme

It certainly was what I was looking for... at first.

But now I'm shying away from module class-level methods. In fact, I'm putting
almost all methods into modules now and including/extending them where I need
them. Its to the point that I can clearly identify three type of modules:
mixin, service and namespace. And the service modules I've started writting
just like the mixins but with extend self:

What made you change your mind? I mean, this is exactly what I suggested in
the first place.

Regards

robert
 
T

T. Onoma

What made you change your mind? I mean, this is exactly what I suggested
in the first place.

Sorry, I probably wasn't clear enough. It wasn't so much that I changed my
mind, as I just decided that I prefer the methods at the instance level. The
difference between this:

module Foo
class << eval
def foo
...
end
end
end

And this

module Foo
def foo
...
end
end

At first I was trying to get the former's class-level method to be "class
inheritable" on include (which is what your example succeeds at quite
nicely). But now I'm thinking I like using the later better b/c the code is
more reusable in that form.

That's all I meant. I'm still doing the same thing --using a module in a
module. Although I'm not modifying the Module class itself to do the work
anymore.

Hmmm...That makes me wonder. Who has found a NECESSARY use for modules that
have BOTH mixable methods AND class-level methods?
 
R

Robert Klemme

T. Onoma said:
Sorry, I probably wasn't clear enough. It wasn't so much that I changed my
mind, as I just decided that I prefer the methods at the instance level. The
difference between this:

module Foo
class << eval
def foo
...
end
end
end

And this

module Foo
def foo
...
end
end

At first I was trying to get the former's class-level method to be "class
inheritable" on include (which is what your example succeeds at quite
nicely). But now I'm thinking I like using the later better b/c the code is
more reusable in that form.

That's all I meant. I'm still doing the same thing --using a module in a
module. Although I'm not modifying the Module class itself to do the work
anymore.

So, if I do understand correctly, basically you decided that all "functions"
(i.e. methods you implemented in the module singleton) could go into
instances as well. You probably put them into the module singleton class
because they encapsulated some algorithm that needed no instance state
(hence "functions").
Hmmm...That makes me wonder. Who has found a NECESSARY use for modules that
have BOTH mixable methods AND class-level methods?

All scenarios where that require a per class bookkeeping of what instances
do, which you apparently didn't need.

robert
 
T

T. Sawyer

So, if I do understand correctly, basically you decided that all "functions"
(i.e. methods you implemented in the module singleton) could go into
instances as well. You probably put them into the module singleton class
because they encapsulated some algorithm that needed no instance state
(hence "functions").

That's right. By having the methods at the instance level, I can then include or extend as the case warrents (or needs change).
that have BOTH mixable methods AND class-level methods?

All scenarios where that require a per class bookkeeping of what instances
do, which you apparently didn't need.

Yes, that's true. And I can see that for Classes. But for Modules, their class-level methods aren't inhertable (at least not normally --one can of course use your singleton method copier). So I'm still not sure the two are every really required in the same context. One might do it just for some orginizational reason, I suppose. I.e. These "functions" (per your definition) are useful to these mixable instance methods.

T.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,141
Latest member
BlissKeto
Top