[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Inheritance, mixins and initializers

Johan Nilsson

12/9/2004 12:14:00 PM

Hi,

I've got a question regarding inheritance, mixins, order of initialization
and calling module/super class "initializers". I'd like to do something
along the lines of (pseudo-ruby code):

---
class Base
def initialize(field_count)
@fields = Array.new(field_count)
end
end

module FooMixin
def initialize(foo_field)
@foo_field = foo_field
self.fields[@foo_field] = Foo.new
end

def foo
self.fields[@foo_field]
end
end

module BarMixin
def initialize(bar_field)
@bar_field = bar_field
self.fields[@bar_field] = Bar.new
end

def bar
self.fields[@bar_field]
end
end

class Derived < Base
include FooMixin
include BarMixin
def initialize
super(2)
FooMixin(0)
BarMixin(1)
end
end

---

Obviously this doesn't work - is there any way of achieving something
similar? The Foo/Bar mixins depend on Base being initialized before them
(ok, maybe not in this particular example).

// Johan

5 Answers

Robert Klemme

12/9/2004 12:27:00 PM

0


"Johan Nilsson" <johan.nilsson@---.esrange.ssc.se> schrieb im Newsbeitrag
news:1102594375.344eddcc1c357ac539046c764cd8c6b8@teranews...
> Hi,
>
> I've got a question regarding inheritance, mixins, order of
initialization
> and calling module/super class "initializers". I'd like to do something
> along the lines of (pseudo-ruby code):
>
> ---
> class Base
> def initialize(field_count)
> @fields = Array.new(field_count)
> end
> end
>
> module FooMixin
> def initialize(foo_field)
> @foo_field = foo_field
> self.fields[@foo_field] = Foo.new
> end
>
> def foo
> self.fields[@foo_field]
> end
> end
>
> module BarMixin
> def initialize(bar_field)
> @bar_field = bar_field
> self.fields[@bar_field] = Bar.new
> end
>
> def bar
> self.fields[@bar_field]
> end
> end
>
> class Derived < Base
> include FooMixin
> include BarMixin
> def initialize
> super(2)
> FooMixin(0)
> BarMixin(1)
> end
> end
>
> ---
>
> Obviously this doesn't work - is there any way of achieving something
> similar? The Foo/Bar mixins depend on Base being initialized before them
> (ok, maybe not in this particular example).

I don't know which real problem you are trying to solve. I can think of
several other approaches. You might want to store your mixin created
instances directly in instance variables and record only the names of
these.

class Foo;end
class Bar;end

class Base
attr_reader :fields
def initialize()
@fields = []
end

def add_field(name) @fields << name end
def all_fields() @fields.map {|f| instance_variable_get f} end
end

module FooMixin
attr_reader :foo

def initialize(*a,&b)
super
@foo = Foo.new
add_field "@foo"
end
end

module BarMixin
attr_reader :bar

def initialize(*a,&b)
super
@bar = Bar.new
add_field "@bar"
end
end

class Derived < Base
include FooMixin
include BarMixin
def initialize
super
end
end


Or you can determine the position automatically.

class Foo;end
class Bar;end

class Base
attr_reader :fields
def initialize()
@fields = []
end
end

module FooMixin
def initialize(*a,&b)
super
@foo_field = self.fields.size
self.fields << Foo.new
end

def foo
self.fields[@foo_field]
end
end

module BarMixin
def initialize(*a,&b)
super
@bar_field = self.fields.size
self.fields << Bar.new
end

def bar
self.fields[@bar_field]
end
end

class Derived < Base
include FooMixin
include BarMixin
def initialize
super
end
end

Kind regards

robert


Robert Klemme

12/9/2004 12:44:00 PM

0


"Robert Klemme" <bob.news@gmx.net> schrieb im Newsbeitrag
news:31qukrF3d6rb9U1@individual.net...
>
> "Johan Nilsson" <johan.nilsson@---.esrange.ssc.se> schrieb im
Newsbeitrag
> news:1102594375.344eddcc1c357ac539046c764cd8c6b8@teranews...
> > Hi,
> >
> > I've got a question regarding inheritance, mixins, order of
> initialization
> > and calling module/super class "initializers". I'd like to do
something
> > along the lines of (pseudo-ruby code):

<snip/>

Here's another solution - even more general:

class Foo;end
class Bar;end
class Baz;end

module FieldMixin
def fields(*classes)
classes.each do |cl|
attr_reader cl.name.downcase.to_sym
end

define_method(:initialize) do
super()
classes.each do |cl|
instance_variable_set( "@#{cl.name.downcase}", cl.new )
end
end
end

def inherited(cl) cl.extend FieldMixin end
end

class Base
extend FieldMixin
end

class Derived < Base
fields Foo, Bar
end

class Der2 < Derived
fields Baz
end

Derived.new.foo
Derived.new.bar
Der2.new.foo
Der2.new.baz

Kind regards

robert



Johan Nilsson

12/9/2004 1:13:00 PM

0


"Robert Klemme" <bob.news@gmx.net> wrote in message
news:31qukrF3d6rb9U1@individual.net...
>
> "Johan Nilsson" <johan.nilsson@---.esrange.ssc.se> schrieb im Newsbeitrag
> news:1102594375.344eddcc1c357ac539046c764cd8c6b8@teranews...
> > Hi,
> >
> > I've got a question regarding inheritance, mixins, order of
> initialization
> > and calling module/super class "initializers". I'd like to do something
> > along the lines of (pseudo-ruby code):
> >
[snip]

>
> I don't know which real problem you are trying to solve. I can think of
> several other approaches. You might want to store your mixin created
> instances directly in instance variables and record only the names of
> these.

Thanks for your reply(s), I'll check them out.

I'm actually mapping a legacy C++ construct to Ruby (no, this is not the
actual code and probably contain some typos):

---
struct FooBarBase {};
struct Foo : FooBarBase {};
struct Bar : FooBarBase {};

class Base
{
protected:
Base(int stuffs)
: m_stuff(stuffs, boost::shared_ptr<FooBarBase>())
{}
void add_stuff_at(int index, boost::shared_ptr<FooBarBase> pfb)
{ m_stuff.at(index) = pfb; }

public:
... functions operating on all "stuff" as a homogenous collection ...
private:
std::vector<boost::shared_ptr<FooBarBase> > m_stuff;
};

template<typename Mixee, int which>
struct FooMixin
{
FooMixin()
: m_pFoo(boost::shared_ptr<Foo>(new Foo))
{ return static_cast<Mixee*>(this)->add_stuff_at(which, m_pFoo); }

const Foo& foo() const
{ return *m_pFoo; }
private:
boost::shared_ptr<Foo> m_pFoo;
};

template<typename Mixee, int which>
struct BarMixin
{ ... };

struct Derived
: Base
, FooMixin<Derived, 0>
, BarMixin<Derived, 1>
{
Derived()
: Base(2)
{}
};

int main(int, char*[])
{
Derived d;
const Foo& foo = d.foo();
d.bar();
return 0;
}

---

To further complicate matters I was trying to use SWIG to inherit from the
C++ class "Base" using the cross-language polymorhism feature. Now I believe
I'll rewrite this part in Ruby instead (but the FooBaseBase stuff etc will
still be wrapped from C++).

Thanks again

// Johan


Robert Klemme

12/9/2004 1:20:00 PM

0


"Johan Nilsson" <johan.nilsson@---.esrange.ssc.se> schrieb im Newsbeitrag
news:1102597896.fbf426538d0cb3bf826331d7f2d41e34@teranews...
>
> "Robert Klemme" <bob.news@gmx.net> wrote in message
> news:31qukrF3d6rb9U1@individual.net...
> >
> > "Johan Nilsson" <johan.nilsson@---.esrange.ssc.se> schrieb im
Newsbeitrag
> > news:1102594375.344eddcc1c357ac539046c764cd8c6b8@teranews...
> > > Hi,
> > >
> > > I've got a question regarding inheritance, mixins, order of
> > initialization
> > > and calling module/super class "initializers". I'd like to do
something
> > > along the lines of (pseudo-ruby code):
> > >
> [snip]
>
> >
> > I don't know which real problem you are trying to solve. I can think
of
> > several other approaches. You might want to store your mixin created
> > instances directly in instance variables and record only the names of
> > these.
>
> Thanks for your reply(s), I'll check them out.
>
> I'm actually mapping a legacy C++ construct to Ruby (no, this is not the
> actual code and probably contain some typos):
>
> ---
> struct FooBarBase {};
> struct Foo : FooBarBase {};
> struct Bar : FooBarBase {};
>
> class Base
> {
> protected:
> Base(int stuffs)
> : m_stuff(stuffs, boost::shared_ptr<FooBarBase>())
> {}
> void add_stuff_at(int index, boost::shared_ptr<FooBarBase> pfb)
> { m_stuff.at(index) = pfb; }
>
> public:
> ... functions operating on all "stuff" as a homogenous collection
....
> private:
> std::vector<boost::shared_ptr<FooBarBase> > m_stuff;
> };
>
> template<typename Mixee, int which>
> struct FooMixin
> {
> FooMixin()
> : m_pFoo(boost::shared_ptr<Foo>(new Foo))
> { return static_cast<Mixee*>(this)->add_stuff_at(which, m_pFoo); }
>
> const Foo& foo() const
> { return *m_pFoo; }
> private:
> boost::shared_ptr<Foo> m_pFoo;
> };
>
> template<typename Mixee, int which>
> struct BarMixin
> { ... };
>
> struct Derived
> : Base
> , FooMixin<Derived, 0>
> , BarMixin<Derived, 1>
> {
> Derived()
> : Base(2)
> {}
> };
>
> int main(int, char*[])
> {
> Derived d;
> const Foo& foo = d.foo();
> d.bar();
> return 0;
> }
>
> ---
>
> To further complicate matters I was trying to use SWIG to inherit from
the
> C++ class "Base" using the cross-language polymorhism feature. Now I
believe
> I'll rewrite this part in Ruby instead (but the FooBaseBase stuff etc
will
> still be wrapped from C++).

This sounds awfully complicated. Good luck!

> Thanks again

You're welcome!

Kind regards

robert

Johan Nilsson

12/13/2004 12:04:00 PM

0


"Robert Klemme" <bob.news@gmx.net> wrote in message
news:31qvkoF3f29i9U1@individual.net...
>

[snip]

>
> class Derived < Base
> fields Foo, Bar
> end

That's most elegant (the "fields Foo, Bar" stuff). I still need to be able
to access the fields by index as well as to name the fields (could be more
than one of a kind), but I think I can manage that by myself.

Thanks,

Johan