scalaz/scalaz — pull request #450 by S11001001 (2013-07-30 04:33:36+00:00)
Title: Replace more traits with classes

Sequel to #444.

The "classier" branch drops lots of traits in favor of final/abstract/case/plain classes. I've focused on core for now, but there are a few changes in e.g. effect; it is a long enough diff as it is. I've chosen things to maximize source compatibility (with a couple exceptions), but let's start with the most visible:

Case classes
------------

Some former traits are now final case classes, complete with members from `Product`, newly generated equals and hashCode, copy methods, and unapply methods.

I chose these where I thought that the data representation is sufficiently locked down that it would be safe to make it a matter of the binary API; it's much harder to eliminate vestiges of a poor case-class data choice while remaining binary-compatible than ordinary classes in the way I've encoded them.

I finalized existing case classes as a matter of course.

Final classes
-------------

Where I wanted to keep nonstrictness options open, or wasn't so confident of the representation, I made final or sealed abstract classes, in the former case with private constructors that we could fix later without breaking binary compatibility.

An example of this difference is `LazyEither`, kept a sealed abstract class to preserve its Church-encoded constructors' nonstrictness, versus `LazyEitherT`, which is only "lazy" in that it uses `LazyEither`, and is therefore a case class.

If you notice a choice I made that lacks symmetry for no good reason, please point it out. For example, transformers should be final case classes now unless defining as such was inconvenient to do source-compatibly.

Other abstract classes
----------------------

And, in some cases I made traits into abstract classes just because that's the easiest change to make, or because keeping exhaustivity checking was useful.

*Instances hierarchies
----------------------

For ADTs defined by scalaz itself (so the typeclass instances are not orphans), instances are now defined in (usually sealed) abstract classes instead of traits.

This prevents them from being mixed in somewhere else. However, because they are already extended by the ADT's companion, their presence in implicit-implicit scope should make that irrelevant.

extends Product with Serializable
---------------------------------

For abstract classes at the root of ADTs, I've added these silly supers to the root. [Here's why.](https://bazaar.launchpad.net/~scompall/stylish-types/trunk/view/head:/src/test/scala/com/nocandysw/stylishtypes/check/ProductIntersectionTypes.scala#L22) It's even worse than that: the inferred types look like `Product with Serializable with Box[B]`, and they erase to Object, not `Box[B]`, in the stored Java types.

The benefit is improved inference when using case classes explicitly; the drawback is that `Product` methods appear in the type itself. So keep this, remove it, whichever you like.

final classes for syntax
------------------------

A more extreme version of #429.