Last active
March 7, 2025 12:47
-
-
Save programaker/09de2a15cfa587cdbe78fb724d33e6c2 to your computer and use it in GitHub Desktop.
Scala 3 export clauses
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* The good practices say we shouldn't use the same type for everything (domain, json, persistence, ...), but | |
* most of the time those types are very similar - if not exactly identical - creating a lot of duplication. | |
* | |
* Inheritance to the rescue? Nah... not very FP and even the OOP folks are aware that we should | |
* prefer composition over it. But composition has it's own challenges (Law of Demeter for instance). | |
* | |
* Let's see how the new `Export Clauses` in Scala 3 can help with that: | |
* https://docs.scala-lang.org/scala3/reference/other-new-features/export.html | |
* */ | |
import io.circe.Encoder | |
import io.circe.generic.semiauto.* | |
import io.circe.syntax.* | |
import java.util.UUID | |
// the pure domain concept/entity | |
// the base data is declared here, and only here | |
case class Frunfles(a: String, b: Int, c: Boolean) | |
object Frunfles: | |
given Encoder[Frunfles] = deriveEncoder | |
// persisted entity containing an id | |
// no need to make the id optional | |
// no need to duplicate Frunfles fields | |
case class PersistedFrunfles(id: UUID, data: Frunfles): | |
export data.* | |
object PersistedFrunfles: | |
// easy to avoid exposing the id in Json | |
given Encoder[PersistedFrunfles] = Encoder.instance(_.data.asJson) | |
// type-safe operations | |
// explictly stating which operations require an entity with id | |
def insert(f: Frunfles): PersistedFrunfles = ??? | |
def update(f: PersistedFrunfles): PersistedFrunfles = ??? | |
def delete(f: PersistedFrunfles): Unit = ??? | |
// composition over inheritance, more FP-ish | |
val f = Frunfles("Meh", 42, true) | |
val pf = PersistedFrunfles(id = UUID.randomUUID().nn, data = f) | |
// exported fields available without calling `.data`. Happy demeter! | |
val id = pf.id | |
val a2 = pf.a | |
val b2 = pf.b | |
val c2 = pf.c |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment