-
Notifications
You must be signed in to change notification settings - Fork 533
Migration guide: shapeless 2.0.0 to 2.1.0
shapeless-2.1.0 is largely backwards source compatible with shapeless-2.0.0, however you might need to make some minor changes as documented below. You might also find the complete set of differences in shapeless's examples and tests between 2.0.0 and 2.1.0 a useful guide to what's involved in updating. They can be found in this commit.
- TypeClass changes
- RecordType replaced by record and union type literals
- No Generic instances for HList and Coproduct
- Record/union definitions now in labelled package
- Typeable changes for null and intersection types
The type class deriving infrastructure included in shapeless-2.0.0 has been significantly reworked in shapeless-2.1.0.
It is now implemented entierly in terms of the Generic
and Lazy
type class primitives. Some applications which
required more flexibility that TypeClass
could provide can now be implemented directly in terms of those primitives
and general Scala implicit-based type level computation as seen throughout shapeless.
Applications already using the shapeless-2.0.0 TypeClass
infrastructure will need the following minor modifications,
- Removal of
auto._
imports.
Previously type class instances were only derived automatically in scopes where a wildcard import from the auto
member of the type classes companion object. This mechanism didn't transfer over well to the new implementation and in
any case experience showed it to be overly verbose while adding little value.
- Implicit
TypeClass
member replace bytypeClass
object in type class companion.
Where previously the type class derivation rules where introduced via an implicit definition of the form,
object Show {
implicit val showInstance: ProductTypeClass[Show] = new LabelledTypeClass[Show] {
def emptyProduct = ...
def product ...
def emptyCoproduct = ...
def coproduct ...
def project ...
}
}
they are now introduced via a nested object named typeClass
,
object Show {
object typeClass extends LabelledTypeClass[Show] {
def emptyProduct = ...
def product ...
def emptyCoproduct = ...
def coproduct ...
def project ...
}
}
In shapeless-2.0.0 record and union types were quite difficult to specify literally in source code. To make it somewhat easier a mechanism was included to allow these types to be inferred from example values,
val schema = RecordType.like('i ->> 23 :: 's ->> "foo" :: 'b ->> true :: HNil)
type R = schema.Record
type U = schema.Union
Whilst this was workable in simple case, it was verbose and clumsy.
In shapeless-2.1.0 this mechanism is replaced by an direct way to express record and union types without requiring a value for them to be inferred from,
import record._, union._
type R = Record.`'i -> Int, 's -> String, 'b -> Boolean`.T
type U = Union.`'i -> Int, 's -> String, 'b -> Boolean`.T
This is still far from ideal compared with first-class syntax for these types, nevertheless in situations where explicit types are required (primarily in tests) this notation is an improvement on what was available in 2.0.0.
In shapeless-2.0.0 Generic
instances were provided for HLists
and Coproducts
. These instances where identity
functions which, while somewhat motivated, were inconsistent with the way that other types were represented
generically. Because these types are used as generic representations of other types it proved to be awkward in
practice for them to have generic representations themselves, and as such it seems better to remove the instances
altogether.
It is unlikely that this change will impact users of Generic
. Since code expecting to handle arbitrary data types
via their generic representations will already have direct handling for HLists
and Coproducts
the absence of
Generic
instances for them should be problematic and may have the benefit of eliminating sources of implicit
ambiguity which might have been problematic with shapeless-2.0.0.
As the functionality for Coproducts
and unions has been filled out to match that available for HLists
and records
it has become useful to factor out some common infrastructure into a shared labelled
namespace. In shapeless-2.1.0
the types FieldType
and FieldPoly
, and the method field
are now imported from shapeless.labelled
.
In shapeless-2.0.0 it was possible to cast null
to any type. This was a mistake and it shapeless-2.1.0 it is not
possible to cast null
at all. If you depend on the 2.0.0 behaviour you should handle null
by an explicit test or
lifting into Option
as you would do elsewhere.
In shapeless-2.0.0 casts to types of the form A with B
, A with B with C
etc. would only verify the runtime type
for the first element of the intersection (ie. A
in the examples just given). In shapeless-2.1.0 all parts of the
intersection are verified.