
Stackable Traits Pattern in Scala - saheb37
https://code.sahebmotiani.com/patterns-in-scala-101-5d0fa70aaf3f#.1d15x2akq
======
lmm
I like the way Scala solves the problem with multiple inheritance as described
in [https://fuhm.net/super-harmful/](https://fuhm.net/super-harmful/) :
multiple inheritance is allowed, but only classes (not traits) may have
constructors, and a class may only have one parent class (i.e. only one parent
with a constructor).

For my part I still prefer composition over inheritance and prefer to do
composition "by hand" (i.e. explicit members and delegation) where necessary;
I wouldn't use this style at all. But Scala's great strength (and great
weakness) is that it has absolutely first-class support for traditional OO
like this as well as all the functional stuff.

~~~
jackweirdy
Could you expand on why you would say having support for traditional OO is a
great weakness?

~~~
lmm
It means there's a diversity of Scala styles; one person's Scala won't
necessarily look like someone else's. More concretely it causes a lot of
problems for type inference (particularly when ADTs in Scala are modeled as
traits with implementing classes, so e.g. the type of Some(x) ends up as Some
rather than Option). Other ML family languages that don't have traditional OO
inheritance generally have perfect type inference (at least in the absence of
higher kinds) via Hindley-Milner.

~~~
mafribe
Practical type inference for Hindley-Milner-style languages with higher kinds
is not a problem, see e.g. [1]. The problem is adding sub-typing.

I'm also not 100% sure it's correct to say that ML-style languages have no
problem with type-inference. I'm sure Robin Milner would have preferred having
full, unrestricted parametric polymorphism (i.e. System F) in ML. Alas System
F has undecidable type inference [2]. Hindley-Milner is a restriction of full
parametric polymorphism that enjoys type inference, and is expressive enough
to type many programs. BC Pierce says that the Hindley-Milner "has hit a
sweetspot". I concur.

[1] M. P. Jones, A system of constructor classes: overloading and implicit
higher-order polymorphism. [http://www.cs.tufts.edu/comp/150GIT/archive/mark-
jones/fpca9...](http://www.cs.tufts.edu/comp/150GIT/archive/mark-
jones/fpca93.pdf)

[2] J. B. Wells, Typability and type checking in System F are equivalent and
undecidable. [http://www.macs.hw.ac.uk/~jbw/papers/f-undecidable-
APAL.ps.g...](http://www.macs.hw.ac.uk/~jbw/papers/f-undecidable-APAL.ps.gz)

------
brandonmenc
> The example is based on characters of Game of Thrones, to make understanding
> concepts less boring.

For those of us who don't know anything about Game of Thrones, and can't
pronounce Elvish names, the example in this article reads like:

Flarg → Twipptch → Glorp → Boop → Fwyxnth → AnyRef → Any

So instead of being less boring, I have to use a decoder ring to figure out
what's going on here.

~~~
saheb37
I agree to your point, but was it that difficult to decode or follow till the
end? You think A, B, C, D would have been better? Or something more logical
names to everyone

~~~
brandonmenc
No, it wasn't impossible to follow, but the extra layer of indirection made me
jump back to the top a few times to make sure I had everything straight.

    
    
        //Legacy
        abstract class Lannister
    
        //Father
        trait Tywin extends Lannister
    

could have just been:

    
    
        abstract class Family
    
        trait Father extends Family
    

Otherwise, I appreciate the article - it was informative.

~~~
saheb37
Thanks, got your point, will keep it more simple and generic next time :)

------
oselhn
I think that it does not make sense that Jamie extends Tywin etc. This is not
"is a" relation.

~~~
saheb37
traits in Scala doesn't always have to be in a "is a" relationship. If it
makes you understand then think of them as adding behavior/mixins. And about
why the syntax confused you, the first "with" trait has to be extended, if it
could replace extends with "with" in case of traits then maybe you would have
liked it better.

~~~
oselhn
Trait in scala represents interface (your type understands some message) or
"is a" relation (your type is more specific specialization of type). In your
example it is not the case (Tywin is Jamie's father, which should be solved by
composition). I do not think that Tywin, Jamie etc. is separate type. In my
opinion, those are instances of some type. It is not good practise to call
super implementation of method either. You are mixing inheritance and
overriding, which in more complex programs always cause trouble (you may break
inherited method by changing super implementation). You should solve this by
composition (Jamie should not inherit Tywin addToDebt but should depend on
Tywin for paying his depts).

I understand what you wanted to show but your example is really confusing and
definitely is not correct.

~~~
saheb37
I agree its not a real life example :) It was never meant to be. And
definitely there is some better approach to implement the same hierarchy.

------
joefkelley
This seems like more of an antipattern to me. If you have to be thinking about
linearization order, your hierarchy is probably too complex.

~~~
SolarNet
I think the point is that if the hierarchy is complex enough that you have to
think about it it's simple enough to figure. The cases presented are obviously
over complex to describe the behavior.

~~~
saheb37
Maybe to make it more interesting, it turned out to complex as you are saying.
But idea was not to use A, B, C etc. Will try to come up with something
different next time.

------
jbooth
Alternate view:

[https://en.wikipedia.org/wiki/Composition_over_inheritance](https://en.wikipedia.org/wiki/Composition_over_inheritance)

~~~
twic
This sort of _is_ composition. It's like a static version of the Decorator
pattern. Here's a vaguely realistic example:

[http://blog.ryannedolan.info/2014/03/scala-pattern-
stackable...](http://blog.ryannedolan.info/2014/03/scala-pattern-stackable-
traits.html)

~~~
jbooth
Not really, at all. Order the traits differently and you can get different
behavior. Inherit one subtrait vs another and you can get different behavior.
You can reason about all of this, but I'm not that smart, so I prefer
composition.

Composition locks away the behavior you want so that you know exactly what
you're getting.

~~~
twic
I don't get it. If you're decorating, then ordering the decorators differently
gets you different behaviour. It's exactly the same.

Indeed, you could write a straightforward mechanical method to convert any
trait stacking into a decoration.

~~~
jbooth
Yeah -- I'm arguing for composition because it's harder to screw up, at the
cost of being less pretty. The manner and order in which composed objects are
delegated to is crystal clear if you're wiring them yourself (or with your
IDE). I've seen some messy, confusing code involving traits and just slapping
'with Thingy' 10 times in a row. The phrase 'emergent behavior' is how I would
best describe it.

