[MUD-Dev] (no subject)

John Buehler johnbue at msn.com
Mon Nov 20 22:02:43 CET 2000


>From: KevinL <darius at bofh.net.au>
>Date: Tue, 21 Nov 2000 11:37:55 +1100

>Essentially, by inheriting, you're assuming that one of the parent objects
>will take full responsibility for the behaviour - one parent or another
will
>win out wrt: what attributes are inherited, where they clash.  If you're
>componentising, you can list all the different values for the different
>attributes (in essence), and write something to control that.

But in an inheritance system, the parent and child classes cooperate in
providing behavior.  Parent classes can provide utility methods that child
classes can employ, child classes can ignore the parent implementation, or
incorporate the parent implementation into their own behavior.

I hope that you're not using attributes as the definitive example of the
sort of problem that needs to be addressed.  Attributes are a fairly simple
problem.  Far more complicated is actual algorithmic behavior that the class
is obligated to perform when its methods are invoked.  To take examples from
the vector component I worked on, the insertion and removal of values is a
bit more complicated than just modifying or retrieving a value.

>For instance, going with the materials example, if I inherit from cloth and
>steel, one or the other object is going to provide the "burnability"
rating.
>If I have an object that contains both cloth and steel objects, and that
>object knows how to manage holding both objects, it can merge the
burnability
>ratings of both, or it can burn one but not the other, or whatever.

In the component case, yup.

>The implementation aspects in inheritance are simply provided by one or the
>other parent.  In component systems, each component gets a chance to have
it's
>say, but it's more likely that you're going to take those decisions out of
the
>hands of the components, and manage it elsewhere - probably in the main
object
>you're creating.

The relationship between base and derived classes is rather strict.  It
results in the statement: I am an example of the base class, and I am
obligated to deliver all aspects of that functionality.  The relationship
between components is whatever you need it to be.  You get to employ other
components in the construction of your component any way that you want.

>Note, this could just as easily be managed with a system that allowed you
to
>refer to your parents explicitly - if I inherit from steel and cloth, I can
>easily intercept a request for burnability, query all my parents
explicitly,
>and make the decisions myself, ala component systems.  So this vague
>difference between "contains" and "is" is what I'm trying to plumb,
>specifically in cases where you can have multiple (parents or components)
but
>the collision between them needs managing.  If you don't need multiple
>(parents or components) then there doesn't appear to be a problem -
likewise,
>if you need multiples but there's no collisions, there's no problem, the
>behaviour is identical (AFAICS) between inheritance and component.

The 'contains' relationship isn't really very interesting in this
discussion.  We're mostly trying to figure out why components are more
interesting when tackling the 'is' relationship.  The difference is that
there is no clear contract between the code that sits in the base class and
the code that sits in the derived class.  There IS a contract, but it hasn't
been captured anywhere.  Making the base class and the derived classes into
discrete components would turn an inheritance system into a component system
(but a rather restricted one).  They would only be able to communicate with
each other through specific interfaces.  Such a component system would still
be limited to a tree composition, with single class representation in the
tree.

> > Inheriting implementation is the problem.  When you inherit
implementation,
> > you have two pieces of software (base and derived classes) that do not
have
> > a clear contract between them.  What is the base class responsible for
and
> > what is the derived class responsible for?  What happens when you
inherit
> > functionality from the same class along two different lineages?  I guess
> > these are the collisions that you're trying to resolve.
>
>Hrm.  I've not had any problems of this sort - I'm using inheritance to
define
>behaviour.  The example I keep giving is the creator example - there's a
bunch
>of methods that make up the "creator" abilities - things like create,
destroy,
>edit, set - which all belong to a single object.  Inherit from that object,
>and you become a creator.  The base class is responsible for anything the
>child chooses not to take responsibility for - which strikes me as the same
as
>component systems.

Yup, that's the same sort of thing that you do in a component system, except
that you'd use the 'creator' class as a tool in the construction of your
class.  The 'creator' methods that you wanted to use, you'd call from your
methods, and the ones you want to supercede, you'd just code up and ignore
the 'creator' class.  And you manually instantiate the 'creator' class when
and if you need it.

>But I'm still not clear on what's meant by "implementation".

I was referring to the code sitting in the base class versus the derived
class.  Some classes do not inherit cleanly, requiring serpentine call
chains that pass between parent and child one or more times.  It's times
like that when not having clear contracts can start to get you into trouble.

> > Whenever you think inheritance, think composition instead.  What if,
instead
> > of inheriting some chunk of functionality, you built it into a
> > self-contained service component that provided the same functionality?
That
> > service component now has to have clearly-defined behavior that anyone
can
> > reuse.  Further, you can use that service component multiple times in
the
> > same component for different purposes.  That is, you can create multiple
> > copies of it for your different purposes.
>
>It seems to me that you're solving problems I wouldn't approach with
>inheritance - inheritance solves the "how do I make something that is x, y,
>and z" really well, whereas composition solves "how do I make something
that
>provides x, y, and z" - the is-a vs. has-a thing I mentioned first time
>around.  Then you're saying replace inheritance with components.  I can
>understand the first bit - they are two different approaches that have
their
>own values - but I can't understand why you'd want to use components where
>inheritance fits well.  You hold up resolving collisions as the main
>advantage, but you still have to resolve them the same way I do with
>inheritance - manually state which behaviour or how to merge the
behaviours.

I'm implementing an 'is a' structure using that service component.
Inheritance IS a composition technique.  It's just clunky and limited.  It
happens to have an implementation in a widely-used language, so it is what
we use.  Components don't resolve 'collision', they avoid having them in the
first place.  Components also permit multiple instances of a class to be
involved in the implementation of a new class, and ensure that strict
contractual separation is always retained between pieces of software.  The
strict separation is invaluable when you want to upgrade your system to have
improved characteristics.

>Then again, it has been noted already elsewhere that I think funny, so
maybe
>it's just me not understanding.

It's not like I talked to Tony and Clemens once and my eyes went wide all of
a sudden  :)

>The example of needing doors in rooms - well, at the moment I have doors as
>objects in their own right, they happen to exist inside rooms.  That's a
>primitive version of components, and I can see a component system working
>nicely for that sort of requirement.  But I can't understand why people are
>convinced it therefore also does a good job where multiple inheritance does
a
>good job - in defining the race, general abilities, etc. - the "class" of
>creature or object or whatever, which is how I'm proposing to use it in
>Moebius.  If you want to mix object type a and object type b, inheriting
from
>both works nicely.  If you want an object to contain potentially multiple
>instances of x, then use a component system.  Yes?

Inheritance works for a certain class of design problems.  Components work
for a superset of design problems.  Why bother with inheritance?

By the way, components are not necessarily about 'has' relationships.  I can
implement an inheritance system using only components behind the scenes,
delivering all the 'is' relationships that you need.  Further, the 'has'
relationship is not far removed from the 'is' relationship.  Possession of a
characteristic can be an 'is' relationship.  For example, a vehicle with
four wheels 'is' a four-wheeled-vehicle.  I can write a contract that a
component can implement (and that another component can require) that
ensures at compile time that what is being communicated between two pieces
of software is a vehicle that 'has' four wheels.  Because it 'is' a
four-wheeled vehicle.

JB


_______________________________________________
MUD-Dev mailing list
MUD-Dev at kanga.nu
https://www.kanga.nu/lists/listinfo/mud-dev



More information about the mud-dev-archive mailing list