Composition: Build objects from other objects

http://www.javaworld.com/javaworld/jw-06-2001/jw-0608-java101.html has
a discussion of composition versus inheritance which I’m trying to apply
to ruby. For discussions sake, I’ll use the classes discussed in the
above linke: Car, Vehicle and Engine. Car inherits from Vehicle, of
course.

Let’s say that Engine is something like:

class Engine

attr_accessor :type

def initialize ()
@type = “generic engine”
end

def vroom ()
puts “vroooooom”
end
end

Vehicle would be something like:

class Vehicle

attr_accessor :engine

def initialize ()
@engine = Engine.new
end
end

class Car < Vehicle

def initialize ()
super()
end
end

then from IRB for instance:

vw_bug = Car.new

then can you make the vw_bug go “vroooooom” and so forth? What would be
the usual way to do this in ruby? When a car is instantiated, should an
engine object get passed to the initializer method?

thanks,

Thufir

Quoth Thufir:

Vehicle would be something like:

then can you make the vw_bug go “vroooooom” and so forth? What would be
the usual way to do this in ruby? When a car is instantiated, should an
engine object get passed to the initializer method?

thanks,

Thufir

vw_bug.engine.vroom() should return “vroooooom” if that’s what you mean.

Sorry, I’m having trouble understanding the question.

Regards,

Thufir wrote:

then can you make the vw_bug go “vroooooom” and so forth? What would be
the usual way to do this in ruby? When a car is instantiated, should an
engine object get passed to the initializer method?

thanks,

Thufir

I do not like (at first view) the idea of this design; it leads to, as
Konrad has correctly observed, to start the car by saying:

vw_bug.engine.vroom()

Should the car user know that he has to tell the car to ask the engine
to rev up? Uhm…

Another take is the following; let’s use a module Engine:

module Engine
attr_accessor :type

def initialize
@type = “generic engine”
end

def vroom
puts “vroooooom”
end
end

class Vehicle
include Engine

def initialize
super
end
end

class Car < Vehicle
def initialize
super
end
end

vw_bug = Car.new
vw_bug.vroom

I am not crazy of the ‘Engine’ Module, but I definitely like to ask the
VW to wroom, without worrying about what is inside,

Raul

On Sat, 17 Nov 2007 14:36:50 +0900, Raul P. wrote:

I do not like (at first view) the idea of this design; it leads to, as
Konrad has correctly observed, to start the car by saying:

vw_bug.engine.vroom()

Fair enough. This is pretty much how Java would do it, and, correct me
if I’m wrong, Smalltalk would probably do similarly.

Put another way: there must be a non-contrived case of composition in
Ruby? Yes?

thanks,

Thufir

Thufir wrote:

Put another way: there must be a non-contrived case of composition in
Ruby? Yes?

I do not really see this as a contrived example of composition; the only
thing that I did not like in the solution we examined is the name
‘Engine’ for a module (for a principle given by D.Black of ‘adjectives
for Modules, and nouns for Classes’…). But I think that the advantage
of a Module in this case trounces the naming principle (so far; perhaps
if design continued…).

For your question about existing examples of ‘Composition’: is this the
eternal OO issue about ‘to have’ vs ‘to be’, and the need for objects to
‘contain’ other objects?

I can only mention the only Ruby application that I looked at: Rails
(not as an user, but internally, to study how Ruby can be used). In
Rails definitely we find objects which ‘contain’ other objects (I will
however use the name ‘reference’ from now on, as I detest the word
‘containment’); for example:

  • the Dispatcher references the objects request, response, and the
    Controller class name
  • the Controller (besides request, response received from the
    Dispatcher) creates an Anonymous Class View and then it instantiates it;
    so it references the instance view (which allows cool tricks for
    instance variables passing).

However, reading Rails, this is NOT what strikes the reader (what is the
big deal about objects referencing other objects?), but rather the
explosive combination of INHERITANCE + MIXIN + METAPROGRAMMING to glue
the system together; for example, what modules ActionController::Helpers
and ClassMethods do on behalf of the Controller (and View).

Here is where Ruby shows facets that other languages cannot even dream
of (and I doubt that we should worry about mimicking with Ruby what
others are doing…); but I am getting off theme.

I hope others will give you more useful examples,
good luck

Raul

On Nov 17, 2007 4:38 AM, Raul P. [email protected] wrote:

if design continued…).
I think there are two issues here. First , how to model the
relationship between car and engine, and second what the interface to
the resulting car should be.

Including an Engine in a car using a module seems wrong to me.

Modules add behavior to an object. That, I think, is the heart of
David’s analogy of Modules as adjectives, the Enumerable module adds
enumerability to an object, the Comparable module adds
comparability…

Cars don’t behave like engines, they use the engine internally to
provide their power source. Modeling the engine as a separate class
allows different models of cars with different types of engines,
likely created using some form of Factory pattern.

vw_bug.engine.vroom violates the ‘law’ of Demeter, which says that
it’s bad style to reach through one object to get at another. The
classic example is modeling a paperboy collecting money from a
customer.

Bad: the paper boy shouldn’t be grabbing money from the customer’s
wallet.

class PaperBoy
def collect_from(customer)
receive_payment(customer, customer.wallet.remove(2.dollars))
end
end

instead of
class Paperboy
def collect_from(customer)
receive_payment(customer, customer.pay(2.dollars))
end
end

So I think that to start the car it should be something like

vw_bug.start

And the start method would cause the engine to start, producing Vrooom
as a side effect, depending on the particular engine which was
installed by the factory.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Doesn’t seeking to mix a method in like that totally break
encapsulation though (and possibly offend our good friend Demeter)?
Why does the whole Car need to know anything about what the Engine is
doing except that it’s doing what it needs to be doing and give it
facilities to do what is needed?

I know you’re going for composition here, but maybe I’m not seeing the
benefit of it or this is a bad example?

–Jeremy

On Nov 17, 2007 1:32 AM, Thufir [email protected] wrote:

Fair enough. This is pretty much how Java would do it, and, correct me
Thufir


http://www.jeremymcanally.com/

My books:
Ruby in Practice

My free Ruby e-book
http://www.humblelittlerubybook.com/

My blogs:
http://www.mrneighborly.com/
http://www.rubyinpractice.com/

On Sat, Nov 17, 2007 at 03:32:03PM +0900, Thufir wrote:

On Sat, 17 Nov 2007 14:36:50 +0900, Raul P. wrote:

Fair enough. This is pretty much how Java would do it, and, correct me
if I’m wrong, Smalltalk would probably do similarly.

Put another way: there must be a non-contrived case of composition in
Ruby? Yes?

What are you looking for? Composition is basically accomplished by
instance variables, even for less contrived cases. As for the
interface, to say TMTOWTDI is an understatement.

require ‘forwardable’
class Engine
def vroom
puts “vroom”
end
end
class MustangEngine
def vroom
puts “rumble”
end
end
class Vehicle
extend Forwardable
def_delegator :@engine, :vroom
attr_accessor :engine
def initialize(engine)
@engine=engine
end
end

v=Vehicle.new(Engine.new)
v.vroom
v.engine=MustangEngine.new
v.vroom

As far as comparison to Java, this example uses duck typing. As long as
it vrooms, you can use it as an engine for your vehicle.

On Sat, 17 Nov 2007 22:40:20 +0900, Liam wrote:

v=Vehicle.new(Engine.new)
v.vroom
v.engine=MustangEngine.new
v.vroom

As far as comparison to Java, this example uses duck typing. As long as
it vrooms, you can use it as an engine for your vehicle.

Hehe, fair enough. Ok, enough Java, it was just an entry point
(although
I would be interested to hear how this is addressed in other OOP
oriented
languages). What stands out about the above is:

1.) I don’t follow all of the syntax, some of it’s over my head (which
is certainly ok).

2.) The engine is being instantiated outside of the class definition.
I was assuming that the engine would be created in the vehicle’s
initialize method. The above technique is to specify the engine when
the
car is “manufactured” by passing a new instance of Engine into the new
Vehicle instance.

-Thufir

Rick Denatale wrote:

Cars don’t behave like engines, they use the engine internally to
provide their power source.

You are right; the word ‘behave’ vs ‘use’ is the key. I could not resist
letting the ‘vroom’ reach the Engine without any intervention from
Vehicle; and I let expediency trounce principle. Your eloquent point is
taken.

vw_bug.engine.vroom violates the ‘law’ of Demeter, which says that
it’s bad style to reach through one object to get at another
So I think that to start the car it should be something like

vw_bug.start

And the start method would cause the engine to start, producing Vrooom
as a side effect, depending on the particular engine which was
installed by the factory.

Here we disagree; not on (what I prefer to call) the “principle of least
knowledge”, but on the example at hand. Removing the ‘vroom’ method from
the user is a bad application of that principle; customers do not always
‘vroom’ to start the car, but to assert something (that I hope I don’t
need to explain). It is enough to watch a city intersection for a few
minutes at a traffic light to see that. Removing the ‘vroom’ is not an
option.

[In fact, I liked the module Engine, exactly because of that: it removed
the need to put knowledge of ‘vroom’ in the Vehicle! but enough on
trying to justify my sin].

I agree that the problem ‘vw_bug.engine.vroom’ is that it breaks
encapsulation.
It seems that we are left with having to put a method in Vehicle to
‘vroom’, just to transmit the command to the engine…

============

Liam wrote:

require ‘forwardable’

class Vehicle
extend Forwardable
def_delegator :@engine, :vroom
attr_accessor :engine
def initialize(engine)
@engine=engine
end
end

v=Vehicle.new(Engine.new)
v.vroom
v.engine=MustangEngine.new
v.vroom

As far as comparison to Java, this example uses duck typing. As long as
it vrooms, you can use it as an engine for your vehicle.

Interesting: this solves the problem of explicitly writing a ‘vroom’
method in Vehicle just to pass it to the Engine. I am not totally
comfortable with the thought of Car ‘delegating to’ (as opposed to
‘having’) an Engine, but it is very elegant.

=========

Personally, I learnt/conclude this (in view of some vagueness in other
comments that seem to say the Composition is not needed):

  1. Thufir was right (aside on the details for how to ‘vroom’), in seeing
    the Engine as a Composition problem for Vehicle. There is an instance
    variable @engine in Vehicle! (shame on me for attempting to remove it
    :-).

  2. we can use ‘Delegation’ to avoid silly ‘bridge methods’ in Vehicle,
    to allow the user reach the Engine, when needed.

Thanks!

Raul

On Nov 16, 2007 9:36 PM, Raul P. [email protected] wrote:

I do not like (at first view) the idea of this design; it leads to, as
attr_accessor :type
class Vehicle
end

Posted via http://www.ruby-forum.com/.

I think this is a pretty bad approach. Consider the following example
(keep in mind I know nothing about cars):

module Engine
attr_reader :engine

def initialize
@engine = :generic
end

def vroom
puts “vrooooooom”
end
end

module Transmission
attr_reader :transmission

def initialize
@transmission = :silky_smooth
end

def vroom
puts “smooth like butta”
end
end

class Car
include Engine
include Transmission

def initialize
super
end
end

By “composing” it with modules like that, we end up with a seriously
broken car - one with no engine! Clearly this approach won’t work.
Part of it is due to how you set stuff up in initialize…but anyway,
the point is that you don’t really use modules for this kind of
composition.

A far better approach would be to have different engine and
transmission objects.

class Engine
def vroom
“vrooooooom”
end
end

class Transmission
def vroom
“smooth like butta”
end
end

class Car
def initialize(engine, transmission)
@engine = engine
@transmission = transmission
end

def vroom
“we go #{@engine.vroom}, #{@transmission.vroom}”
end
end

c = Car.new Engine.new, Transmission.new
c.vroom # => “we go vrooooooom, smooth like butta”

if you want to create a car with its parts already initialized, you
can create a factory method:

def Car.basic
self.new Engine.new, Transmission.new
end

The basic idea is that you don’t really want to make the car object
responsible for a bunch of stuff…you want a bunch of little objects
that know how to do one thing well.

Pat

Pat M. wrote:

I think this is a pretty bad approach. Consider the following example
(keep in mind I know nothing about cars):

Pat, 1 hour before your letter, I wrote a clear admission of sin :slight_smile:

In particular, there is this sentence in Rick’s letter: “a car ‘uses’
the Engine, does not ‘behave’ as an Engine”. That settled the issue.

However, let’s remember that there is often another view for modeling
the world.
I just found in D.Black’s book a very pertinent example (p. 172):

module SelfPropelling # was a Class…
end

class Vehicle
include SelfPropelling
end

class Truck < Vehicle
end

Of course, I let him elaborate, if he has a chance,

Raul

On Sun, Nov 18, 2007 at 05:02:12AM +0900, Thufir wrote:

Hehe, fair enough. Ok, enough Java, it was just an entry point (although
I would be interested to hear how this is addressed in other OOP oriented
languages). What stands out about the above is:

1.) I don’t follow all of the syntax, some of it’s over my head (which
is certainly ok).

It makes use of fowardable[1] from the standard library.

2.) The engine is being instantiated outside of the class definition.
I was assuming that the engine would be created in the vehicle’s
initialize method. The above technique is to specify the engine when the
car is “manufactured” by passing a new instance of Engine into the new
Vehicle instance.

This is more of a design decision. Providing outside access allows for
inversion of control. Perhaps you would prefer to use a factory for
your car?

class Factory
def self.build_car
Car.new(Engine.new)
end
end
class Mechanic
def soup_up(car)
car.engine=MustangEngine.new
end
end

falcon=Factory.build_car
car.vroom
joe=Mechanic.new
joe.soup_up falcon
car.vroom

The interface is of course rather arbitrary. Take a look at logr4[2]
for some interesting composition.

[1]
http://ruby-doc.org/stdlib/libdoc/forwardable/rdoc/files/forwardable_rb.html
[2] http://log4r.sourceforge.net/

On Sun, 18 Nov 2007 07:40:38 +0900, Liam wrote:

falcon=Factory.build_car
car.vroom
joe=Mechanic.new
joe.soup_up falcon
car.vroom

The interface is of course rather arbitrary.

I really like that interface, thanks Liam.

-Thufir

On Nov 18, 7:13 pm, Thufir [email protected] wrote:

I need to learn more about Delegation, and was very interested in the
Factory pattern. It seemed amazingly apropos, given that cars are
manufactured in a factory!

shakes head

T.

On Sun, 18 Nov 2007 06:20:04 +0900, Raul P. wrote:

  1. Thufir was right (aside on the details for how to ‘vroom’), in seeing
    the Engine as a Composition problem for Vehicle. There is an instance
    variable @engine in Vehicle! (shame on me for attempting to remove it .

Well that’s very complimentary of you :slight_smile:

  1. we can use ‘Delegation’ to avoid silly ‘bridge methods’ in Vehicle,
    to allow the user reach the Engine, when needed.

I need to learn more about Delegation, and was very interested in the
Factory pattern. It seemed amazingly apropos, given that cars are
manufactured in a factory!

thanks,

Thufir

On Nov 17, 5:08 pm, “Pat M.” [email protected] wrote:

thanks,

puts "vroooooom"

VW to wroom, without worrying about what is inside,
attr_reader :engine
module Transmission

broken car - one with no engine! Clearly this approach won’t work.
end
@engine = engine

if you want to create a car with its parts already initialized, you
can create a factory method:

def Car.basic
self.new Engine.new, Transmission.new
end

The basic idea is that you don’t really want to make the car object
responsible for a bunch of stuff…you want a bunch of little objects
that know how to do one thing well.

These module examples are flawed. First of all, we need to know what
the use case is. Is this a Nasa Pro Racing Game or a Traffic Light
Simulator? If the later a simple module would probably do fine b/c no
one’s planning on swapping out whole engines (i.e. the car just needs
some engine qualities like vroom). We might write:

module Engine
attr_accessor :type

def vroom
  case type
  when :small
    "vrooom!"
  when :big
    "VROOOOOOOOOM!"
  else
    raise HunkOJunkError
  end
end

end

Now if we need something more fancy. A module still might be useful to
define “Engineability”. You know, a thing that has #fuel and an
#ignition switch can handle Engineability, and that can set up the
delegation we want.

module Engineability
attr :engine

def install_engine(type, ignition, fuel)
  @engine = Engine.factory(type, ignition, fuel)
end

def vroom(level=10)
  ignition.turn unless engine.on?
  engine.throttle += level
end

end

So modules can be useful in a variety of ways.

And really the bottom line is a simple fact, Model != Reality. Try to
use the simplest abstraction possible. We don’t always need to map
real objects <=> program objects, when a simpler abstraction would be
enough --eg. a function would do, but we went and created a whole
Engine class just to go #vroom :wink:

2c.
T.

Thufir wrote:

On Sun, 18 Nov 2007 06:20:04 +0900, Raul P. wrote:

  1. Thufir was right …

Well that’s very complimentary of you :slight_smile:

Just stating a fact in the summary I attempted to do (which does not
include the interesting and alternative view given by Trans, which came
after).

I need to learn more about Delegation…

You can learn what Delegation is very easily; the real work in the
Forwarding module is done in a few lines; I wrote a mini-version of the
module removing exception processing and others things not necessary, to
play with it a bit.

Look at this simplified version (used in the example below):

module Simple_Forwardable

def def_delegator(accessor, method, ali = method)

module_eval(<<-EOS)
  def #{ali}(*args, &block)
     #{accessor}.send(:#{method}, *args, &block)
EOS

end
end

Believe it or not, these 6 lines are the heart of Forwardable; in short,
in case you are not familiar with some things:

a) the method ‘send’ is used to ‘send’ a method name (eg, a method that
you have in a string or symbol, for example that you collected from a
web form or cmd line) to an object.
b) the module_eval allows to define dynamically methods using
interpolation.
That’s it!

If the syntax looks a bit mysterious at first, look at ‘accessor’ as our
@engine object and ‘method’ as ‘vroom’. Notice that we can even name an
alias for ‘vroom’ if in the Vehicle class we prefer a different name
(say, ‘rev’); and,we can even pass arguments (eg, we can pass the level
of the vroom we want). Both are done in the file below.

Below is the file that you may want to play with, if you find it useful
(it combines the 2 examples given by Liam in one file; perhaps there are
too many options, but you will decide that).

Good luck! and perhaps let us know how your project goes and if stood up
well to the shock with ‘reality’ :slight_smile:

Raul

module Simple_Forwardable

def def_delegator(accessor, method, ali= method)
module_eval(<<-EOS)
def #{ali}(*args, &block)
#{accessor}.send(:#{method}, *args, &block)
end
EOS
end

end

from Liam’s examples, combined

class Engine
def vroom(level)
puts “vroom #{level}”
end
end

class MustangEngine
def vroom(level)
puts “rumble #{level}”
end
end

class Vehicle
extend Simple_Forwardable

def_delegator :@engine, :vroom, :rev
attr_accessor :engine

def initialize(engine)
@engine=engine
end
end

class Factory
def self.build_car
Vehicle.new(Engine.new)
end
end

falcon = Factory.build_car
falcon.rev(‘mid’) # => vroom mid

v = Vehicle.new(Engine.new)
v.rev(‘high’) # => vroom high

changing the engine

v.engine = MustangEngine.new
v.rev(‘low’) # => rumble low

Thank you for the information.

I was looking at <http://www.juixe.com/techknow/index.php/2006/06/15/
mixins-in-ruby/> and it has a good discussion and explanation of
“include” versus “extend” for mixins of modules, which I find quite
informative. Bit off topic, but kinda related.

thanks,

Thufir

On Sat, 24 Nov 2007 09:57:42 +0900, Raul P. wrote:

methods free; the module is in fact calling your ‘each’).
Thank you for the heads up, definitely something for me to come back to
:slight_smile:

-Thufir