This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Inheritance vs composition in Scala?

22 replies
Piotr Gabryanczyk
Joined: 2011-12-14,
User offline. Last seen 30 weeks 3 days ago.

In his book "Effective Java" Joshua Bloch advises us to use
composition over inheritance. The main argument for using composition
is that inheritance violates encapsulation. Super class has to expose
it's internals in order for subclass to extend it's behaviour; or
subclass is dangerously dependent on superclass implementation.

I wanted to examine this statement in the context of Scala and it's
trait inheritance mechanism.

Lets have a look at this two examples:

Example 1:

class Delegate{
val work = new Queue[Task]
def receive{
case t @ Task => work add(t)
case Available(worker) => worker ! (work next)
...
}
}

Example 2:

class Delegate with QueueLike{
def receive{
case t @ Task => add(t)
case Available(worker) => worker ! next
...
}
}

Common code:

trait QueueLike[T]{
private[this] val elements = new List[T]
def add(e:T) = ...
def next : T= ...
...
}
class Queue extends QueueLike

In example 2, we clearly see, that there is no danger of weakening
encapsulation, because QueueLike is well specialised and encapsulated.
Well is it? What if someone decided to override enqueue method? This
could make it confusing for other developers reading the code, but
there is no real danger of breaking encapsulation in our example.

Ok it is not about encapsulation. What is it about than?
Example 2 looks like less code (comparing to example 1) and less
clutter. Seems nicer, but... From the API user point of view there is
no reason why Delegate should extend QueueLike. It is Delegate's
implementation detail. Moreover poor user could think he(she) should
call the add(...) method instead of sending a message to the Delegate.
So in our example, by using inheritance, we are exposing too much of
the inherited class to the user, and it breaks the encapsulation?

Well than in my opinion verdict is clear. Traits are very nice
mechanism for extending observable behaviour of a class. They should
be used in scenarios where we want the additional (mixed-in) behaviour
to be available to the user of our API. In other cases I would still
prefer composition to avoid exposing too much, to avoid confusing the
user and keep high level of encapsulation.

What do you think?

Piotr Gabryanczyk

Luc Duponcheel
Joined: 2008-12-19,
User offline. Last seen 34 weeks 3 days ago.
Re: Inheritance vs composition in Scala?
Here is some (agreed, maybe not very technical) opinion on traits versus composition.

imho it is also about implementation reuse by
 o delegating to others (i.e. delegating to reusable implementations)
    (can be done both using Java and Scala)
 o doing things yourself (i.e. mixing-in reusable implementations)
    (can be done using Scala)

now, if OO claims to 'somehow model reality accurately',
then look at the following example:

suppose you are both
a basketball player (say during the day)
and
the husband of your wife (say during the evening and the night)

[ and assuming you really like playing basketball and really like your wife ]

would you not prefer to model this so that you implement both "responsibilities" yourself
rather than, for example, delegating the husband "responsibilities" to someone else?

So, even from a pure modelling point of view, traits may sometimes be a better choice :-)

Luc


On Fri, Dec 16, 2011 at 11:48 AM, Piotr Gabryanczyk <piotrga@gmail.com> wrote:
In his book "Effective Java" Joshua Bloch advises us to use
composition over inheritance. The main argument for using composition
is that  inheritance violates encapsulation. Super class has to expose
it's internals in order for subclass to extend it's behaviour; or
subclass is dangerously dependent on superclass implementation.

I wanted to examine this statement in the context of Scala and it's
trait inheritance mechanism.

Lets have a look at this two examples:

Example 1:

class Delegate{
 val work = new Queue[Task]
 def receive{
    case t @ Task => work add(t)
    case Available(worker) => worker ! (work next)
...
 }
}

Example 2:

class Delegate with QueueLike{
 def receive{
    case t @ Task =>  add(t)
    case Available(worker) => worker ! next
...
 }
}

Common code:

trait QueueLike[T]{
  private[this] val elements = new List[T]
  def add(e:T) = ...
  def next : T= ...
  ...
}
class Queue extends QueueLike


In example 2, we clearly see, that there is no danger of weakening
encapsulation, because QueueLike is well specialised and encapsulated.
Well is it? What if someone decided to override enqueue method? This
could make it confusing for other developers reading the code, but
there is no real danger of breaking encapsulation in our example.

Ok it is not about encapsulation. What is it about than?
Example 2 looks like less code (comparing to example 1) and less
clutter. Seems nicer, but... From the API user point of view there is
no reason why Delegate should extend QueueLike. It is Delegate's
implementation detail. Moreover poor user could think he(she) should
call the add(...) method instead of sending a message to the Delegate.
So in our example, by using inheritance, we are exposing too much of
the inherited class to the user, and it breaks the encapsulation?

Well than in my opinion verdict is clear. Traits are very nice
mechanism for extending observable behaviour of a class. They should
be used in scenarios where we want the additional (mixed-in) behaviour
to be available to the user of our API. In other cases I would still
prefer composition to avoid exposing too much, to avoid confusing the
user and keep high level of encapsulation.

What do you think?

Piotr Gabryanczyk



--
   __~O
  -\ <,
(*)/ (*)

reality goes far beyond imagination

Piotr Gabryanczyk
Joined: 2011-12-14,
User offline. Last seen 30 weeks 3 days ago.
Re: Inheritance vs composition in Scala?
I can not agree more.btw. My wife should see it :)
I am going to quote myself here  "Traits are very nicemechanism for extending observable behaviour of a class. They shouldbe used in scenarios where we want the additional (mixed-in) behaviourto be available to the user of our API."
In this case my wife is THE USER (some say the boss), so I am happy to mix-in my observable behaviour as a husband.
Piotr Gabryanczyk
On 16 Dec 2011, at 15:58, Luc Duponcheel wrote:
Here is some (agreed, maybe not very technical) opinion on traits versus composition.

imho it is also about implementation reuse by
 o delegating to others (i.e. delegating to reusable implementations)
    (can be done both using Java and Scala)
 o doing things yourself (i.e. mixing-in reusable implementations)
    (can be done using Scala)

now, if OO claims to 'somehow model reality accurately',
then look at the following example:

suppose you are both
a basketball player (say during the day)
and
the husband of your wife (say during the evening and the night)

[ and assuming you really like playing basketball and really like your wife ]

would you not prefer to model this so that you implement both "responsibilities" yourself
rather than, for example, delegating the husband "responsibilities" to someone else?

So, even from a pure modelling point of view, traits may sometimes be a better choice :-)

Luc


On Fri, Dec 16, 2011 at 11:48 AM, Piotr Gabryanczyk <piotrga@gmail.com> wrote:
In his book "Effective Java" Joshua Bloch advises us to use
composition over inheritance. The main argument for using composition
is that  inheritance violates encapsulation. Super class has to expose
it's internals in order for subclass to extend it's behaviour; or
subclass is dangerously dependent on superclass implementation.

I wanted to examine this statement in the context of Scala and it's
trait inheritance mechanism.

Lets have a look at this two examples:

Example 1:

class Delegate{
 val work = new Queue[Task]
 def receive{
    case t @ Task => work add(t)
    case Available(worker) => worker ! (work next)
...
 }
}

Example 2:

class Delegate with QueueLike{
 def receive{
    case t @ Task =>  add(t)
    case Available(worker) => worker ! next
...
 }
}

Common code:

trait QueueLike[T]{
  private[this] val elements = new List[T]
  def add(e:T) = ...
  def next : T= ...
  ...
}
class Queue extends QueueLike


In example 2, we clearly see, that there is no danger of weakening
encapsulation, because QueueLike is well specialised and encapsulated.
Well is it? What if someone decided to override enqueue method? This
could make it confusing for other developers reading the code, but
there is no real danger of breaking encapsulation in our example.

Ok it is not about encapsulation. What is it about than?
Example 2 looks like less code (comparing to example 1) and less
clutter. Seems nicer, but... From the API user point of view there is
no reason why Delegate should extend QueueLike. It is Delegate's
implementation detail. Moreover poor user could think he(she) should
call the add(...) method instead of sending a message to the Delegate.
So in our example, by using inheritance, we are exposing too much of
the inherited class to the user, and it breaks the encapsulation?

Well than in my opinion verdict is clear. Traits are very nice
mechanism for extending observable behaviour of a class. They should
be used in scenarios where we want the additional (mixed-in) behaviour
to be available to the user of our API. In other cases I would still
prefer composition to avoid exposing too much, to avoid confusing the
user and keep high level of encapsulation.

What do you think?

Piotr Gabryanczyk



--
   __~O
  -\ <,
(*)/ (*)

reality goes far beyond imagination


Kevin Wright 2
Joined: 2010-05-30,
User offline. Last seen 26 weeks 4 days ago.
Re: Inheritance vs composition in Scala?
I'm going to have to strongly disagree with both of you.
Being a basketball player or being a husband are not inherent properties, you're still the same person if you e.g. get divorced (albeit a somewhat less wealthy person).
These are merely roles that you perform; they're something that you do, not something that you are.  This is better modelled with objects that act as the roles, so there is a being-a-husband role that delegates to you (or to anyone else who's also being a husband).  The role specific behaviour is then dynamically mixed-in when it's required, and isn't permanently "baked in" to the concept of you-ness.
Ideally, this could be modelled something like:
  val you = Person("Luc")  val yourWife: Person = ...  val youAsHusband = you with HusbandOf(yourWife)


But we can't do that at present, "with" is strictly a static construct.  This is better suited to fixed properties such as gender (neatly sidestepping the possibility of surgery for the sake of this discussion)
It's something I've given a lot of thought to, and has lead me on a glorious whirlwind tour of writing compiler plugins.  Sadly, the resulting efforts have been limited as compared to my original vision (https://github.com/kevinwright/Autoproxy-Lite) - I'm ever-thwarted by challenges with synthesizing classes and methods in a way that keeps the type-checker happy.
That then allows you to do something like:
  class HusbandRole(@proxy person: Person, husbandOf: Person) extends Person {    def consumate() = ...    def payHousekeeping() = ...     def fileForDivorce() = ...  }
  val you = Person("Luc")  val youAsHusband = HusbandRole(you, yourWife)


On 16 December 2011 16:15, Piotr Gabryanczyk <piotrga@gmail.com> wrote:
I can not agree more.btw. My wife should see it :)
I am going to quote myself here  "Traits are very nicemechanism for extending observable behaviour of a class. They shouldbe used in scenarios where we want the additional (mixed-in) behaviour to be available to the user of our API."
In this case my wife is THE USER (some say the boss), so I am happy to mix-in my observable behaviour as a husband.
Piotr Gabryanczyk
On 16 Dec 2011, at 15:58, Luc Duponcheel wrote:
Here is some (agreed, maybe not very technical) opinion on traits versus composition.

imho it is also about implementation reuse by
 o delegating to others (i.e. delegating to reusable implementations)
    (can be done both using Java and Scala)
 o doing things yourself (i.e. mixing-in reusable implementations)
    (can be done using Scala)

now, if OO claims to 'somehow model reality accurately',
then look at the following example:

suppose you are both
a basketball player (say during the day)
and
the husband of your wife (say during the evening and the night)

[ and assuming you really like playing basketball and really like your wife ]

would you not prefer to model this so that you implement both "responsibilities" yourself
rather than, for example, delegating the husband "responsibilities" to someone else?

So, even from a pure modelling point of view, traits may sometimes be a better choice :-)

Luc


On Fri, Dec 16, 2011 at 11:48 AM, Piotr Gabryanczyk <piotrga@gmail.com> wrote:
In his book "Effective Java" Joshua Bloch advises us to use
composition over inheritance. The main argument for using composition
is that  inheritance violates encapsulation. Super class has to expose
it's internals in order for subclass to extend it's behaviour; or
subclass is dangerously dependent on superclass implementation.

I wanted to examine this statement in the context of Scala and it's
trait inheritance mechanism.

Lets have a look at this two examples:

Example 1:

class Delegate{
 val work = new Queue[Task]
 def receive{
    case t @ Task => work add(t)
    case Available(worker) => worker ! (work next)
...
 }
}

Example 2:

class Delegate with QueueLike{
 def receive{
    case t @ Task =>  add(t)
    case Available(worker) => worker ! next
...
 }
}

Common code:

trait QueueLike[T]{
  private[this] val elements = new List[T]
  def add(e:T) = ...
  def next : T= ...
  ...
}
class Queue extends QueueLike


In example 2, we clearly see, that there is no danger of weakening
encapsulation, because QueueLike is well specialised and encapsulated.
Well is it? What if someone decided to override enqueue method? This
could make it confusing for other developers reading the code, but
there is no real danger of breaking encapsulation in our example.

Ok it is not about encapsulation. What is it about than?
Example 2 looks like less code (comparing to example 1) and less
clutter. Seems nicer, but... From the API user point of view there is
no reason why Delegate should extend QueueLike. It is Delegate's
implementation detail. Moreover poor user could think he(she) should
call the add(...) method instead of sending a message to the Delegate.
So in our example, by using inheritance, we are exposing too much of
the inherited class to the user, and it breaks the encapsulation?

Well than in my opinion verdict is clear. Traits are very nice
mechanism for extending observable behaviour of a class. They should
be used in scenarios where we want the additional (mixed-in) behaviour
to be available to the user of our API. In other cases I would still
prefer composition to avoid exposing too much, to avoid confusing the
user and keep high level of encapsulation.

What do you think?

Piotr Gabryanczyk



--
   __~O
  -\ <,
(*)/ (*)

reality goes far beyond imagination





--
Kevin Wright
mail: kevin.wright@scalatechnology.com
gtalk / msn : kev.lee.wright@gmail.comquora: http://www.quora.com/Kevin-Wright google+: http://gplus.to/thecoda
kev.lee.wright@gmail.comtwitter: @thecoda
vibe / skype: kev.lee.wright steam: kev_lee_wright
"My point today is that, if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent": the current conventional wisdom is so foolish as to book that count on the wrong side of the ledger" ~ Dijkstra
Luc Duponcheel
Joined: 2008-12-19,
User offline. Last seen 34 weeks 3 days ago.
Re: Inheritance vs composition in Scala?
Hey, Kevin,

First: I only wanted to give a non-technical remark :-) .

Second: I agree that, essentially, we are talking about roles, and roles are dynamic.

I (implicitely) wanted to (only) discuss the topic from a static perspective.

Having full support (without any form of delegation (whatever that could mean))
for dynamically changing roles is, probably, out of scope of any statically typed
language anyway (I may be wrong).

Thanks for bringing this (important) aspect into this discussion.

Cheers,

Luc

On Fri, Dec 16, 2011 at 5:39 PM, Kevin Wright <kev.lee.wright@gmail.com> wrote:
I'm going to have to strongly disagree with both of you.
Being a basketball player or being a husband are not inherent properties, you're still the same person if you e.g. get divorced (albeit a somewhat less wealthy person).
These are merely roles that you perform; they're something that you do, not something that you are.  This is better modelled with objects that act as the roles, so there is a being-a-husband role that delegates to you (or to anyone else who's also being a husband).  The role specific behaviour is then dynamically mixed-in when it's required, and isn't permanently "baked in" to the concept of you-ness.
Ideally, this could be modelled something like:
  val you = Person("Luc")  val yourWife: Person = ...  val youAsHusband = you with HusbandOf(yourWife)


But we can't do that at present, "with" is strictly a static construct.  This is better suited to fixed properties such as gender (neatly sidestepping the possibility of surgery for the sake of this discussion)
It's something I've given a lot of thought to, and has lead me on a glorious whirlwind tour of writing compiler plugins.  Sadly, the resulting efforts have been limited as compared to my original vision (https://github.com/kevinwright/Autoproxy-Lite) - I'm ever-thwarted by challenges with synthesizing classes and methods in a way that keeps the type-checker happy.
That then allows you to do something like:
  class HusbandRole(@proxy person: Person, husbandOf: Person) extends Person {    def consumate() = ...    def payHousekeeping() = ...     def fileForDivorce() = ...  }
  val you = Person("Luc")  val youAsHusband = HusbandRole(you, yourWife)


On 16 December 2011 16:15, Piotr Gabryanczyk <piotrga@gmail.com> wrote:
I can not agree more.btw. My wife should see it :)
I am going to quote myself here  "Traits are very nicemechanism for extending observable behaviour of a class. They shouldbe used in scenarios where we want the additional (mixed-in) behaviour to be available to the user of our API."
In this case my wife is THE USER (some say the boss), so I am happy to mix-in my observable behaviour as a husband.
Piotr Gabryanczyk
On 16 Dec 2011, at 15:58, Luc Duponcheel wrote:
Here is some (agreed, maybe not very technical) opinion on traits versus composition.

imho it is also about implementation reuse by
 o delegating to others (i.e. delegating to reusable implementations)
    (can be done both using Java and Scala)
 o doing things yourself (i.e. mixing-in reusable implementations)
    (can be done using Scala)

now, if OO claims to 'somehow model reality accurately',
then look at the following example:

suppose you are both
a basketball player (say during the day)
and
the husband of your wife (say during the evening and the night)

[ and assuming you really like playing basketball and really like your wife ]

would you not prefer to model this so that you implement both "responsibilities" yourself
rather than, for example, delegating the husband "responsibilities" to someone else?

So, even from a pure modelling point of view, traits may sometimes be a better choice :-)

Luc


On Fri, Dec 16, 2011 at 11:48 AM, Piotr Gabryanczyk <piotrga@gmail.com> wrote:
In his book "Effective Java" Joshua Bloch advises us to use
composition over inheritance. The main argument for using composition
is that  inheritance violates encapsulation. Super class has to expose
it's internals in order for subclass to extend it's behaviour; or
subclass is dangerously dependent on superclass implementation.

I wanted to examine this statement in the context of Scala and it's
trait inheritance mechanism.

Lets have a look at this two examples:

Example 1:

class Delegate{
 val work = new Queue[Task]
 def receive{
    case t @ Task => work add(t)
    case Available(worker) => worker ! (work next)
...
 }
}

Example 2:

class Delegate with QueueLike{
 def receive{
    case t @ Task =>  add(t)
    case Available(worker) => worker ! next
...
 }
}

Common code:

trait QueueLike[T]{
  private[this] val elements = new List[T]
  def add(e:T) = ...
  def next : T= ...
  ...
}
class Queue extends QueueLike


In example 2, we clearly see, that there is no danger of weakening
encapsulation, because QueueLike is well specialised and encapsulated.
Well is it? What if someone decided to override enqueue method? This
could make it confusing for other developers reading the code, but
there is no real danger of breaking encapsulation in our example.

Ok it is not about encapsulation. What is it about than?
Example 2 looks like less code (comparing to example 1) and less
clutter. Seems nicer, but... From the API user point of view there is
no reason why Delegate should extend QueueLike. It is Delegate's
implementation detail. Moreover poor user could think he(she) should
call the add(...) method instead of sending a message to the Delegate.
So in our example, by using inheritance, we are exposing too much of
the inherited class to the user, and it breaks the encapsulation?

Well than in my opinion verdict is clear. Traits are very nice
mechanism for extending observable behaviour of a class. They should
be used in scenarios where we want the additional (mixed-in) behaviour
to be available to the user of our API. In other cases I would still
prefer composition to avoid exposing too much, to avoid confusing the
user and keep high level of encapsulation.

What do you think?

Piotr Gabryanczyk



--
   __~O
  -\ <,
(*)/ (*)

reality goes far beyond imagination





--
Kevin Wright
mail: kevin.wright@scalatechnology.com
gtalk / msn : kev.lee.wright@gmail.comquora: http://www.quora.com/Kevin-Wright google+: http://gplus.to/thecoda
kev.lee.wright@gmail.comtwitter: @thecoda
vibe / skype: kev.lee.wright steam: kev_lee_wright
"My point today is that, if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent": the current conventional wisdom is so foolish as to book that count on the wrong side of the ledger" ~ Dijkstra



--
   __~O
  -\ <,
(*)/ (*)

reality goes far beyond imagination

Luc Duponcheel
Joined: 2008-12-19,
User offline. Last seen 34 weeks 3 days ago.
Re: Inheritance vs composition in Scala?
By the way, Kevin,

many years ago (early nineties), when I programmed C++,
I wrote code for a "role pattern" similar to the state pattern
(using a list of roles rather than just one state)

... using the pattern was far from elegant (I had a
method "as" to dynamically decide about your role) ...

... very ugly ...

maybe we can hope, with a combination of Scala's
DSL capabilities and (maybe (?)) a bit of compiler magic
to implement all this in a way that using it is more elegant

But then again, all this would rely on delegation instead of treats.

Your efforts to (try to) accomplish the same flexibility+elegance
using treats are much more challenging (and, if successful, would
be much more worthwhile).


Cheers,

Luc

On Fri, Dec 16, 2011 at 8:23 PM, Luc Duponcheel <luc.duponcheel@gmail.com> wrote:
Hey, Kevin,

First: I only wanted to give a non-technical remark :-) .

Second: I agree that, essentially, we are talking about roles, and roles are dynamic.

I (implicitely) wanted to (only) discuss the topic from a static perspective.

Having full support (without any form of delegation (whatever that could mean))
for dynamically changing roles is, probably, out of scope of any statically typed
language anyway (I may be wrong).

Thanks for bringing this (important) aspect into this discussion.

Cheers,

Luc

On Fri, Dec 16, 2011 at 5:39 PM, Kevin Wright <kev.lee.wright@gmail.com> wrote:
I'm going to have to strongly disagree with both of you.
Being a basketball player or being a husband are not inherent properties, you're still the same person if you e.g. get divorced (albeit a somewhat less wealthy person).
These are merely roles that you perform; they're something that you do, not something that you are.  This is better modelled with objects that act as the roles, so there is a being-a-husband role that delegates to you (or to anyone else who's also being a husband).  The role specific behaviour is then dynamically mixed-in when it's required, and isn't permanently "baked in" to the concept of you-ness.
Ideally, this could be modelled something like:
  val you = Person("Luc")  val yourWife: Person = ...  val youAsHusband = you with HusbandOf(yourWife)


But we can't do that at present, "with" is strictly a static construct.  This is better suited to fixed properties such as gender (neatly sidestepping the possibility of surgery for the sake of this discussion)
It's something I've given a lot of thought to, and has lead me on a glorious whirlwind tour of writing compiler plugins.  Sadly, the resulting efforts have been limited as compared to my original vision (https://github.com/kevinwright/Autoproxy-Lite) - I'm ever-thwarted by challenges with synthesizing classes and methods in a way that keeps the type-checker happy.
That then allows you to do something like:
  class HusbandRole(@proxy person: Person, husbandOf: Person) extends Person {    def consumate() = ...    def payHousekeeping() = ...     def fileForDivorce() = ...  }
  val you = Person("Luc")  val youAsHusband = HusbandRole(you, yourWife)


On 16 December 2011 16:15, Piotr Gabryanczyk <piotrga@gmail.com> wrote:
I can not agree more.btw. My wife should see it :)
I am going to quote myself here  "Traits are very nicemechanism for extending observable behaviour of a class. They shouldbe used in scenarios where we want the additional (mixed-in) behaviour to be available to the user of our API."
In this case my wife is THE USER (some say the boss), so I am happy to mix-in my observable behaviour as a husband.
Piotr Gabryanczyk
On 16 Dec 2011, at 15:58, Luc Duponcheel wrote:
Here is some (agreed, maybe not very technical) opinion on traits versus composition.

imho it is also about implementation reuse by
 o delegating to others (i.e. delegating to reusable implementations)
    (can be done both using Java and Scala)
 o doing things yourself (i.e. mixing-in reusable implementations)
    (can be done using Scala)

now, if OO claims to 'somehow model reality accurately',
then look at the following example:

suppose you are both
a basketball player (say during the day)
and
the husband of your wife (say during the evening and the night)

[ and assuming you really like playing basketball and really like your wife ]

would you not prefer to model this so that you implement both "responsibilities" yourself
rather than, for example, delegating the husband "responsibilities" to someone else?

So, even from a pure modelling point of view, traits may sometimes be a better choice :-)

Luc


On Fri, Dec 16, 2011 at 11:48 AM, Piotr Gabryanczyk <piotrga@gmail.com> wrote:
In his book "Effective Java" Joshua Bloch advises us to use
composition over inheritance. The main argument for using composition
is that  inheritance violates encapsulation. Super class has to expose
it's internals in order for subclass to extend it's behaviour; or
subclass is dangerously dependent on superclass implementation.

I wanted to examine this statement in the context of Scala and it's
trait inheritance mechanism.

Lets have a look at this two examples:

Example 1:

class Delegate{
 val work = new Queue[Task]
 def receive{
    case t @ Task => work add(t)
    case Available(worker) => worker ! (work next)
...
 }
}

Example 2:

class Delegate with QueueLike{
 def receive{
    case t @ Task =>  add(t)
    case Available(worker) => worker ! next
...
 }
}

Common code:

trait QueueLike[T]{
  private[this] val elements = new List[T]
  def add(e:T) = ...
  def next : T= ...
  ...
}
class Queue extends QueueLike


In example 2, we clearly see, that there is no danger of weakening
encapsulation, because QueueLike is well specialised and encapsulated.
Well is it? What if someone decided to override enqueue method? This
could make it confusing for other developers reading the code, but
there is no real danger of breaking encapsulation in our example.

Ok it is not about encapsulation. What is it about than?
Example 2 looks like less code (comparing to example 1) and less
clutter. Seems nicer, but... From the API user point of view there is
no reason why Delegate should extend QueueLike. It is Delegate's
implementation detail. Moreover poor user could think he(she) should
call the add(...) method instead of sending a message to the Delegate.
So in our example, by using inheritance, we are exposing too much of
the inherited class to the user, and it breaks the encapsulation?

Well than in my opinion verdict is clear. Traits are very nice
mechanism for extending observable behaviour of a class. They should
be used in scenarios where we want the additional (mixed-in) behaviour
to be available to the user of our API. In other cases I would still
prefer composition to avoid exposing too much, to avoid confusing the
user and keep high level of encapsulation.

What do you think?

Piotr Gabryanczyk



--
   __~O
  -\ <,
(*)/ (*)

reality goes far beyond imagination





--
Kevin Wright
mail: kevin.wright@scalatechnology.com
gtalk / msn : kev.lee.wright@gmail.comquora: http://www.quora.com/Kevin-Wright google+: http://gplus.to/thecoda
kev.lee.wright@gmail.comtwitter: @thecoda
vibe / skype: kev.lee.wright steam: kev_lee_wright
"My point today is that, if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent": the current conventional wisdom is so foolish as to book that count on the wrong side of the ledger" ~ Dijkstra



--
   __~O
  -\ <,
(*)/ (*)

reality goes far beyond imagination




--
   __~O
  -\ <,
(*)/ (*)

reality goes far beyond imagination

Piotr Gabryanczyk
Joined: 2011-12-14,
User offline. Last seen 30 weeks 3 days ago.
Re: Inheritance vs composition in Scala?

Guys,

Thank you for your comments.
I just wanted to refocus conversation back on the original question:
"Composition or inheritance? (in scala)"

Piotr Gabryanczyk
-
piotrga@gmail.com

On 16 December 2011 19:34, Luc Duponcheel wrote:
> By the way, Kevin,
>
> many years ago (early nineties), when I programmed C++,
> I wrote code for a "role pattern" similar to the state pattern
> (using a list of roles rather than just one state)
>
> ... using the pattern was far from elegant (I had a
> method "as" to dynamically decide about your role) ...
>
> ... very ugly ...
>
> maybe we can hope, with a combination of Scala's
> DSL capabilities and (maybe (?)) a bit of compiler magic
> to implement all this in a way that using it is more elegant
>
> But then again, all this would rely on delegation instead of treats.
>
> Your efforts to (try to) accomplish the same flexibility+elegance
> using treats are much more challenging (and, if successful, would
> be much more worthwhile).
>
>
> Cheers,
>
> Luc
>
>
> On Fri, Dec 16, 2011 at 8:23 PM, Luc Duponcheel
> wrote:
>>
>> Hey, Kevin,
>>
>> First: I only wanted to give a non-technical remark :-) .
>>
>> Second: I agree that, essentially, we are talking about roles, and roles
>> are dynamic.
>>
>> I (implicitely) wanted to (only) discuss the topic from a static
>> perspective.
>>
>> Having full support (without any form of delegation (whatever that could
>> mean))
>> for dynamically changing roles is, probably, out of scope of any
>> statically typed
>> language anyway (I may be wrong).
>>
>> Thanks for bringing this (important) aspect into this discussion.
>>
>> Cheers,
>>
>> Luc
>>
>>
>> On Fri, Dec 16, 2011 at 5:39 PM, Kevin Wright
>> wrote:
>>>
>>> I'm going to have to strongly disagree with both of you.
>>>
>>> Being a basketball player or being a husband are not inherent properties,
>>> you're still the same person if you e.g. get divorced (albeit a somewhat
>>> less wealthy person).
>>>
>>> These are merely roles that you perform; they're something that you do,
>>> not something that you are.  This is better modelled with objects that act
>>> as the roles, so there is a being-a-husband role that delegates to you (or
>>> to anyone else who's also being a husband).  The role specific behaviour is
>>> then dynamically mixed-in when it's required, and isn't permanently "baked
>>> in" to the concept of you-ness.
>>>
>>> Ideally, this could be modelled something like:
>>>
>>>   val you = Person("Luc")
>>>   val yourWife: Person = ...
>>>   val youAsHusband = you with HusbandOf(yourWife)
>>>
>>>
>>> But we can't do that at present, "with" is strictly a static construct.
>>>  This is better suited to fixed properties such as gender (neatly
>>> sidestepping the possibility of surgery for the sake of this discussion)
>>>
>>> It's something I've given a lot of thought to, and has lead me on a
>>> glorious whirlwind tour of writing compiler plugins.  Sadly, the resulting
>>> efforts have been limited as compared to my original vision
>>> (https://github.com/kevinwright/Autoproxy-Lite) - I'm ever-thwarted by
>>> challenges with synthesizing classes and methods in a way that keeps the
>>> type-checker happy.
>>>
>>> That then allows you to do something like:
>>>
>>>   class HusbandRole(@proxy person: Person, husbandOf: Person) extends
>>> Person {
>>>     def consumate() = ...
>>>     def payHousekeeping() = ...
>>>     def fileForDivorce() = ...
>>>   }
>>>
>>>   val you = Person("Luc")
>>>   val youAsHusband = HusbandRole(you, yourWife)
>>>
>>>
>>>
>>> On 16 December 2011 16:15, Piotr Gabryanczyk wrote:
>>>>
>>>> I can not agree more.
>>>> btw. My wife should see it :)
>>>>
>>>> I am going to quote myself here  "Traits are very nice
>>>> mechanism for extending observable behaviour of a class. They should
>>>> be used in scenarios where we want the additional (mixed-in) behaviour
>>>> to be available to the user of our API."
>>>>
>>>> In this case my wife is THE USER (some say the boss), so I am happy to
>>>> mix-in my observable behaviour as a husband.
>>>>
>>>> Piotr Gabryanczyk
>>>>
>>>> On 16 Dec 2011, at 15:58, Luc Duponcheel wrote:
>>>>
>>>> Here is some (agreed, maybe not very technical) opinion on traits versus
>>>> composition.
>>>>
>>>> imho it is also about implementation reuse by
>>>>  o delegating to others (i.e. delegating to reusable implementations)
>>>>     (can be done both using Java and Scala)
>>>>  o doing things yourself (i.e. mixing-in reusable implementations)
>>>>     (can be done using Scala)
>>>>
>>>> now, if OO claims to 'somehow model reality accurately',
>>>> then look at the following example:
>>>>
>>>> suppose you are both
>>>> a basketball player (say during the day)
>>>> and
>>>> the husband of your wife (say during the evening and the night)
>>>>
>>>> [ and assuming you really like playing basketball and really like your
>>>> wife ]
>>>>
>>>> would you not prefer to model this so that you implement both
>>>> "responsibilities" yourself
>>>> rather than, for example, delegating the husband "responsibilities" to
>>>> someone else?
>>>>
>>>> So, even from a pure modelling point of view, traits may sometimes be a
>>>> better choice :-)
>>>>
>>>> Luc
>>>>
>>>>
>>>> On Fri, Dec 16, 2011 at 11:48 AM, Piotr Gabryanczyk
>>>> wrote:
>>>>>
>>>>> In his book "Effective Java" Joshua Bloch advises us to use
>>>>> composition over inheritance. The main argument for using composition
>>>>> is that  inheritance violates encapsulation. Super class has to expose
>>>>> it's internals in order for subclass to extend it's behaviour; or
>>>>> subclass is dangerously dependent on superclass implementation.
>>>>>
>>>>> I wanted to examine this statement in the context of Scala and it's
>>>>> trait inheritance mechanism.
>>>>>
>>>>> Lets have a look at this two examples:
>>>>>
>>>>> Example 1:
>>>>>
>>>>> class Delegate{
>>>>>  val work = new Queue[Task]
>>>>>  def receive{
>>>>>     case t @ Task => work add(t)
>>>>>     case Available(worker) => worker ! (work next)
>>>>> ...
>>>>>  }
>>>>> }
>>>>>
>>>>> Example 2:
>>>>>
>>>>> class Delegate with QueueLike{
>>>>>  def receive{
>>>>>     case t @ Task =>  add(t)
>>>>>     case Available(worker) => worker ! next
>>>>> ...
>>>>>  }
>>>>> }
>>>>>
>>>>> Common code:
>>>>>
>>>>> trait QueueLike[T]{
>>>>>   private[this] val elements = new List[T]
>>>>>   def add(e:T) = ...
>>>>>   def next : T= ...
>>>>>   ...
>>>>> }
>>>>> class Queue extends QueueLike
>>>>>
>>>>>
>>>>> In example 2, we clearly see, that there is no danger of weakening
>>>>> encapsulation, because QueueLike is well specialised and encapsulated.
>>>>> Well is it? What if someone decided to override enqueue method? This
>>>>> could make it confusing for other developers reading the code, but
>>>>> there is no real danger of breaking encapsulation in our example.
>>>>>
>>>>> Ok it is not about encapsulation. What is it about than?
>>>>> Example 2 looks like less code (comparing to example 1) and less
>>>>> clutter. Seems nicer, but... From the API user point of view there is
>>>>> no reason why Delegate should extend QueueLike. It is Delegate's
>>>>> implementation detail. Moreover poor user could think he(she) should
>>>>> call the add(...) method instead of sending a message to the Delegate.
>>>>> So in our example, by using inheritance, we are exposing too much of
>>>>> the inherited class to the user, and it breaks the encapsulation?
>>>>>
>>>>> Well than in my opinion verdict is clear. Traits are very nice
>>>>> mechanism for extending observable behaviour of a class. They should
>>>>> be used in scenarios where we want the additional (mixed-in) behaviour
>>>>> to be available to the user of our API. In other cases I would still
>>>>> prefer composition to avoid exposing too much, to avoid confusing the
>>>>> user and keep high level of encapsulation.
>>>>>
>>>>> What do you think?
>>>>>
>>>>> Piotr Gabryanczyk
>>>>
>>>>
>>>>
>>>>
>>>> --
>>>>    __~O
>>>>   -\ <,
>>>> (*)/ (*)
>>>>
>>>> reality goes far beyond imagination
>>>>
>>>>
>>>
>>>
>>>
>>> --
>>> Kevin Wright
>>> mail: kevin.wright@scalatechnology.com
>>> gtalk / msn : kev.lee.wright@gmail.com
>>> quora: http://www.quora.com/Kevin-Wright
>>> google+: http://gplus.to/thecoda
>>> twitter: @thecoda
>>> vibe / skype: kev.lee.wright
>>> steam: kev_lee_wright
>>>
>>> "My point today is that, if we wish to count lines of code, we should not
>>> regard them as "lines produced" but as "lines spent": the current
>>> conventional wisdom is so foolish as to book that count on the wrong side of
>>> the ledger" ~ Dijkstra
>>>
>>
>>
>>
>> --
>>    __~O
>>   -\ <,
>> (*)/ (*)
>>
>> reality goes far beyond imagination
>>
>
>
>
> --
>    __~O
>   -\ <,
> (*)/ (*)
>
> reality goes far beyond imagination
>

Luc Duponcheel
Joined: 2008-12-19,
User offline. Last seen 34 weeks 3 days ago.
Re: Inheritance vs composition in Scala?
Well,

to a certain extent the discussion was relevant to your question:

composition is more dynamic than inheritance (even when using traits)

Luc

On Fri, Dec 16, 2011 at 9:43 PM, Piotr Gabryanczyk <piotrga@gmail.com> wrote:
Guys,

Thank you for your comments.
I just wanted to refocus conversation back on the original question:
"Composition or inheritance? (in scala)"

Piotr Gabryanczyk
-
piotrga@gmail.com



On 16 December 2011 19:34, Luc Duponcheel <luc.duponcheel@gmail.com> wrote:
> By the way, Kevin,
>
> many years ago (early nineties), when I programmed C++,
> I wrote code for a "role pattern" similar to the state pattern
> (using a list of roles rather than just one state)
>
> ... using the pattern was far from elegant (I had a
> method "as" to dynamically decide about your role) ...
>
> ... very ugly ...
>
> maybe we can hope, with a combination of Scala's
> DSL capabilities and (maybe (?)) a bit of compiler magic
> to implement all this in a way that using it is more elegant
>
> But then again, all this would rely on delegation instead of treats.
>
> Your efforts to (try to) accomplish the same flexibility+elegance
> using treats are much more challenging (and, if successful, would
> be much more worthwhile).
>
>
> Cheers,
>
> Luc
>
>
> On Fri, Dec 16, 2011 at 8:23 PM, Luc Duponcheel <luc.duponcheel@gmail.com>
> wrote:
>>
>> Hey, Kevin,
>>
>> First: I only wanted to give a non-technical remark :-) .
>>
>> Second: I agree that, essentially, we are talking about roles, and roles
>> are dynamic.
>>
>> I (implicitely) wanted to (only) discuss the topic from a static
>> perspective.
>>
>> Having full support (without any form of delegation (whatever that could
>> mean))
>> for dynamically changing roles is, probably, out of scope of any
>> statically typed
>> language anyway (I may be wrong).
>>
>> Thanks for bringing this (important) aspect into this discussion.
>>
>> Cheers,
>>
>> Luc
>>
>>
>> On Fri, Dec 16, 2011 at 5:39 PM, Kevin Wright <kev.lee.wright@gmail.com>
>> wrote:
>>>
>>> I'm going to have to strongly disagree with both of you.
>>>
>>> Being a basketball player or being a husband are not inherent properties,
>>> you're still the same person if you e.g. get divorced (albeit a somewhat
>>> less wealthy person).
>>>
>>> These are merely roles that you perform; they're something that you do,
>>> not something that you are.  This is better modelled with objects that act
>>> as the roles, so there is a being-a-husband role that delegates to you (or
>>> to anyone else who's also being a husband).  The role specific behaviour is
>>> then dynamically mixed-in when it's required, and isn't permanently "baked
>>> in" to the concept of you-ness.
>>>
>>> Ideally, this could be modelled something like:
>>>
>>>   val you = Person("Luc")
>>>   val yourWife: Person = ...
>>>   val youAsHusband = you with HusbandOf(yourWife)
>>>
>>>
>>> But we can't do that at present, "with" is strictly a static construct.
>>>  This is better suited to fixed properties such as gender (neatly
>>> sidestepping the possibility of surgery for the sake of this discussion)
>>>
>>> It's something I've given a lot of thought to, and has lead me on a
>>> glorious whirlwind tour of writing compiler plugins.  Sadly, the resulting
>>> efforts have been limited as compared to my original vision
>>> (https://github.com/kevinwright/Autoproxy-Lite) - I'm ever-thwarted by
>>> challenges with synthesizing classes and methods in a way that keeps the
>>> type-checker happy.
>>>
>>> That then allows you to do something like:
>>>
>>>   class HusbandRole(@proxy person: Person, husbandOf: Person) extends
>>> Person {
>>>     def consumate() = ...
>>>     def payHousekeeping() = ...
>>>     def fileForDivorce() = ...
>>>   }
>>>
>>>   val you = Person("Luc")
>>>   val youAsHusband = HusbandRole(you, yourWife)
>>>
>>>
>>>
>>> On 16 December 2011 16:15, Piotr Gabryanczyk <piotrga@gmail.com> wrote:
>>>>
>>>> I can not agree more.
>>>> btw. My wife should see it :)
>>>>
>>>> I am going to quote myself here  "Traits are very nice
>>>> mechanism for extending observable behaviour of a class. They should
>>>> be used in scenarios where we want the additional (mixed-in) behaviour
>>>> to be available to the user of our API."
>>>>
>>>> In this case my wife is THE USER (some say the boss), so I am happy to
>>>> mix-in my observable behaviour as a husband.
>>>>
>>>> Piotr Gabryanczyk
>>>>
>>>> On 16 Dec 2011, at 15:58, Luc Duponcheel wrote:
>>>>
>>>> Here is some (agreed, maybe not very technical) opinion on traits versus
>>>> composition.
>>>>
>>>> imho it is also about implementation reuse by
>>>>  o delegating to others (i.e. delegating to reusable implementations)
>>>>     (can be done both using Java and Scala)
>>>>  o doing things yourself (i.e. mixing-in reusable implementations)
>>>>     (can be done using Scala)
>>>>
>>>> now, if OO claims to 'somehow model reality accurately',
>>>> then look at the following example:
>>>>
>>>> suppose you are both
>>>> a basketball player (say during the day)
>>>> and
>>>> the husband of your wife (say during the evening and the night)
>>>>
>>>> [ and assuming you really like playing basketball and really like your
>>>> wife ]
>>>>
>>>> would you not prefer to model this so that you implement both
>>>> "responsibilities" yourself
>>>> rather than, for example, delegating the husband "responsibilities" to
>>>> someone else?
>>>>
>>>> So, even from a pure modelling point of view, traits may sometimes be a
>>>> better choice :-)
>>>>
>>>> Luc
>>>>
>>>>
>>>> On Fri, Dec 16, 2011 at 11:48 AM, Piotr Gabryanczyk <piotrga@gmail.com>
>>>> wrote:
>>>>>
>>>>> In his book "Effective Java" Joshua Bloch advises us to use
>>>>> composition over inheritance. The main argument for using composition
>>>>> is that  inheritance violates encapsulation. Super class has to expose
>>>>> it's internals in order for subclass to extend it's behaviour; or
>>>>> subclass is dangerously dependent on superclass implementation.
>>>>>
>>>>> I wanted to examine this statement in the context of Scala and it's
>>>>> trait inheritance mechanism.
>>>>>
>>>>> Lets have a look at this two examples:
>>>>>
>>>>> Example 1:
>>>>>
>>>>> class Delegate{
>>>>>  val work = new Queue[Task]
>>>>>  def receive{
>>>>>     case t @ Task => work add(t)
>>>>>     case Available(worker) => worker ! (work next)
>>>>> ...
>>>>>  }
>>>>> }
>>>>>
>>>>> Example 2:
>>>>>
>>>>> class Delegate with QueueLike{
>>>>>  def receive{
>>>>>     case t @ Task =>  add(t)
>>>>>     case Available(worker) => worker ! next
>>>>> ...
>>>>>  }
>>>>> }
>>>>>
>>>>> Common code:
>>>>>
>>>>> trait QueueLike[T]{
>>>>>   private[this] val elements = new List[T]
>>>>>   def add(e:T) = ...
>>>>>   def next : T= ...
>>>>>   ...
>>>>> }
>>>>> class Queue extends QueueLike
>>>>>
>>>>>
>>>>> In example 2, we clearly see, that there is no danger of weakening
>>>>> encapsulation, because QueueLike is well specialised and encapsulated.
>>>>> Well is it? What if someone decided to override enqueue method? This
>>>>> could make it confusing for other developers reading the code, but
>>>>> there is no real danger of breaking encapsulation in our example.
>>>>>
>>>>> Ok it is not about encapsulation. What is it about than?
>>>>> Example 2 looks like less code (comparing to example 1) and less
>>>>> clutter. Seems nicer, but... From the API user point of view there is
>>>>> no reason why Delegate should extend QueueLike. It is Delegate's
>>>>> implementation detail. Moreover poor user could think he(she) should
>>>>> call the add(...) method instead of sending a message to the Delegate.
>>>>> So in our example, by using inheritance, we are exposing too much of
>>>>> the inherited class to the user, and it breaks the encapsulation?
>>>>>
>>>>> Well than in my opinion verdict is clear. Traits are very nice
>>>>> mechanism for extending observable behaviour of a class. They should
>>>>> be used in scenarios where we want the additional (mixed-in) behaviour
>>>>> to be available to the user of our API. In other cases I would still
>>>>> prefer composition to avoid exposing too much, to avoid confusing the
>>>>> user and keep high level of encapsulation.
>>>>>
>>>>> What do you think?
>>>>>
>>>>> Piotr Gabryanczyk
>>>>
>>>>
>>>>
>>>>
>>>> --
>>>>    __~O
>>>>   -\ <,
>>>> (*)/ (*)
>>>>
>>>> reality goes far beyond imagination
>>>>
>>>>
>>>
>>>
>>>
>>> --
>>> Kevin Wright
>>> mail: kevin.wright@scalatechnology.com
>>> gtalk / msn : kev.lee.wright@gmail.com
>>> quora: http://www.quora.com/Kevin-Wright
>>> google+: http://gplus.to/thecoda
>>> twitter: @thecoda
>>> vibe / skype: kev.lee.wright
>>> steam: kev_lee_wright
>>>
>>> "My point today is that, if we wish to count lines of code, we should not
>>> regard them as "lines produced" but as "lines spent": the current
>>> conventional wisdom is so foolish as to book that count on the wrong side of
>>> the ledger" ~ Dijkstra
>>>
>>
>>
>>
>> --
>>    __~O
>>   -\ <,
>> (*)/ (*)
>>
>> reality goes far beyond imagination
>>
>
>
>
> --
>    __~O
>   -\ <,
> (*)/ (*)
>
> reality goes far beyond imagination
>



--
   __~O
  -\ <,
(*)/ (*)

reality goes far beyond imagination

Ken Scambler
Joined: 2009-11-07,
User offline. Last seen 42 years 45 weeks ago.
Re: Inheritance vs composition in Scala?
Well than in my opinion verdict is clear. Traits are very nice
mechanism for extending observable behaviour of a class. They should
be used in scenarios where we want the additional (mixed-in) behaviour
to be available to the user of our API. In other cases I would still
prefer composition to avoid exposing too much, to avoid confusing the
user and keep high level of encapsulation.

What do you think?

Piotr Gabryanczyk

Spot on.  Traits should be used where they need to be used; the collections library is a fairly spectacular use case.  For example, it would be absurd to have something like list.seq.traversable.traversableLike.foreach() in the public API.  The traits are being used to expose their behaviour through the interface, rather than just used internally.

Everything else should use composition, including your code example here.

Ken McDonald
Joined: 2011-02-13,
User offline. Last seen 42 years 45 weeks ago.
Re: Inheritance vs composition in Scala?
To me, inheritance makes sense even when there isn't an "isa" relationship, as long as it can be done in a manner that doesn't break encapsulation--and in Scala, it usually can. You get code reuse without the downside of writing boilerplate and potentially introducing errors.
The real problem with composition (IMHO), even in Scala, is that it isn't general enough. When importing something in Scala, one can alias the name to avoid name clashes. What if one could do that when inheriting? It would then be possible to write a "Link" than implements links between objects, and then a "Bilink" class that inherits "Link" twice, once aliased as "Forward" and once as "Back". I haven't thought much about type issues, but I don't see any problems with aliasing issues--though I'm not an internals guy.
In any case, I think it's time to stop thinking of inheritance = isa. That idea was broken long ago. So inheritance is just a tool in the toolkit, to be used sensibly, but without artificial restraints.
Ken
Raoul Duke
Joined: 2009-01-05,
User offline. Last seen 42 years 45 weeks ago.
Re: Inheritance vs composition in Scala?

On Fri, Dec 16, 2011 at 2:54 PM, Ken McDonald wrote:
> To me, inheritance makes sense even when there isn't an "isa" relationship,
> as long as it can be done in a manner that doesn't break encapsulation--and
> in Scala, it usually can. You get code reuse without the downside of writing
> boilerplate and potentially introducing errors.

if you have the time and energy, can you please expand? i'm too
clueless about scala to know concrete examples of this.

thank you.

Piotr Gabryanczyk
Joined: 2011-12-14,
User offline. Last seen 30 weeks 3 days ago.
Re: Inheritance vs composition in Scala?

Piotr Gabryanczyk

On 16 Dec 2011, at 22:54, Ken McDonald wrote:

> To me, inheritance makes sense even when there isn't an "isa" relationship, as long as it can be done in a manner that doesn't break encapsulation--and in Scala, it usually can. You get code reuse without the downside of writing boilerplate and potentially introducing errors.
How is this different from delegation?

>
> The real problem with composition (IMHO), even in Scala, is that it isn't general enough. When importing something in Scala, one can alias the name to avoid name clashes. What if one could do that when inheriting? It would then be possible to write a "Link" than implements links between objects, and then a "Bilink" class that inherits "Link" twice, once aliased as "Forward" and once as "Back". I haven't thought much about type issues, but I don't see any problems with aliasing issues--though I'm not an internals guy.
Considering the amount of jiggery pokery involved with aliasing, my preference would be the delegation in this case. Also, how would you refer to methods of forward/backward link? This would have to be exactly the same from the user point of view.

>
> In any case, I think it's time to stop thinking of inheritance = isa. That idea was broken long ago. So inheritance is just a tool in the toolkit, to be used sensibly, but without artificial restraints.
>

> Ken

Joshua.Suereth
Joined: 2008-09-02,
User offline. Last seen 32 weeks 5 days ago.
Re: Inheritance vs composition in Scala?

You can use inheritance to denote composition in Scala.

trait HasFoo {
  def foo: Foo
}

Things extending HasFoo denote that they contain some instance of Foo.

In my book, Scala In Depth, I outline composition using members, inheritance and applicative functors.   Each have pros and cons.   The point being, it's not a black and white issue.

On Dec 16, 2011 3:43 PM, "Piotr Gabryanczyk" <piotrga@gmail.com> wrote:
Guys,

Thank you for your comments.
I just wanted to refocus conversation back on the original question:
"Composition or inheritance? (in scala)"

Piotr Gabryanczyk
-
piotrga@gmail.com



On 16 December 2011 19:34, Luc Duponcheel <luc.duponcheel@gmail.com> wrote:
> By the way, Kevin,
>
> many years ago (early nineties), when I programmed C++,
> I wrote code for a "role pattern" similar to the state pattern
> (using a list of roles rather than just one state)
>
> ... using the pattern was far from elegant (I had a
> method "as" to dynamically decide about your role) ...
>
> ... very ugly ...
>
> maybe we can hope, with a combination of Scala's
> DSL capabilities and (maybe (?)) a bit of compiler magic
> to implement all this in a way that using it is more elegant
>
> But then again, all this would rely on delegation instead of treats.
>
> Your efforts to (try to) accomplish the same flexibility+elegance
> using treats are much more challenging (and, if successful, would
> be much more worthwhile).
>
>
> Cheers,
>
> Luc
>
>
> On Fri, Dec 16, 2011 at 8:23 PM, Luc Duponcheel <luc.duponcheel@gmail.com>
> wrote:
>>
>> Hey, Kevin,
>>
>> First: I only wanted to give a non-technical remark :-) .
>>
>> Second: I agree that, essentially, we are talking about roles, and roles
>> are dynamic.
>>
>> I (implicitely) wanted to (only) discuss the topic from a static
>> perspective.
>>
>> Having full support (without any form of delegation (whatever that could
>> mean))
>> for dynamically changing roles is, probably, out of scope of any
>> statically typed
>> language anyway (I may be wrong).
>>
>> Thanks for bringing this (important) aspect into this discussion.
>>
>> Cheers,
>>
>> Luc
>>
>>
>> On Fri, Dec 16, 2011 at 5:39 PM, Kevin Wright <kev.lee.wright@gmail.com>
>> wrote:
>>>
>>> I'm going to have to strongly disagree with both of you.
>>>
>>> Being a basketball player or being a husband are not inherent properties,
>>> you're still the same person if you e.g. get divorced (albeit a somewhat
>>> less wealthy person).
>>>
>>> These are merely roles that you perform; they're something that you do,
>>> not something that you are.  This is better modelled with objects that act
>>> as the roles, so there is a being-a-husband role that delegates to you (or
>>> to anyone else who's also being a husband).  The role specific behaviour is
>>> then dynamically mixed-in when it's required, and isn't permanently "baked
>>> in" to the concept of you-ness.
>>>
>>> Ideally, this could be modelled something like:
>>>
>>>   val you = Person("Luc")
>>>   val yourWife: Person = ...
>>>   val youAsHusband = you with HusbandOf(yourWife)
>>>
>>>
>>> But we can't do that at present, "with" is strictly a static construct.
>>>  This is better suited to fixed properties such as gender (neatly
>>> sidestepping the possibility of surgery for the sake of this discussion)
>>>
>>> It's something I've given a lot of thought to, and has lead me on a
>>> glorious whirlwind tour of writing compiler plugins.  Sadly, the resulting
>>> efforts have been limited as compared to my original vision
>>> (https://github.com/kevinwright/Autoproxy-Lite) - I'm ever-thwarted by
>>> challenges with synthesizing classes and methods in a way that keeps the
>>> type-checker happy.
>>>
>>> That then allows you to do something like:
>>>
>>>   class HusbandRole(@proxy person: Person, husbandOf: Person) extends
>>> Person {
>>>     def consumate() = ...
>>>     def payHousekeeping() = ...
>>>     def fileForDivorce() = ...
>>>   }
>>>
>>>   val you = Person("Luc")
>>>   val youAsHusband = HusbandRole(you, yourWife)
>>>
>>>
>>>
>>> On 16 December 2011 16:15, Piotr Gabryanczyk <piotrga@gmail.com> wrote:
>>>>
>>>> I can not agree more.
>>>> btw. My wife should see it :)
>>>>
>>>> I am going to quote myself here  "Traits are very nice
>>>> mechanism for extending observable behaviour of a class. They should
>>>> be used in scenarios where we want the additional (mixed-in) behaviour
>>>> to be available to the user of our API."
>>>>
>>>> In this case my wife is THE USER (some say the boss), so I am happy to
>>>> mix-in my observable behaviour as a husband.
>>>>
>>>> Piotr Gabryanczyk
>>>>
>>>> On 16 Dec 2011, at 15:58, Luc Duponcheel wrote:
>>>>
>>>> Here is some (agreed, maybe not very technical) opinion on traits versus
>>>> composition.
>>>>
>>>> imho it is also about implementation reuse by
>>>>  o delegating to others (i.e. delegating to reusable implementations)
>>>>     (can be done both using Java and Scala)
>>>>  o doing things yourself (i.e. mixing-in reusable implementations)
>>>>     (can be done using Scala)
>>>>
>>>> now, if OO claims to 'somehow model reality accurately',
>>>> then look at the following example:
>>>>
>>>> suppose you are both
>>>> a basketball player (say during the day)
>>>> and
>>>> the husband of your wife (say during the evening and the night)
>>>>
>>>> [ and assuming you really like playing basketball and really like your
>>>> wife ]
>>>>
>>>> would you not prefer to model this so that you implement both
>>>> "responsibilities" yourself
>>>> rather than, for example, delegating the husband "responsibilities" to
>>>> someone else?
>>>>
>>>> So, even from a pure modelling point of view, traits may sometimes be a
>>>> better choice :-)
>>>>
>>>> Luc
>>>>
>>>>
>>>> On Fri, Dec 16, 2011 at 11:48 AM, Piotr Gabryanczyk <piotrga@gmail.com>
>>>> wrote:
>>>>>
>>>>> In his book "Effective Java" Joshua Bloch advises us to use
>>>>> composition over inheritance. The main argument for using composition
>>>>> is that  inheritance violates encapsulation. Super class has to expose
>>>>> it's internals in order for subclass to extend it's behaviour; or
>>>>> subclass is dangerously dependent on superclass implementation.
>>>>>
>>>>> I wanted to examine this statement in the context of Scala and it's
>>>>> trait inheritance mechanism.
>>>>>
>>>>> Lets have a look at this two examples:
>>>>>
>>>>> Example 1:
>>>>>
>>>>> class Delegate{
>>>>>  val work = new Queue[Task]
>>>>>  def receive{
>>>>>     case t @ Task => work add(t)
>>>>>     case Available(worker) => worker ! (work next)
>>>>> ...
>>>>>  }
>>>>> }
>>>>>
>>>>> Example 2:
>>>>>
>>>>> class Delegate with QueueLike{
>>>>>  def receive{
>>>>>     case t @ Task =>  add(t)
>>>>>     case Available(worker) => worker ! next
>>>>> ...
>>>>>  }
>>>>> }
>>>>>
>>>>> Common code:
>>>>>
>>>>> trait QueueLike[T]{
>>>>>   private[this] val elements = new List[T]
>>>>>   def add(e:T) = ...
>>>>>   def next : T= ...
>>>>>   ...
>>>>> }
>>>>> class Queue extends QueueLike
>>>>>
>>>>>
>>>>> In example 2, we clearly see, that there is no danger of weakening
>>>>> encapsulation, because QueueLike is well specialised and encapsulated.
>>>>> Well is it? What if someone decided to override enqueue method? This
>>>>> could make it confusing for other developers reading the code, but
>>>>> there is no real danger of breaking encapsulation in our example.
>>>>>
>>>>> Ok it is not about encapsulation. What is it about than?
>>>>> Example 2 looks like less code (comparing to example 1) and less
>>>>> clutter. Seems nicer, but... From the API user point of view there is
>>>>> no reason why Delegate should extend QueueLike. It is Delegate's
>>>>> implementation detail. Moreover poor user could think he(she) should
>>>>> call the add(...) method instead of sending a message to the Delegate.
>>>>> So in our example, by using inheritance, we are exposing too much of
>>>>> the inherited class to the user, and it breaks the encapsulation?
>>>>>
>>>>> Well than in my opinion verdict is clear. Traits are very nice
>>>>> mechanism for extending observable behaviour of a class. They should
>>>>> be used in scenarios where we want the additional (mixed-in) behaviour
>>>>> to be available to the user of our API. In other cases I would still
>>>>> prefer composition to avoid exposing too much, to avoid confusing the
>>>>> user and keep high level of encapsulation.
>>>>>
>>>>> What do you think?
>>>>>
>>>>> Piotr Gabryanczyk
>>>>
>>>>
>>>>
>>>>
>>>> --
>>>>    __~O
>>>>   -\ <,
>>>> (*)/ (*)
>>>>
>>>> reality goes far beyond imagination
>>>>
>>>>
>>>
>>>
>>>
>>> --
>>> Kevin Wright
>>> mail: kevin.wright@scalatechnology.com
>>> gtalk / msn : kev.lee.wright@gmail.com
>>> quora: http://www.quora.com/Kevin-Wright
>>> google+: http://gplus.to/thecoda
>>> twitter: @thecoda
>>> vibe / skype: kev.lee.wright
>>> steam: kev_lee_wright
>>>
>>> "My point today is that, if we wish to count lines of code, we should not
>>> regard them as "lines produced" but as "lines spent": the current
>>> conventional wisdom is so foolish as to book that count on the wrong side of
>>> the ledger" ~ Dijkstra
>>>
>>
>>
>>
>> --
>>    __~O
>>   -\ <,
>> (*)/ (*)
>>
>> reality goes far beyond imagination
>>
>
>
>
> --
>    __~O
>   -\ <,
> (*)/ (*)
>
> reality goes far beyond imagination
>
Piotr Gabryanczyk
Joined: 2011-12-14,
User offline. Last seen 30 weeks 3 days ago.
Re: Inheritance vs composition in Scala?
On 16 Dec 2011, at 23:56, Josh Suereth wrote:

You can use inheritance to denote composition in Scala.

trait HasFoo {
  def foo: Foo
}

Things extending HasFoo denote that they contain some instance of Foo.

I am not quite sure how is the example above addressing the question "Inheritance or compositon in scala?"

In my book, Scala In Depth, I outline composition using members, inheritance and applicative functors.   Each have pros and cons.   The point being, it's not a black and white issue.

Before we rush and buy the book, could you possibly show us what you mean as a little teaser/freebie/ free book advertising :) ?
Piotr Gabryanczyk
Joshua.Suereth
Joined: 2008-09-02,
User offline. Last seen 32 weeks 5 days ago.
Re: Inheritance vs composition in Scala?

As an aside, I prefer type traits to represent roles, back to previous discussion.

On Dec 16, 2011 6:56 PM, "Josh Suereth" <joshua.suereth@gmail.com> wrote:

You can use inheritance to denote composition in Scala.

trait HasFoo {
  def foo: Foo
}

Things extending HasFoo denote that they contain some instance of Foo.

In my book, Scala In Depth, I outline composition using members, inheritance and applicative functors.   Each have pros and cons.   The point being, it's not a black and white issue.

On Dec 16, 2011 3:43 PM, "Piotr Gabryanczyk" <piotrga@gmail.com> wrote:
Guys,

Thank you for your comments.
I just wanted to refocus conversation back on the original question:
"Composition or inheritance? (in scala)"

Piotr Gabryanczyk
-
piotrga@gmail.com



On 16 December 2011 19:34, Luc Duponcheel <luc.duponcheel@gmail.com> wrote:
> By the way, Kevin,
>
> many years ago (early nineties), when I programmed C++,
> I wrote code for a "role pattern" similar to the state pattern
> (using a list of roles rather than just one state)
>
> ... using the pattern was far from elegant (I had a
> method "as" to dynamically decide about your role) ...
>
> ... very ugly ...
>
> maybe we can hope, with a combination of Scala's
> DSL capabilities and (maybe (?)) a bit of compiler magic
> to implement all this in a way that using it is more elegant
>
> But then again, all this would rely on delegation instead of treats.
>
> Your efforts to (try to) accomplish the same flexibility+elegance
> using treats are much more challenging (and, if successful, would
> be much more worthwhile).
>
>
> Cheers,
>
> Luc
>
>
> On Fri, Dec 16, 2011 at 8:23 PM, Luc Duponcheel <luc.duponcheel@gmail.com>
> wrote:
>>
>> Hey, Kevin,
>>
>> First: I only wanted to give a non-technical remark :-) .
>>
>> Second: I agree that, essentially, we are talking about roles, and roles
>> are dynamic.
>>
>> I (implicitely) wanted to (only) discuss the topic from a static
>> perspective.
>>
>> Having full support (without any form of delegation (whatever that could
>> mean))
>> for dynamically changing roles is, probably, out of scope of any
>> statically typed
>> language anyway (I may be wrong).
>>
>> Thanks for bringing this (important) aspect into this discussion.
>>
>> Cheers,
>>
>> Luc
>>
>>
>> On Fri, Dec 16, 2011 at 5:39 PM, Kevin Wright <kev.lee.wright@gmail.com>
>> wrote:
>>>
>>> I'm going to have to strongly disagree with both of you.
>>>
>>> Being a basketball player or being a husband are not inherent properties,
>>> you're still the same person if you e.g. get divorced (albeit a somewhat
>>> less wealthy person).
>>>
>>> These are merely roles that you perform; they're something that you do,
>>> not something that you are.  This is better modelled with objects that act
>>> as the roles, so there is a being-a-husband role that delegates to you (or
>>> to anyone else who's also being a husband).  The role specific behaviour is
>>> then dynamically mixed-in when it's required, and isn't permanently "baked
>>> in" to the concept of you-ness.
>>>
>>> Ideally, this could be modelled something like:
>>>
>>>   val you = Person("Luc")
>>>   val yourWife: Person = ...
>>>   val youAsHusband = you with HusbandOf(yourWife)
>>>
>>>
>>> But we can't do that at present, "with" is strictly a static construct.
>>>  This is better suited to fixed properties such as gender (neatly
>>> sidestepping the possibility of surgery for the sake of this discussion)
>>>
>>> It's something I've given a lot of thought to, and has lead me on a
>>> glorious whirlwind tour of writing compiler plugins.  Sadly, the resulting
>>> efforts have been limited as compared to my original vision
>>> (https://github.com/kevinwright/Autoproxy-Lite) - I'm ever-thwarted by
>>> challenges with synthesizing classes and methods in a way that keeps the
>>> type-checker happy.
>>>
>>> That then allows you to do something like:
>>>
>>>   class HusbandRole(@proxy person: Person, husbandOf: Person) extends
>>> Person {
>>>     def consumate() = ...
>>>     def payHousekeeping() = ...
>>>     def fileForDivorce() = ...
>>>   }
>>>
>>>   val you = Person("Luc")
>>>   val youAsHusband = HusbandRole(you, yourWife)
>>>
>>>
>>>
>>> On 16 December 2011 16:15, Piotr Gabryanczyk <piotrga@gmail.com> wrote:
>>>>
>>>> I can not agree more.
>>>> btw. My wife should see it :)
>>>>
>>>> I am going to quote myself here  "Traits are very nice
>>>> mechanism for extending observable behaviour of a class. They should
>>>> be used in scenarios where we want the additional (mixed-in) behaviour
>>>> to be available to the user of our API."
>>>>
>>>> In this case my wife is THE USER (some say the boss), so I am happy to
>>>> mix-in my observable behaviour as a husband.
>>>>
>>>> Piotr Gabryanczyk
>>>>
>>>> On 16 Dec 2011, at 15:58, Luc Duponcheel wrote:
>>>>
>>>> Here is some (agreed, maybe not very technical) opinion on traits versus
>>>> composition.
>>>>
>>>> imho it is also about implementation reuse by
>>>>  o delegating to others (i.e. delegating to reusable implementations)
>>>>     (can be done both using Java and Scala)
>>>>  o doing things yourself (i.e. mixing-in reusable implementations)
>>>>     (can be done using Scala)
>>>>
>>>> now, if OO claims to 'somehow model reality accurately',
>>>> then look at the following example:
>>>>
>>>> suppose you are both
>>>> a basketball player (say during the day)
>>>> and
>>>> the husband of your wife (say during the evening and the night)
>>>>
>>>> [ and assuming you really like playing basketball and really like your
>>>> wife ]
>>>>
>>>> would you not prefer to model this so that you implement both
>>>> "responsibilities" yourself
>>>> rather than, for example, delegating the husband "responsibilities" to
>>>> someone else?
>>>>
>>>> So, even from a pure modelling point of view, traits may sometimes be a
>>>> better choice :-)
>>>>
>>>> Luc
>>>>
>>>>
>>>> On Fri, Dec 16, 2011 at 11:48 AM, Piotr Gabryanczyk <piotrga@gmail.com>
>>>> wrote:
>>>>>
>>>>> In his book "Effective Java" Joshua Bloch advises us to use
>>>>> composition over inheritance. The main argument for using composition
>>>>> is that  inheritance violates encapsulation. Super class has to expose
>>>>> it's internals in order for subclass to extend it's behaviour; or
>>>>> subclass is dangerously dependent on superclass implementation.
>>>>>
>>>>> I wanted to examine this statement in the context of Scala and it's
>>>>> trait inheritance mechanism.
>>>>>
>>>>> Lets have a look at this two examples:
>>>>>
>>>>> Example 1:
>>>>>
>>>>> class Delegate{
>>>>>  val work = new Queue[Task]
>>>>>  def receive{
>>>>>     case t @ Task => work add(t)
>>>>>     case Available(worker) => worker ! (work next)
>>>>> ...
>>>>>  }
>>>>> }
>>>>>
>>>>> Example 2:
>>>>>
>>>>> class Delegate with QueueLike{
>>>>>  def receive{
>>>>>     case t @ Task =>  add(t)
>>>>>     case Available(worker) => worker ! next
>>>>> ...
>>>>>  }
>>>>> }
>>>>>
>>>>> Common code:
>>>>>
>>>>> trait QueueLike[T]{
>>>>>   private[this] val elements = new List[T]
>>>>>   def add(e:T) = ...
>>>>>   def next : T= ...
>>>>>   ...
>>>>> }
>>>>> class Queue extends QueueLike
>>>>>
>>>>>
>>>>> In example 2, we clearly see, that there is no danger of weakening
>>>>> encapsulation, because QueueLike is well specialised and encapsulated.
>>>>> Well is it? What if someone decided to override enqueue method? This
>>>>> could make it confusing for other developers reading the code, but
>>>>> there is no real danger of breaking encapsulation in our example.
>>>>>
>>>>> Ok it is not about encapsulation. What is it about than?
>>>>> Example 2 looks like less code (comparing to example 1) and less
>>>>> clutter. Seems nicer, but... From the API user point of view there is
>>>>> no reason why Delegate should extend QueueLike. It is Delegate's
>>>>> implementation detail. Moreover poor user could think he(she) should
>>>>> call the add(...) method instead of sending a message to the Delegate.
>>>>> So in our example, by using inheritance, we are exposing too much of
>>>>> the inherited class to the user, and it breaks the encapsulation?
>>>>>
>>>>> Well than in my opinion verdict is clear. Traits are very nice
>>>>> mechanism for extending observable behaviour of a class. They should
>>>>> be used in scenarios where we want the additional (mixed-in) behaviour
>>>>> to be available to the user of our API. In other cases I would still
>>>>> prefer composition to avoid exposing too much, to avoid confusing the
>>>>> user and keep high level of encapsulation.
>>>>>
>>>>> What do you think?
>>>>>
>>>>> Piotr Gabryanczyk
>>>>
>>>>
>>>>
>>>>
>>>> --
>>>>    __~O
>>>>   -\ <,
>>>> (*)/ (*)
>>>>
>>>> reality goes far beyond imagination
>>>>
>>>>
>>>
>>>
>>>
>>> --
>>> Kevin Wright
>>> mail: kevin.wright@scalatechnology.com
>>> gtalk / msn : kev.lee.wright@gmail.com
>>> quora: http://www.quora.com/Kevin-Wright
>>> google+: http://gplus.to/thecoda
>>> twitter: @thecoda
>>> vibe / skype: kev.lee.wright
>>> steam: kev_lee_wright
>>>
>>> "My point today is that, if we wish to count lines of code, we should not
>>> regard them as "lines produced" but as "lines spent": the current
>>> conventional wisdom is so foolish as to book that count on the wrong side of
>>> the ledger" ~ Dijkstra
>>>
>>
>>
>>
>> --
>>    __~O
>>   -\ <,
>> (*)/ (*)
>>
>> reality goes far beyond imagination
>>
>
>
>
> --
>    __~O
>   -\ <,
> (*)/ (*)
>
> reality goes far beyond imagination
>
Sebastien Bocq
Joined: 2008-12-18,
User offline. Last seen 42 years 45 weeks ago.
Re: Inheritance vs composition in Scala?


2011/12/16 Piotr Gabryanczyk <piotrga@gmail.com>
In his book "Effective Java" Joshua Bloch advises us to use
composition over inheritance. The main argument for using composition
is that  inheritance violates encapsulation. Super class has to expose
it's internals in order for subclass to extend it's behaviour; or
subclass is dangerously dependent on superclass implementation.

I wanted to examine this statement in the context of Scala and it's
trait inheritance mechanism.

Lets have a look at this two examples:

Example 1:

class Delegate{
 val work = new Queue[Task]
 def receive{
    case t @ Task => work add(t)
    case Available(worker) => worker ! (work next)
...
 }
}

Example 2:

class Delegate with QueueLike{
 def receive{
    case t @ Task =>  add(t)
    case Available(worker) => worker ! next
...
 }
}

Common code:

trait QueueLike[T]{
  private[this] val elements = new List[T]
  def add(e:T) = ...
  def next : T= ...
  ...
}
class Queue extends QueueLike


In example 2, we clearly see, that there is no danger of weakening
encapsulation, because QueueLike is well specialised and encapsulated.
Well is it? What if someone decided to override enqueue method? This
could make it confusing for other developers reading the code, but
there is no real danger of breaking encapsulation in our example.

Ok it is not about encapsulation. What is it about than?
Example 2 looks like less code (comparing to example 1) and less
clutter. Seems nicer, but... From the API user point of view there is
no reason why Delegate should extend QueueLike. It is Delegate's
implementation detail. Moreover poor user could think he(she) should
call the add(...) method instead of sending a message to the Delegate.
So in our example, by using inheritance, we are exposing too much of
the inherited class to the user, and it breaks the encapsulation?

Well than in my opinion verdict is clear. Traits are very nice
mechanism for extending observable behaviour of a class. They should
be used in scenarios where we want the additional (mixed-in) behaviour
to be available to the user of our API. In other cases I would still
prefer composition to avoid exposing too much, to avoid confusing the
user and keep high level of encapsulation.

What do you think?

Piotr Gabryanczyk

When I came to Scala I was very excited about mixins. Today, I think it is a feature that warrants Scala's complexity because it is harder to maintain. So, I always favour composition over inheritance, even if it takes a bit more work.

When a class implements many mixins, I find it very difficult to know which methods are implemented where, and which feature of one trait interacts with a feature defined of another trait. For example, I find it very difficult to navigate Scala collections without good IDE support or Scala doc online. It is like for n mixins inhertited by a class you have potentially O(2^(n-1)) feature interactions.

Maybe it is possible to do with just classes and interfaces and use import/export module syntax like in Haskell to cut off some of the boiler plate needed for composition... but that would probably be another language than Scala :)

Cheers!
Sébastien

*Formula provided as such, without any correctness guarantees.
Piotr Gabryanczyk
Joined: 2011-12-14,
User offline. Last seen 30 weeks 3 days ago.
Re: Inheritance vs composition in Scala?

Piotr Gabryanczyk
On 17 Dec 2011, at 12:16, Sébastien Bocq wrote:
When I came to Scala I was very excited about mixins. Today, I think it is a feature that warrants Scala's complexity because it is harder to maintain. So, I always favour composition over inheritance, even if it takes a bit more work.
Do you think that there are some cases where mix-ins would be preferable? 
When a class implements many mixins, I find it very difficult to know which methods are implemented where, and which feature of one trait interacts with a feature defined of another trait.
What if traits would be orthogonal to each other and would enrich the class functionality, so there is no name clashes? Would it be acceptable? i.e.trait PersistableInDB[T]{  def  saveInDB = ...  def loadFromDB(id:Long) :T =    ...}
trait Drawable{  def drawOn(canvas:Canvas) = ...}
trait Multiplicable{ def *(other : Multiplicable) = ...}
class Matrix extends PersistableInDB[Matrix] with Drawable with Multiplicable{...}
For example, I find it very difficult to navigate Scala collections without good IDE support or Scala doc online. It is like for n mixins inhertited by a class you have potentially O(2^(n-1)) feature interactions. 
I agree, scala collections could be a bit intimidating at first. Have you seen SeqMethods, TraversableMethods, etc? They are interfaces (in Java sense) of scala collections and clarify a lot.

Maybe it is possible to do with just classes and interfaces and use import/export module syntax like in Haskell to cut off some of the boiler plate needed for composition... but that would probably be another language than Scala :)

Cheers!
Sébastien

Sebastien Bocq
Joined: 2008-12-18,
User offline. Last seen 42 years 45 weeks ago.
Re: Inheritance vs composition in Scala?


2011/12/17 Piotr Gabryanczyk <piotrga@gmail.com>

Piotr Gabryanczyk
On 17 Dec 2011, at 12:16, Sébastien Bocq wrote:
When I came to Scala I was very excited about mixins. Today, I think it is a feature that warrants Scala's complexity because it is harder to maintain. So, I always favour composition over inheritance, even if it takes a bit more work.
Do you think that there are some cases where mix-ins would be preferable? 
When a class implements many mixins, I find it very difficult to know which methods are implemented where, and which feature of one trait interacts with a feature defined of another trait.
What if traits would be orthogonal to each other and would enrich the class functionality, so there is no name clashes? Would it be acceptable? i.e.trait PersistableInDB[T]{  def  saveInDB = ...   def loadFromDB(id:Long) :T =    ...}
trait Drawable{  def drawOn(canvas:Canvas) = ...}
trait Multiplicable{ def *(other : Multiplicable) = ... }
class Matrix extends PersistableInDB[Matrix] with Drawable with Multiplicable{...}
For example, I find it very difficult to navigate Scala collections without good IDE support or Scala doc online. It is like for n mixins inhertited by a class you have potentially O(2^(n-1)) feature interactions. 
I agree, scala collections could be a bit intimidating at first. Have you seen SeqMethods, TraversableMethods, etc? They are interfaces (in Java sense) of scala collections and clarify a lot.

Maybe it is possible to do with just classes and interfaces and use import/export module syntax like in Haskell to cut off some of the boiler plate needed for composition... but that would probably be another language than Scala :)

Cheers!
Sébastien


There are trivial cases where it is harmless, but it should be used with caution. For instance, coupling Matrix with PersistableInDB in your example is already shooting yourself in the foot:
- Someone that wants to use just Matrix has to drag in dependencies to Persistable.
- It make it more difficult to maintain these traits independently, although these two concepts are completely orthogonal.

The general advice is to prefer short & pure interfaces and keep features as decoupled as possible until the last moment. Once the time comes to compose features, I prefer composition over inheritance. Composition takes a bit more manual work to express dependencies but on the other hand it makes the code easier to reason about and maintain. 

It seems I'm not the only one having "mixed" feeling about traits, see the remark posted a few hours ago on scala-debate:
http://groups.google.com/group/scala-debate/msg/99ca3dd15c74f5ea

On Sat, Dec 17, 2011 at 18:01, Paul Phillips <pa...@improving.org> wrote:
 
"I feel like traits have been something of a trap in that
they have reduced the motivation to cleanly define interfaces, and they
have made it too easy to reuse code (and actually, too hard not to) so
code ends up being reused in places where the implementation for that
purpose is questionable at best; and in other cases the "reused" code
becomes a hostile entity which one must defend against by being sure to
override the existing implementation.
...
I wish we had language support for pure interfaces, by the way.  There's
no way to write a trait and require that it provide no implementations.
 We could make "abstract trait" mean this. "

Maybe it could just be called "interface" :)

Cheers,
Sébastien
Piotr Gabryanczyk
Joined: 2011-12-14,
User offline. Last seen 30 weeks 3 days ago.
Re: Inheritance vs composition in Scala?


There are trivial cases where it is harmless, but it should be used with caution.
Well this is what I am talking about. Maybe If we kept things simple, we could benefit from using traits without the aforementioned risks?
For instance, coupling Matrix with PersistableInDB in your example is already shooting yourself in the foot:
- Someone that wants to use just Matrix has to drag in dependencies to Persistable.
I have heard this argument many times and it is valid when someone is writing a library. However in the live system often objects are inherently persistable or drawable and there is no point of stripping them of this behaviour to get the hypothetical reuse or lack of coupling.In this particular example if wanted to reuse Matrix behaviour I would probably define MatrixLike trait and then in my live system I would have Matrix which would extend aforementioned traits plus MatrixLike. Others would be free to reuse MatrixLike, without dragging the database into it.
- It make it more difficult to maintain these traits independently, although these two concepts are completely orthogonal.
Agreed. We want traits to be orthogonal.
The general advice is to prefer short & pure interfaces and keep features as decoupled as possible until the last moment. Once the time comes to compose features, I prefer composition over inheritance. Composition takes a bit more manual work to express dependencies but on the other hand it makes the code easier to reason about and maintain. 
I agree, moreover traits can be decoupled and can be mixed-in at the last moment, and they are not harder to maintain when certain good practices are applied.  So, maybe they could be considered as a "composition vehicle"?


It seems I'm not the only one having "mixed" feeling about traits, see the remark posted a few hours ago on scala-debate:
http://groups.google.com/group/scala-debate/msg/99ca3dd15c74f5ea
Does the fact that the knife is sharp imply that you shouldn't use it?
Sebastien Bocq
Joined: 2008-12-18,
User offline. Last seen 42 years 45 weeks ago.
Re: Inheritance vs composition in Scala?


2011/12/18 Piotr Gabryanczyk <piotrga@gmail.com>


There are trivial cases where it is harmless, but it should be used with caution.
Well this is what I am talking about. Maybe If we kept things simple, we could benefit from using traits without the aforementioned risks?
For instance, coupling Matrix with PersistableInDB in your example is already shooting yourself in the foot:
- Someone that wants to use just Matrix has to drag in dependencies to Persistable.
I have heard this argument many times and it is valid when someone is writing a library. However in the live system often objects are inherently persistable or drawable and there is no point of stripping them of this behaviour to get the hypothetical reuse or lack of coupling. In this particular example if wanted to reuse Matrix behaviour I would probably define MatrixLike trait and then in my live system I would have Matrix which would extend aforementioned traits plus MatrixLike. Others would be free to reuse MatrixLike, without dragging the database into it.
I don't think using traits buys you anything better in your example. I could take a well tested Matrix class in a third party library and use another class in a persistence layer to persist it when required.
- It make it more difficult to maintain these traits independently, although these two concepts are completely orthogonal.
Agreed. We want traits to be orthogonal.
The general advice is to prefer short & pure interfaces and keep features as decoupled as possible until the last moment. Once the time comes to compose features, I prefer composition over inheritance. Composition takes a bit more manual work to express dependencies but on the other hand it makes the code easier to reason about and maintain. 
I agree, moreover traits can be decoupled and can be mixed-in at the last moment, and they are not harder to maintain when certain good practices are applied.  So, maybe they could be considered as a "composition vehicle"?


It seems I'm not the only one having "mixed" feeling about traits, see the remark posted a few hours ago on scala-debate:
http://groups.google.com/group/scala-debate/msg/99ca3dd15c74f5ea
Does the fact that the knife is sharp imply that you shouldn't use it?

Definitely not, but I don't think the manual, with all the necessary warning and danger symbols, has yet been written. It is up to us to write the book. For example, traits (I mean partially implemented interface in this context) can be very helpful in to define default method implementations for fundamental typeclasses like in scalaz. E.g.
trait Applicative[Z[_]] extends Pointed[Z] with Apply[Z] {
  override def fmap[A, B](fa: Z[A], f: A => B): Z[B] = this(pure(f), fa)
}
trait Monad[M[_]] extends Applicative[M] with Bind[M] with Pointed[M] {
  override def fmap[A, B](fa: M[A], f: A => B) = bind(fa, (a: A) => pure(f(a)))
  override def apply[A, B](f: M[A => B], a: M[A]): M[B] = bind(f, (k: A => B) => fmap(a, k(_: A)))
}
Why is this a good example? I can't come up with a satisfying answer right now (maybe because these definitions stand on their own) but it is definitely something to ponder upon and contrast with other examples. If you or others want to share some experiences and other examples of what and what not to do with traits, please go ahead!

Sébastien
Matthew Pocock 3
Joined: 2010-07-30,
User offline. Last seen 42 years 45 weeks ago.
Re: Inheritance vs composition in Scala?


On 20 December 2011 00:07, Sébastien Bocq <sebastien.bocq@gmail.com> wrote:
 
Why is this a good example? I can't come up with a satisfying answer right now (maybe because these definitions stand on their own) but it is definitely something to ponder upon and contrast with other examples. If you or others want to share some experiences and other examples of what and what not to do with traits, please go ahead!

I'll bite. I have a typeclass called Interval with defs min, max, length. I've then got various methods that compare intervals e.g. checking for overlap or containment. Nearly all of the types for which I have Interval instances have ways to acquire min and max, but not length. It makes sense here to provide an implementation of length in the trait, defined in terms of min and max. It is important in my application that Interval is defined as a type-class, as the actual data comes from all sorts of APIs that have no natural common inheritance structure and in some cases are provided from different libraries. Requiring each of these 'interval-like' data-types to conform to the Interval interface would be a non-starter. Requiring every instance to implement all 3 methods seems a bit heavy when they can all be implemented in terms of each other.
Matthew 

Sébastien



--
Dr Matthew PocockIntegrative Bioinformatics Group, School of Computing Science, Newcastle Universitymailto: turingatemyhamster@gmail.com gchat: turingatemyhamster@gmail.commsn: matthew_pocock@yahoo.co.uk irc.freenode.net: drdozerskype: matthew.pococktel: (0191) 2566550mob: +447535664143
Razvan Cojocaru 3
Joined: 2010-07-28,
User offline. Last seen 42 years 45 weeks ago.
RE: Inheritance vs composition in Scala?

As I know it,

 

Composition is generally preferred to inheritance, since it reduces coupling – effects of changes are not as large and unforeseen as in the other case.

 

Also, if you're looking for a generic design pattern to not use traits, I strongly recommend James Coplien's DCI. Look it up - he makes clear references to scala and traits to describe roles. This will give you a good, strong framework for when to use traits and inheritance and where composition.

 

There was a nice talk of J.C. on DCI, where he mixes in scala and explains that in true OO design, you blow up the code and methods have an average of 3 lines of code. It has become rather rigid and hard to understand/maintain, i.e. stupid.

 

I agree on the collections - I think it could use some code duplication to simplify the structure.

 

I hope this won’t follow the path of former OO vs FP threads…?

 

Cheers,

Razie

 

From: scala-user@googlegroups.com [mailto:scala-user@googlegroups.com] On Behalf Of Piotr Gabryanczyk
Sent: December-17-11 5:38 PM
To: Sébastien Bocq
Cc: scala-user@googlegroups.com
Subject: Re: [scala-user] Inheritance vs composition in Scala?

 

 

Piotr Gabryanczyk

 

On 17 Dec 2011, at 12:16, Sébastien Bocq wrote:



When I came to Scala I was very excited about mixins. Today, I think it is a feature that warrants Scala's complexity because it is harder to maintain. So, I always favour composition over inheritance, even if it takes a bit more work.

Do you think that there are some cases where mix-ins would be preferable? 



When a class implements many mixins, I find it very difficult to know which methods are implemented where, and which feature of one trait interacts with a feature defined of another trait.

What if traits would be orthogonal to each other and would enrich the class functionality, so there is no name clashes? Would it be acceptable? i.e.

trait PersistableInDB[T]{

  def  saveInDB = ...

  def loadFromDB(id:Long) :T = 

   ...

}

 

trait Drawable{

  def drawOn(canvas:Canvas) = ...

}

 

trait Multiplicable{

 def *(other : Multiplicable) = ...

}

 

class Matrix extends PersistableInDB[Matrix] with Drawable with Multiplicable{

...

}



For example, I find it very difficult to navigate Scala collections without good IDE support or Scala doc online. It is like for n mixins inhertited by a class you have potentially O(2^(n-1)) feature interactions. 

I agree, scala collections could be a bit intimidating at first. Have you seen SeqMethods, TraversableMethods, etc? They are interfaces (in Java sense) of scala collections and clarify a lot.




Maybe it is possible to do with just classes and interfaces and use import/export module syntax like in Haskell to cut off some of the boiler plate needed for composition... but that would probably be another language than Scala :)

Cheers!
Sébastien

 

Luc Duponcheel
Joined: 2008-12-19,
User offline. Last seen 34 weeks 3 days ago.
Re: Inheritance vs composition in Scala?
Hi,

> I strongly recommend James Coplien's DCI.

which, imho, somehow brings us back to my original
(somewhat non-technical) remark about modeling things

James Coplien wites in his "Properties of DCI":

 o We use roles to capture the main user concepts that participate in a Use Case requirement.
 o ...

 o DCI is a natural fit for Agile software development. It allows programmers to connect directly with the end user mental model.

somehow (as far as I understand it) he favors traits
(here is a quote:"Traits as the design trick to combine characteristics and purpose")
and claims that Scala naturally supports the concept
(here is a quote: "in Scala, traits are implemented by a language construct called, curiously enough,
a trait, whose methods can be injected into an object at instantiation time.
")


nevertheless:
I buy into the claim of Sébastien not to blindly fall in love with them.
(btw: it is best to never, ever, blindly fall in love with anything)


Luc

On Tue, Dec 20, 2011 at 8:27 PM, Razvan Cojocaru <pub@razie.com> wrote:

As I know it,

 

Composition is generally preferred to inheritance, since it reduces coupling – effects of changes are not as large and unforeseen as in the other case.

 

Also, if you're looking for a generic design pattern to not use traits, I strongly recommend James Coplien's DCI. Look it up - he makes clear references to scala and traits to describe roles. This will give you a good, strong framework for when to use traits and inheritance and where composition.

 

There was a nice talk of J.C. on DCI, where he mixes in scala and explains that in true OO design, you blow up the code and methods have an average of 3 lines of code. It has become rather rigid and hard to understand/maintain, i.e. stupid.

 

I agree on the collections - I think it could use some code duplication to simplify the structure.

 

I hope this won’t follow the path of former OO vs FP threads…?

 

Cheers,

Razie

 

From: scala-user@googlegroups.com [mailto:scala-user@googlegroups.com] On Behalf Of Piotr Gabryanczyk
Sent: December-17-11 5:38 PM
To: Sébastien Bocq
Cc: scala-user@googlegroups.com
Subject: Re: [scala-user] Inheritance vs composition in Scala?

 

 

Piotr Gabryanczyk

 

On 17 Dec 2011, at 12:16, Sébastien Bocq wrote:



When I came to Scala I was very excited about mixins. Today, I think it is a feature that warrants Scala's complexity because it is harder to maintain. So, I always favour composition over inheritance, even if it takes a bit more work.

Do you think that there are some cases where mix-ins would be preferable? 



When a class implements many mixins, I find it very difficult to know which methods are implemented where, and which feature of one trait interacts with a feature defined of another trait.

What if traits would be orthogonal to each other and would enrich the class functionality, so there is no name clashes? Would it be acceptable? i.e.

trait PersistableInDB[T]{

  def  saveInDB = ...

  def loadFromDB(id:Long) :T = 

   ...

}

 

trait Drawable{

  def drawOn(canvas:Canvas) = ...

}

 

trait Multiplicable{

 def *(other : Multiplicable) = ...

}

 

class Matrix extends PersistableInDB[Matrix] with Drawable with Multiplicable{

...

}



For example, I find it very difficult to navigate Scala collections without good IDE support or Scala doc online. It is like for n mixins inhertited by a class you have potentially O(2^(n-1)) feature interactions. 

I agree, scala collections could be a bit intimidating at first. Have you seen SeqMethods, TraversableMethods, etc? They are interfaces (in Java sense) of scala collections and clarify a lot.




Maybe it is possible to do with just classes and interfaces and use import/export module syntax like in Haskell to cut off some of the boiler plate needed for composition... but that would probably be another language than Scala :)

Cheers!
Sébastien

 




--
   __~O
  -\ <,
(*)/ (*)

reality goes far beyond imagination

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland