Base class vs. module inclusion

Showing 1-48 of 48 messages
Base class vs. module inclusion Michael Schürig 5/14/12 11:44 PM

Here's a question related to OO in Ruby, even if not directly related to
OOR. When you implement some general functionality, you basically have
to options. Implement it in a base class to be subclassed, or implement
it in a module to be included. The usage of each one looks like this

  class Concrete < Base
    ...
  end

  class Concrete
    include Base
    ...
  end

As far as I can tell, in recent years there has been a trend toward the
second. Are there any reasons or circumstances where the first
alternative is preferable?

Michael

--
Michael Schuerig
mailto:mic...@schuerig.de
http://www.schuerig.de/michael/
Re: Base class vs. module inclusion Kevin Rutherford 5/14/12 11:48 PM
Hi,

On Tue, May 15, 2012 at 7:44 AM, Michael Schuerig
<michae...@schuerig.de> wrote:
>
> Here's a question related to OO in Ruby, even if not directly related to
> OOR. When you implement some general functionality, you basically have
> to options. Implement it in a base class to be subclassed, or implement
> it in a module to be included.

There's a third option: put it in an object. before considering the
other two options you mentioned, I always look very hard to see if
there's a way to put common stuff in a new class. Patterns such as
Decorator, Facade and Delegate really help here, and unless there are
other constraints (eg. framework rules) I generally find inheritance
and mixins to be unnecessary (and much much much harder to test).
Cheers,
    Kevin
--
http://www.kevinrutherford.co.uk
http://myonepage.com/kevinrutherford
+44 (0) 797 356 3521
Re: Base class vs. module inclusion avalanche123 5/14/12 11:51 PM
The way I approach it is by using a base class when it should be
possible to instantiate it directly, while mixins used for things that
should always be included and don't make sense on their own

Bulat

On May 14, 2012, at 11:44 PM, Michael Schuerig
Re: Base class vs. module inclusion Neal Clark 5/14/12 11:53 PM
Seems to me it's when a given subclass _proximally is_ a thing of its
base class in the context of your program. Like a circle is a shape
more than it is a database abstraction.

The trend towards inclusion is basically 3rd party libs getting out of
your way so you can implement an object model for your specific
needs... cause you only get one superclass.

-n



On May 14, 2012, at 11:44 PM, Michael Schuerig
<michae...@schuerig.de> wrote:

>
Re: Base class vs. module inclusion Sammy Larbi 5/15/12 4:54 AM


On Tue, May 15, 2012 at 1:48 AM, Kevin Rutherford <ke...@rutherford-software.com> wrote:
Hi,

On Tue, May 15, 2012 at 7:44 AM, Michael Schuerig
<michae...@schuerig.de> wrote:
>
> Here's a question related to OO in Ruby, even if not directly related to
> OOR. When you implement some general functionality, you basically have
> to options. Implement it in a base class to be subclassed, or implement
> it in a module to be included.

There's a third option: put it in an object. before considering the
other two options you mentioned, I always look very hard to see if
there's a way to put common stuff in a new class. 


+1 for object composition.

Sam
 
Re: Base class vs. module inclusion Michael Schürig 5/15/12 7:40 AM
Care to elaborate? I don't think these apply to the same cases, but I'm
not completely sure I understand what you have in mind.
Re: Base class vs. module inclusion Sammy Larbi 5/16/12 4:19 AM
You are right, it doesn't apply to the same cases you mentioned, which are both reuse by inheritance, where your object ends up being a kind of something other than itself, either by directly inheriting from another class, or including its functionality via module.

But my response and Kevin's are directed at this statement:

When you implement some general functionality, you basically have
to options. Implement it in a base class to be subclassed, or implement
it in a module to be included.

You don't have to think about it only in terms of sharing via inheritance: another option is to consider just using another object altogether. 

If you weren't constrained by the framework to inherit from ActiveRecord::Base for persisting objects, for example, you might prefer to do something like this:

class Post
  def initialize 
    @persistance = PostPersister.new(self) 
  end
 
  def save
    @persistance.save
  end
  # ... more stuff
end 

This way you're using a totally different object in the 3rd way mentioned -- now a Post object is not an ActiveRecord::Base, it's an object on its own which achieves code reuse and gets its functionality by being composed of other objects (hence the term "object composition").

So now your Post is just a Post, it only does what you think a Post should do based on your domain model, and you aren't forced into choosing between hiding a bunch of inherited methods versus supporting an "infinite interface" (to use a term Avdi used in the book).

Hope that helps,
Sam

Re: Base class vs. module inclusion Kevin Rutherford 5/16/12 4:57 AM
> class Post
>   def initialize
>     @persistance = PostPersister.new(self)
>   end
>
>   def save
>     @persistance.save
>   end
>   # ... more stuff
> end

Yes.
Alternatively, and depending on circumstance, you might use a
persistence decorator:

class PersistentPost
  def initialize(post)
    @post = post
  end

  def something_a_post_can_do
    @post.something_a_post_can_do   # or use delegattion
  end

  def save
    # do stuff with @post
  end
end

Note that the GoF explicitly tell us to "prefer composition over
inheritance", and that's what most of their design patterns are
attempting to achieve.
Cheers,
Kevin
Re: Base class vs. module inclusion Michael Schürig 5/16/12 8:22 AM
I see. And I agree, yes, object composition is the normal case. My
original question was worded sloppily, in that I was assuming that I
wanted a new class to inherit methods from another class or module.
Re: Base class vs. module inclusion Michael Schürig 5/16/12 8:28 AM
On Wednesday 16 May 2012, Kevin Rutherford wrote:
> > class Post
> >   def initialize
> >     @persistance = PostPersister.new(self)
> >   end
> >
> >   def save
> >     @persistance.save
> >   end
> >   # ... more stuff
> > end
>
> Yes.
> Alternatively, and depending on circumstance, you might use a
> persistence decorator:
>
> class PersistentPost
>   def initialize(post)
>     @post = post
>   end
>
>   def something_a_post_can_do
>     @post.something_a_post_can_do   # or use delegattion
>   end
>
>   def save
>     # do stuff with @post
>   end
> end

As it happens, this is pretty close to my actual case. I have entity
classes who are basically ActiveModel + (homegrown) associations. There
I want some kind of inheritance from a base class or module to support
something like

class Blog < Entity
  has_many :posts
end

But the whole mechanism for actually loading and storing associated
objects is implemented in other classes Entity doesn't know anythig
about. And instance of these later I can inject for different uses, say
when mocking them in tests. Also, I'm going to change from a superclass
to including a module.
Re: Base class vs. module inclusion diabolo 5/16/12 9:04 AM
You might want to have a look at SRP (single responsibility principle). The approach you seem to want to follow will probably give you a class with a large method footprint and a number of different responsibilities. (note: including a module increases the method footprint of the class). This generally makes things more difficult, for you, for your tests, and for anybody who uses your code. You might be better seeing if you can split up these responsibilities; and if you do have to bring all these responsibilities into a single class, use composition and delegation so your aggregating class just has one responsibility (to delegate functionality to other classes).

All best

Andrew

Michael
--
Michael Schuerig
mailto:mic...@schuerig.de
http://www.schuerig.de/michael/



--
------------------------
Andrew Premdas
Re: Base class vs. module inclusion Michael Schürig 5/16/12 9:31 AM
On Wednesday 16 May 2012, Andrew Premdas wrote:
> On 16 May 2012 16:28, Michael Schuerig <michae...@schuerig.de>
 [...]
> > As it happens, this is pretty close to my actual case. I have
> > entity classes who are basically ActiveModel + (homegrown)
> > associations. There I want some kind of inheritance from a base
> > class or module to support something like
> >
> > class Blog < Entity
> >
> >  has_many :posts
> >
> > end
> >
> > But the whole mechanism for actually loading and storing associated
> > objects is implemented in other classes Entity doesn't know anythig
> > about. And instance of these later I can inject for different uses,
> > say when mocking them in tests. Also, I'm going to change from a
> > superclass to including a module.
>
> You might want to have a look at SRP (single responsibility
> principle).

Oh, I'm quite aware of the SRP since about the time RCM, as Uncle Bob
was called then, first wrote about it sometime in the late 90s. :-)

> The approach you seem to want to follow will probably
> give you a class with a large method footprint and a number of
> different responsibilities. (note: including a module increases the
> method footprint of the class). This generally makes things more
> difficult, for you, for your tests, and for anybody who uses your
> code. You might be better seeing if you can split up these
> responsibilities; and if you do have to bring all these
> responsibilities into a single class, use composition and delegation
> so your aggregating class just has one responsibility (to delegate
> functionality to other classes).

I'm curious, what was it in my formulation that made you think I'd end
up with a class violating the SRP? Yes, including modules increases the
footprint, but it is increased by methods I *want*: basically, methods
that make my "entities" work nicely with controllers and forms (supplied
by ActiveModel) and associations (implemented myself). All things
related to loading/saving and accessing associations is delegated to
other objects who are injected into the entities at appropriate times.
Re: Base class vs. module inclusion Gregory Brown 5/16/12 9:54 AM


On Tuesday, May 15, 2012 2:44:20 AM UTC-4, mschuerig wrote:

Here's a question related to OO in Ruby, even if not directly related to
OOR. When you implement some general functionality, you basically have
to options. Implement it in a base class to be subclassed, or implement
it in a module to be included.

Hi, I wrote a couple articles on this topic for Practicing Ruby that you and the other folks here might be interested in. It's actually a pretty complicated question!

Criteria for Disciplined Inheritance, Part 1:
http://practicingruby.com/articles/shared/yddazggrvift

Criteria for Disciplined Inheritance, Part 2:
http://practicingruby.com/articles/shared/lxgettcjiggh

Since Practicing Ruby is a paid service, the discussions there are open only to subscribers, but I'm happy to answer any questions about these articles here.
 
Re: Base class vs. module inclusion diabolo 5/16/12 5:46 PM

I'm not sure, probably the context of the overall discussion, and the phrasing of the original post. Anyhow apologies for my misjudgment


All best

Andrew
 


Re: Base class vs. module inclusion Mark Wilden 5/17/12 9:25 AM
On Wednesday, May 16, 2012 4:57:59 AM UTC-7, Kevin Rutherford wrote:
 
Note that the GoF explicitly tell us to "prefer composition over
inheritance", and that's what most of their design patterns are
attempting to achieve.

Actually, out of 23 patterns in the book, only 2 do not use inheritance (Singleton and Memento) - either in the pattern itself, or in the pattern's clients.

///ark

Mark Wilden
Web Applications Developer
California Academy of Sciences
Re: Base class vs. module inclusion gicappa 5/17/12 12:50 PM
Hi,
using inheritance _to extend behavior_ is not a good idea because you might end up with implicit dependencies on hierarchies of objects.
If you use composition instead you can avoid this problem enforcing encapsulation of the behavior and avoid breaking the OCP.

This doesn't mean you should never use inheritance (GoF says 'favor' composition) but use it just to specialize abstractions and let abstract objects talk only with other abstract objects.

Here is first trivial - and I hope not too stupid :) - example that comes to my mind:

class PrinterDriver
   def common_task
     ...
   end

   def print
     # it might be an empty method
   end
end

class HpPrinterDriver < PrinterDriver
   def print
     # doing the specific hp printer work here
     # using common_task if needed
   end
end

is a good inheritance because you can avoid bothering about detail of specific printer driver and put it in an encapsulated and bounded place and you can add another kind of printer just adding classes without changing code (EpsonPrinter < Printer)

Instead:

class MultiFunctionPrinterDriver < PrinterDriver
    def scan
        ...
    end
end

class HpMultiFunctionPrinterDriver < HpPrinterDriver
    def scan
        ...
    end
end

is a bad inheritance model because you are messing up two different abstraction coupling them in an hierarchy.
So to create an EpsonMultiFunctionPrinterDriver you are forced to create an EpsonPrinterDriver replicating the hierarchy.
In addition if you want to modify the HpPrinterDriver you could break encapsulation of HpMultiFunctionPrinterDriver that can access and use the internals of HpPrinterDriver.

Ciao,
--
gk
Re: Base class vs. module inclusion Steve Klabnik 5/17/12 12:53 PM
>   def print
>     # it might be an empty method
>   end

This is _incredibly_ silly in Ruby.
Re: Base class vs. module inclusion avalanche123 5/17/12 1:04 PM
Hello everyone,

This is an interesting discussion and something I've been wondering
about myself since I come from Java-like languages background and the
concept of modules in Ruby seemed very unusual.

Here is how I make such decision - use inheritance where it should be
possible to instantiate a parent class directly to just add some
additional behavior to child:

class BankAccount
  def deposit(amout)
    # some logic
  end
end

class LoggableBankAccount < BankAccount
  include Logging

  def deposit(amount)
    log "deposited #{amount}"
    super
  end
end

In the above example both bank accounts can be directly instantiated
and used, while LoggableBankAccount will write audit logs on every
action.
The above example also demonstrates Logging module, which makes no
sense to be instantiated and used standalone and serves only to
enhance other classes.

To sum up - use inheritance when you're can instantiate the Base, use
module when Base doesn't make sense as an independent object.

Bulat
Re: Base class vs. module inclusion gicappa 5/17/12 1:28 PM
That's where the 'might' comes from: a lot of doubts :) Suggestions of a better way to deal it?

I'm still trying to mix and match the java world concepts I've left with the ruby ones I'm (happily) in and so, day by day, I'm discovering that the OO principles are real common ground between the two.
And it seems to me that the historical ruby community is going down the way of enforcing principles and (not all) patterns, so I'm happy to share ideas and thought about this.

Ciao,
--
gk

Re: Base class vs. module inclusion Steve Klabnik 5/17/12 1:32 PM
Sorry for being terse, I'm supposed to be doing work. ;)

These two things are equivalent in Ruby. One of them feels like Ruby,
one of them feels like Java:

class A
end

class B < A
  def foo
    "b foo"
  end
end

class C < A
  def foo
    "c foo"
  end
end

and


class A
  def foo
  end
end

class B < A
  def foo
    "b foo"
  end
end

class C < A
  def foo
    "c foo"
  end
end

At the _very least_, throw a NotImplementedError in foo in A.

TL;DR: Duck typing solves the same problem without trying to create
'abstract classes'.
Re: Base class vs. module inclusion avalanche123 5/17/12 1:33 PM
to me a Module *is* an abstract class
Re: Base class vs. module inclusion Steve Klabnik 5/17/12 1:35 PM
Abstract classes are so that you can make paramaterized types in a
statically typed system, modules are for namespacing or for
cross-cutting concerns.
Re: Base class vs. module inclusion eric 5/17/12 1:43 PM
If one considers inheritance/mixins and composition as two different ways to "extend" objects, then it seems that the more shared implementation there is in the extended for the extendees, then the more inheritance and "mixins" make sense over composition.

Sent from my iPhone
Re: Base class vs. module inclusion Rick DeNatale 5/17/12 1:43 PM


On Thu, May 17, 2012 at 12:25 PM, Mark Wilden <ma...@mwilden.com> wrote:
On Wednesday, May 16, 2012 4:57:59 AM UTC-7, Kevin Rutherford wrote:
 
Note that the GoF explicitly tell us to "prefer composition over
inheritance", and that's what most of their design patterns are
attempting to achieve.

Actually, out of 23 patterns in the book, only 2 do not use inheritance (Singleton and Memento) - either in the pattern itself, or in the pattern's clients.

But that's almost  certainly be 3 of the GOF were c++ guys.  Although the book takes a fair amount of inspiration from Smalltalk, what came out, particularly in the details is much more applicable to statically typed languages like C++ and to a lesser degree Java, than it is to dynamically typed languages like Smalltalk and Ruby.

I got to know all 4 of the GOF pretty well, John and Richard from IBM, Ralph and Erich from the earliest days of OOPSLA, and Erich later as as a colleague at OTI/IBM.  I have a copy of the GOF book signed by all four and Ralph added "Sorry there isn't more Smalltalk in here."

In retrospect I'm even sorrier, since that book did more than to popularize the notion that OO was about type hierarchies and coupling of type and implementation rather than about loose implementation via messaging and implementation hiding.

--
Rick DeNatale

Google+: +Rick DeNatale
Blog: http://talklikeaduck.denhaven2.com/
Github: http://github.com/rubyredrick
Twitter: @RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
Re: Base class vs. module inclusion Wil Moore 5/17/12 1:49 PM
I've found that the GOF book does a great job of getting you up and running; however, there are a lot language specific idioms that it doesn't account for. Through lots of trial and error, I've found the following to be my preference for where to use inheritance vs. composition:

module StorageAgnostic

  class FileStore
    # common filestore methods
  end

  class LocalFilesystem < FileStore
    # optionally override common filestore methods for special needs
  end

  class RackspaceCloud < FileStore
    include HttpTransport
    include AuthHttpBasic

    # optionally override common filestore methods for special needs
  end

  class GoogleDrive < FileStore
    include HttpTransport
    include AuthOauth

    # optionally override common filestore methods for special needs
  end

  class AmazonS3 < FileStore
    include S3FlavoredRestHttpTransport
    include AuthCustomHttpHeaders

    # optionally override common filestore methods for special needs
  end

end


What you get here is a common base (is-a relationship in FileStore), then you get to "cherry-pick" in your cross-cutting concerns via mixing in modules.


--Wil Moore III
@wilmoore

Re: Base class vs. module inclusion gicappa 5/17/12 1:55 PM

> Sorry for being terse, I'm supposed to be doing work. ;)
No worries at all for short or late answers, in Italy it's 10:43 PM so I'm just having fun with ML and coding :)

> These two things are equivalent in Ruby. One of them feels like Ruby,
> one of them feels like Java:
<snips/>

> At the _very least_, throw a NotImplementedError in foo in A.
ouch, this was my first thought but it seemed to me too... javish! :)

> TL;DR: Duck typing solves the same problem without trying to create
> 'abstract classes'.
ok got it, thanks.

But I'm curious to understand what do you think about the small analysis I made on inheritance.
Do you agree with it - apart from the javish code :)?

Ciao,
--
gk

Re: Base class vs. module inclusion Sammy Larbi 5/17/12 1:58 PM


On Thu, May 17, 2012 at 3:32 PM, Steve Klabnik <st...@steveklabnik.com> wrote:
Sorry for being terse, I'm supposed to be doing work. ;)

These two things are equivalent in Ruby. One of them feels like Ruby,
one of them feels like Java:

class A
end

class B < A
 def foo
   "b foo"
 end
end

class C < A
 def foo
   "c foo"
 end
end

and


class A
 def foo
 end
end

class B < A
 def foo
   "b foo"
 end
end

class C < A
 def foo
   "c foo"
 end
end


At the _very least_, throw a NotImplementedError in foo in A.

TL;DR: Duck typing solves the same problem without trying to create
'abstract classes'.


I think it depends. Overall, I'd like to see the NotImplementedError at least, if the intent is that all subclasses override #foo.  But I don't see a problem with providing a blank default implementation if there's a reason it should be blank.

If A can be instantiated into an object, we ought to think about LSP here. 

I think there's also something to be said about documenting our intent. If all objects which descend from A ought to have that method, then it ought to be in A.

Would you share your thoughts light of those assertions? (Feel free to finish your work first. =) I've got to get back to mine as well.)

Thanks,
Sam





Re: Base class vs. module inclusion gicappa 5/17/12 2:02 PM

On May 17, 2012, at 10:43 PM, Eric Steen wrote:

> If one considers inheritance/mixins and composition as two different ways to "extend" objects, then it seems that the more shared implementation there is in the extended for the extendees, then the more inheritance and "mixins" make sense over composition.

IMHO using just mixins and inheritance you miss object encapsulation that allows to better segregate responsibility and tackle part of complexity of the business logic.

Ciao,
--
gk
Re: Base class vs. module inclusion Sammy Larbi 5/17/12 2:10 PM


I'd also add that, IMO, shared implementation shouldn't be a concern with regard to the statement "more shared implementation ... the more inheritance ... make[s] sense."

I think "shared interface" would be a better phrase than "shared implementation" ... and that may be what was meant by it. 

Eric, would you clarify or explain a little more why that's the case?

Sam
  
Re: Base class vs. module inclusion Gregory Brown 5/17/12 2:14 PM

This hits the nail on the head about one of the most significant 
differences between composition and inheritance. Big systems exhibit 
this problem most notably:

 >> (ActiveRecord::Base.instance_methods - Object.methods).count
=> 125
 >> ActiveRecord::Base.ancestors.count
=> 32

I had linked to a pair of Practicing Ruby articles before that cover 
pretty much everything that has been discussed here so far, but I wasn't 
doing that to sell my work!

A few months ago, I read two papers (one by M. Sakkinen and one by 
Liskov/Wing which was the source of
the Liskov Substitution Principle), and they thoroughly broke my
brain. I wrote up a comprehensive summary of how I felt these
papers applied to Ruby and ran it in my journal. I've gone ahead
and copied my articles over to Gist so that there is now
a comment thread that anyone can use on them (not just PR subscribers).
Would love to hear feedback there, or here!

https://gist.github.com/2721607
 
Re: Base class vs. module inclusion Sammy Larbi 5/17/12 2:27 PM

On Thu, May 17, 2012 at 4:14 PM, Gregory Brown <gregory...@gmail.com> wrote:
I had linked to a pair of Practicing Ruby articles before that cover 
pretty much everything that has been discussed here so far, but I wasn't 
doing that to sell my work!

A few months ago, I read two papers (one by M. Sakkinen and one by 
Liskov/Wing which was the source of
the Liskov Substitution Principle), and they thoroughly broke my
brain. I wrote up a comprehensive summary of how I felt these
papers applied to Ruby and ran it in my journal. I've gone ahead
and copied my articles over to Gist so that there is now
a comment thread that anyone can use on them (not just PR subscribers).
Would love to hear feedback there, or here!

https://gist.github.com/2721607


Thanks for sharing those, I appreciate it, even though I haven't made the time to read through them yet. 

I do have the browser open to them though, and will get to them soon!

Sam 

Re: Base class vs. module inclusion Gregory Brown 5/17/12 2:35 PM


On Thursday, May 17, 2012 5:27:50 PM UTC-4, Sammy Larbi wrote:

Thanks for sharing those, I appreciate it, even though I haven't made the time to read through them yet. 

I know there is an awful lot there. But it is concise compared to the source papers at least!
We did start working on a trimmed down version of the recommendations of when to use what, but never got around to publishing it. I've attached a PDF with the rough draft of it.

-greg 
Re: Base class vs. module inclusion Gregory Brown 5/17/12 2:37 PM
God, that PDF formatted horribly. Now I remember why we didn't publish it. Please disregard!
Re: Base class vs. module inclusion Michael Schürig 5/17/12 2:39 PM
On Thursday 17 May 2012, avalanche123 wrote:
> To sum up - use inheritance when you're can instantiate the Base, use
> module when Base doesn't make sense as an independent object.

I feel uncomfortable with that. I don't have an argument at hand, just a
hunch that may be dating back to my C++ days long ago. Anyway, I prefer
to instantiate only leaf classes.

Relating back to my original questions about base class vs. module
inclusion, I have changed my code in such a way that inheritance is
reserved for domain modelling. I use modules to mix in implementations
of other, technically-inspired interfaces such as validation, callbacks,
the generic machinery for associations.

Michael

--
Michael Schuerig
mailto:mic...@schuerig.de
http://www.schuerig.de/michael/
Re: Base class vs. module inclusion Steve Klabnik 5/17/12 2:42 PM
Before I really reply:
http://blog.steveklabnik.com/posts/2012-05-07-mixins--a-refactoring-anti-pattern
Re: Base class vs. module inclusion Michael Schürig 5/17/12 2:31 PM
On Thursday 17 May 2012, Gian Carlo Pace wrote:
> > At the _very least_, throw a NotImplementedError in foo in A.
>
> ouch, this was my first thought but it seemed to me too... javish! :)

I'd say go ahead and raise an exception. In ruby we have no other
straightforward way to enforce the contract between superclass and
subclass.
Re: Base class vs. module inclusion gicappa 5/17/12 3:26 PM
> Relating back to my original questions about base class vs. module
> inclusion, I have changed my code in such a way that inheritance is
> reserved for domain modelling. I use modules to mix in implementations
> of other, technically-inspired interfaces such as validation, callbacks,
> the generic machinery for associations.
Could please expand the concept of "inheritance is reserved for domain modeling" ? In which cases?

BTW my summarizations are:

* inheritance when the two objects share the same behavior and the base object is an abstract concept of the derived one.
* mixin when you want to share a common behavior that is not dependend on the type of the object (or as Steve said better a cross cutting concern)
* composition when you want to enrich the behavior of another object

WDYT?

Ciao,
--
gk
Re: Base class vs. module inclusion gicappa 5/17/12 3:39 PM
>> ouch, this was my first thought but it seemed to me too... javish! :)
> I'd say go ahead and raise an exception. In ruby we have no other
> straightforward way to enforce the contract between superclass and
> subclass.
This is a good starting point: should we enforce any contract in ruby code? Or duck typing is the ruby alternative to the "design by contract" Meyer's mantra (where inheritance can express part of the contract)?

My opinion is that DbC is still valid but I could be eventually biased by my history.

What do you think?
Ciao,
--
gk
Re: Base class vs. module inclusion eric 5/17/12 3:41 PM
I'd also add that, IMO, shared implementation shouldn't be a concern with regard to the statement "more shared implementation ... the more inheritance ... make[s] sense."

I think "shared interface" would be a better phrase than "shared implementation" ... and that may be what was meant by it. 

Eric, would you clarify or explain a little more why that's the case?



I think a good example is the template method pattern, where subclasses can hook into the interfaces of a base/mixin. With composition this might be more complicated depending in your implementation of course. If you have a very strong 'is a' relationship, inheritance could be the way to go. ActiveRecord objects, on the other hand usually don't fit "is an active record object", because they are usually much more than that, most importantly in the concept space, i.e.. "Comment". Thus the SRP is violated and it is obvious that inheritance may not be the first choice.



Sent from my iPhone
Re: Base class vs. module inclusion Michael Schürig 5/17/12 3:54 PM
I see your point, I think, but the Post/PostMapper implementation
doesn't look very attractive to me. I'd have to see actual code using
Post and PostMapper, but so far, in my imagination, it seems rather
unwieldy. Say, those posts have comments. Then, in addition to the
PostMapper, I get a CommentMapper. Basically, for every domain entity, I
get a corresponding mapper class. And the relationships among domain
entities are mirrored by relationships among mappers. The PostMapper
needs to know about CommentMapper, in order to first save the post
itself, then extract its comments and save them using a CommentMapper.

I currently prefer a solution where domain entities know a slight bit
about persistence. They get injected with (the moral equivalent of) a
mapper object at creation and know that in order to persist themselves,
they need to call a method on that mapper passing in themselves. The
actual persistence is to a REST service, but the entities know nothing
about that.

Additionally, the mapper is generic, and if one entity instance begets
another, it passes the mapper along. As a consequence, I can inject
special mappers for testing in just one place, the root of an aggregate,
and everything just works.

I'd love to show some code, but I work on this stuff in the context of a
closed-source project and therefore unfortunately can't.
Re: Base class vs. module inclusion gicappa 5/17/12 3:56 PM

On May 18, 2012, at 12:41 AM, Eric Steen wrote:

> I'd also add that, IMO, shared implementation shouldn't be a concern with regard to the statement "more shared implementation ... the more inheritance ... make[s] sense."
>
> I think "shared interface" would be a better phrase than "shared implementation" ... and that may be what was meant by it.
>
> Eric, would you clarify or explain a little more why that's the case?
>
>
>
> I think a good example is the template method pattern, where subclasses can hook into the interfaces of a base/mixin. With composition this might be more complicated depending in your implementation of course. If you have a very strong 'is a' relationship, inheritance could be the way to go. ActiveRecord objects, on the other hand usually don't fit "is an active record object", because they are usually much more than that, most importantly in the concept space, i.e.. "Comment". Thus the SRP is violated and it is obvious that inheritance may not be the first choice.
Now I got what you meant and I mostly agree.

Just to avoid the "shared implementation/shared interfaces" dilemma I would use _shared behavior_ for what regards inheritance that actually should define what an "is a" relationship is.

About mixins I still would apply them just to cross cutting concern that should add/decorate behavior to different type of objects.

Ciao,
--
gk
Re: Base class vs. module inclusion Sammy Larbi 5/17/12 4:11 PM


I think if an object is_a? or is kind_of? another object, and you don't adhere to the interface of the class which you say you are, you are not duck typing correctly. Other principles are violated, but this is not duck typing. 

Duck typing means you could put in any object, whether or not it's a kind_of? the object you're expecting, and if it responds_to? the methods you expect it to, then it's quacking like a duck, so you're OK.

But if you say an object is a kind_of? a class, and then you do not enforce the contract, you are actively lying.

I think code that lies may be one of the worst kinds of code.

Sam

Re: Base class vs. module inclusion Michael Schürig 5/17/12 4:13 PM
On Friday 18 May 2012, Gian Carlo Pace wrote:
> > Relating back to my original questions about base class vs. module
> > inclusion, I have changed my code in such a way that inheritance is
> > reserved for domain modelling. I use modules to mix in
> > implementations of other, technically-inspired interfaces such as
> > validation, callbacks, the generic machinery for associations.
>
> Could please expand the concept of "inheritance is reserved for
> domain modeling" ? In which cases?

This is not hard and fast rule for me. I really just made it up, more or
less because in Ruby it is possible.

I'll make up an example. Let's say I have a shop selling books, CDs, and
DVDs. I express that as an abstract class Product with concrete
subclasses Book, CD, and DVD. Also, the shop caters to personal
customers and institutions, whose commonalities I would model pull up
into an abstract Customer class and put the specifics into concrete
PersonalCustomer and InstitutionalCustomer classes. Both Product and
Customer are concepts within the domain, not technical details of the
implementation.

I would not subclass Product or Customer from MyPersistentSuperclass. I
do want validation on those classes and I would include the necessary
modules in the two abstract base classes.
Re: Base class vs. module inclusion eric 5/17/12 4:37 PM
> Just to avoid the "shared implementation/shared interfaces" dilemma I would use _shared behavior_ for what regards inheritance that actually should define what an "is a" relationship is

Not sure what you mean here but the more shared behavior there is, the more likely i would use composition, i.e. strategy etc.., whereas dumb data objects ala DCI, i would be more likely to use large inheritance hierarchies. I think the distinction between these three terms is significant. Implementation could involve data structures, interfaces aren't concerned with those. If a Vehicle always 'has a' color, implementations could differ, e.g. Hex vs. name etc... Now if Vehicle 'has a' Engine.. By all mean composition.

Sent from my iPhone
Re: Base class vs. module inclusion Patrick Mulder 5/18/12 2:57 AM
On Thu, May 17, 2012 at 10:35 PM, Steve Klabnik <st...@steveklabnik.com> wrote:
> Abstract classes are so that you can make paramaterized types in a
> statically typed system, modules are for namespacing or for
> cross-cutting concerns.

Yes, that's a very good point, also backed by Alan Kay, pioneer in
that whole OOP movement:

"I'm not against types, but I don't know of any type systems that
aren't a complete pain, so I still like dynamic typing.
OOP to me means only messaging, local retention and protection and
hiding of state-process, and extreme late-binding of all things. It
can be done in Smalltalk and in LISP. There are possibly other
systems in which this is possible, but I'm not aware of them." ( 2003,
http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay_oop_en )
Re: Base class vs. module inclusion Chris Flipse 5/18/12 7:03 PM



DBC -- full-scale, proper DBC -- I've only seen successfully done in Eiffel ... most other languages don't have all the right hooks to allow the pre/post-conditions to inherit properly.

The Ruby equivalant of the contract is testing, really.  For that sort of thing, I really like RSpec's   shared examples:

shared_examples "a frobinator" do
  it "blends smoothies" do
  end
  it "makes julienne fries" do
  end
end

describe Frobnitz9000 do
  it_should_behave_like "a frobinator"
end

In test/unit land, which I'm less familiar with, you can include a module in your tests (ActiveModel::Lint is, I belive, an example of this):

class TestThing < UnitTest
  include ActiveModel::Lint
  # other tests ....
end

You can test all of the edges of the contract in your unit tests like this, and basically get all the advantages of DBC[0], with the additional advantage of not requiring inheritence, since you don't need that in a duck-typed language.

[0] As I recall (it's been, umm, 15 years), in Eiffel, your pre/post-conditions and invariants were enabled while you ran in development mode.  When violated, they took the program down immedately, so you saw the source of the problem, not the Null pointer error 20 minutes later.  You turned off the invariants in production, however. 

--
:wq

Re: Base class vs. module inclusion Chris Flipse 5/18/12 7:07 PM


On Thu, May 17, 2012 at 6:54 PM, Michael Schuerig <michae...@schuerig.de> wrote:
On Thursday 17 May 2012, Steve Klabnik wrote:
> Before I really reply:
> http://blog.steveklabnik.com/posts/2012-05-07-mixins--a-refactoring-a
> nti-pattern

I see your point, I think, but the Post/PostMapper implementation
doesn't look very attractive to me. I'd have to see actual code using
Post and PostMapper, but so far, in my imagination, it seems rather
unwieldy. Say, those posts have comments. Then, in addition to the
PostMapper, I get a CommentMapper. Basically, for every domain entity, I
get a corresponding mapper class. And the relationships among domain
entities are mirrored by relationships among mappers. The PostMapper
needs to know about CommentMapper, in order to first save the post
itself, then extract its comments and save them using a CommentMapper.

Not quite.  There's an idea in DDD that helps to reduce the scope of what needs to go through mappers:  the Aggregate.  An aggregate is a collection of related domain objects, in a relationship graph determined by the domain.  An aggregate can be composed of any number of Entities (things with IDs) and Value Objects.  You can have several different entities inside of an aggregate:  A Post with many Comments, each Post has an Author and some date information.  The comments don't really have existence independent of the Post, but the Author does.

A basic rule of Aggregates is that you don't build it's components individually -- you don't build the Comments, you assemble the Post aggregate and then reference it's comments _through_ the post.  In this case, the Post is called the Aggregate Root.

Aggregates are added to repositories, which would have the responsibility for figuring out how to map / unmap the entire aggregate -- the Post, it's comments, references to authors and posters.  I've found it's important that the repository not try to cross out of it's own boundaries -- if your comment has an Author, you save the _reference_ to the author, but you don't try to do the job of the Users repository.  That path really does lead to a mess.

Yes, I am building code that works like this right now -- Repositories and aggregates and factories, oh my.  One of the interesting advantages I'm finding is that I can have my repositories totally mask the details of persistence -- that _is_ their point, after all -- and switch data sources using a strategy, to jump from, say, in-memory to ActiveRecord, to a JSON-based web-service.  And, by keeping the repositories separate (that's what I'm getting at in the previous paragraph), I can mix-and-match those strategies, with some aggregates living in MySQL, while others live in "the cloud".  So far, I'm finding it very flexible, though I'm still chasing down some of the duck-typing needed to make ActionPack happy.
 

I currently prefer a solution where domain entities know a slight bit
about persistence. They get injected with (the moral equivalent of) a
mapper object at creation and know that in order to persist themselves,
they need to call a method on that mapper passing in themselves. The
actual persistence is to a REST service, but the entities know nothing
about that.

Additionally, the mapper is generic, and if one entity instance begets
another, it passes the mapper along. As a consequence, I can inject
special mappers for testing in just one place, the root of an aggregate,
and everything just works.

I'd love to show some code, but I work on this stuff in the context of a
closed-source project and therefore unfortunately can't.

Michael

--
Michael Schuerig
mailto:mic...@schuerig.de
http://www.schuerig.de/michael/



--
:wq

Re: Base class vs. module inclusion JEG2 5/22/12 2:19 PM
Here's a late reply, but I wrote about this topic recently in Rubies in the Rough:


James Edward Gray II

More topics »