Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Easy, fast, transparent generic derivation of typeclass instances

License

NotificationsYou must be signed in to change notification settings

softwaremill/magnolia

Repository files navigation

Magnolia

GitHub Workflow

Magnolia

Magnolia is a generic macro for automatic materialization of typeclasses for datatypes composed from product types (e.g. case classes) and coproduct types (e.g. enums). It supports recursively-defined datatypes out-of-the-box, and incurs no significant time-penalty during compilation.

Features

  • derives typeclasses for case classes, case objects and sealed traits
  • offers a lightweight syntax for writing derivations without needing to understand complex parts of Scala
  • builds upon Scala 3's built-in generic derivation
  • works with recursive and mutually-recursive definitions
  • supports parameterized ADTs (GADTs), including those in recursive types
  • supports typeclasses whose generic type parameter is used in either covariant and contravariant positions

Getting Started

Given an ADT such as,

enumTree[+T]derivesPrint:caseBranch(left:Tree[T],right:Tree[T])caseLeaf(value:T)

and provided a given instance ofPrint[Int] is in scope, and a Magnolia derivation for thePrint typeclasshas been provided, we can automatically derive given typeclass instances ofPrint[Tree[Int]] on-demand, likeso,

Tree.Branch(Tree.Branch(Tree.Leaf(1),Tree.Leaf(2)),Tree.Leaf(3)).print

Typeclass authors may provide Magnolia derivations in the typeclass's companion object, but it is easy to createyour own.

Creating a generic derivation with Magnolia requires implementing two methods onmagnolia1.Derivation:

  • join() : create typeclasses for case classes ('product types')
  • split() : create typeclasses for sealed-traits/enums ('sum types')

Example derivations

There are many examples in theexamples sub-project.

The definition of aPrint typeclass with generic derivation might look like this(note we're using theLambda syntax for Single Abstract Method typesto instantiate thePrint instances injoin &split - that's possible becausePrint has only a single abstract method,print):

importmagnolia1.*traitPrint[T] {extension (x:T)defprint:String}objectPrintextendsAutoDerivation[Print]:defjoin[T](ctx:CaseClass[Print,T]):Print[T]= value=>    ctx.params.map { param=>      param.typeclass.print(param.deref(value))    }.mkString(s"${ctx.typeInfo.short}(",",",")")overridedefsplit[T](ctx:SealedTrait[Print,T]):Print[T]= value=>    ctx.choose(value) { sub=> sub.typeclass.print(sub.cast(value)) }givenPrint[Int]= _.toString

TheAutoDerivation trait provides a givenautoDerived method which will attempt to construct a corresponding typeclassinstance for the type passed to it. ImportingPrint.autoDerived as defined in the example above will make genericderivation forPrint typeclasses available in the scope of the import.

While any object may be used to define a derivation, if you control the typeclass you are deriving for, thecompanion object of the typeclass is the obvious choice since it generic derivations for that typeclass willbe automatically available for consideration during contextual search.

If you don't want to make the automatic derivation available in the given scope, consider using theDerivation trait which provides semi-auto derivation withderived method, but also brings some additional limitations.

Limitations

For accessing default values for case class parameters we recommend compilation with-Yretain-trees on.

For a recursive structures it is required to assign the derived value to an implicit variable e.g.

giveninstance:SemiPrint[Recursive]=SemiPrint.derived

Availability

For Scala 3:

valmagnolia="com.softwaremill.magnolia1_3"%%"magnolia"%"1.3.16"

For Scala 2, see thescala2 branch.

Package and artifact naming, versioning

The main magnolia package ismagnolia1, so that magnolia 1.x can be used alongside magnolia 0.17 (which are binary-incompatible).Future major releases of magnolia can change the package name for the same reason.

The group id for magnolia follows the naming scheme:com.softwaremill.magnolia[major version]_[scala major version].The scala major version suffix is necessary to allow evolving and publishing versions for Scala 2 & Scala 3 independently.The magnolia major version is included for consistency with the package name, and so that future major releases may beused alongside this release.

Contributing

Contributors to Magnolia are welcome and encouraged. New contributors may like to look for issues markedlabel: good first issue.

Credits

Magnolia was originally designed and developed byJon Pretty, and is currentlymaintained bySoftwareMill.

License

Magnolia is made available under theApache 2.0 License.


[8]ページ先頭

©2009-2025 Movatter.jp