Newtypes
Typesafe wrappers
Newtypes is een gratis Scala voor backend-engineering en functioneel programmeren-les op CoddyKit. Dit is les 3 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Scala voor backend-engineering en functioneel programmeren. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Scala voor backend-engineering en functioneel programmeren bevat in totaal 4 lessen.
Typesafe wrappers
Een newtype is een afzonderlijk type dat één onderliggende waarde omhult. Het voorkomt dat je waarden verwisselt die dezelfde primitieve representatie hebben, zoals een UserId en een ProductId die beide Ints zijn.
case class UserId(value: Int)
case class ProductId(value: Int)
object Main:
def main(args: Array[String]): Unit =
val u = UserId(1)
val p = ProductId(1)
println(u.value == p.value) // values equal, types differHet probleem van primitieve fixatie
Primitieve fixatie betekent dat je String en Int te veel gebruikt voor domeinconcepten. Daardoor is onzinnigheid mogelijk, zoals een e-mailadres doorgeven waar een naam hoort. Newtypes lossen dit op door elk concept een eigen type te geven.
case class Email(value: String)
case class City(value: String)
object Main:
def greet(c: City): String = s"Welcome to ${c.value}"
def main(args: Array[String]): Unit =
println(greet(City("Berlin")))Newtypes met case class
De eenvoudigste newtype is een case class met één veld. Deze biedt gelijkheid, een leesbare toString en pattern matching zonder extra werk. De prijs is één objecttoewijzing per waarde.
case class OrderId(value: String)
object Main:
def main(args: Array[String]): Unit =
val id = OrderId("ORD-42")
println(id)
println(id.value)Newtypes met opaque types
Gebruik voor nul toewijzingen een opaque type als newtype. Tijdens runtime gedraagt het zich als het onderliggende type, maar tijdens het compileren is het ervan onderscheiden.
object Ids:
opaque type UserId = Int
def apply(i: Int): UserId = i
extension (u: UserId) def value: Int = u
object Main:
def main(args: Array[String]): Unit =
val u = Ids(7)
println(u.value)Gedrag toevoegen met extensies
Geef een newtype bewerkingen via extension-methoden, waarbij je alleen beschikbaar maakt wat bij het domeinconcept past.
object Money:
opaque type Cents = Long
def apply(n: Long): Cents = n
extension (c: Cents)
def +(o: Cents): Cents = c + o
def toDollars: Double = c / 100.0
object Main:
def main(args: Array[String]): Unit =
val total = Money(250) + Money(750)
println(total.toDollars)Newtypes in functiesignaturen
Newtypes maken signaturen zelfdocumenterend en detecteren fouten in de volgorde van argumenten tijdens het compileren. Je kunt niet per ongeluk twee parameters van verschillende newtypes verwisselen.
case class Width(value: Int)
case class Height(value: Int)
object Main:
def area(w: Width, h: Height): Int = w.value * h.value
def main(args: Array[String]): Unit =
println(area(Width(4), Height(5)))Newtypes en verzamelingen
Een Map met een newtype als sleutel is duidelijker en veiliger dan een map met een onbewerkte Int als sleutel. Het type voorkomt dat je de verkeerde soort sleutel gebruikt.
case class UserId(value: Int)
object Main:
def main(args: Array[String]): Unit =
val names = Map(UserId(1) -> "Ada", UserId(2) -> "Bob")
println(names(UserId(2)))Gevalideerde newtypes
Combineer een newtype met een slimme constructor, zodat de wrapper ook invarianten afdwingt. Een NonEmptyString kan hier nooit leeg zijn.
case class NonEmptyString private (value: String)
object NonEmptyString:
def of(s: String): Option[NonEmptyString] =
if s.nonEmpty then Some(NonEmptyString(s)) else None
object Main:
def main(args: Array[String]): Unit =
println(NonEmptyString.of("hi"))
println(NonEmptyString.of(""))Een representatie kiezen
Kies op basis van je behoeften.
- case class: het eenvoudigst, geschikt voor pattern matching, maar maakt een object aan.
- opaque type: zonder kosten, zonder boxing, ideaal voor kritieke codepaden en grote verzamelingen.
object Temp:
opaque type Kelvin = Double
def apply(d: Double): Kelvin = d
extension (k: Kelvin) def value: Double = k
object Main:
def main(args: Array[String]): Unit =
val readings = List(Temp(300.0), Temp(310.5))
println(readings.map(_.value).sum)Onbedoelde conversies voorkomen
Twee newtypes op basis van hetzelfde type worden niet impliciet naar elkaar geconverteerd. Om van het ene naar het andere te gaan, schrijf je een expliciete functie die de bedoeling documenteert.
case class Meters(value: Double)
case class Feet(value: Double)
object Main:
def toFeet(m: Meters): Feet = Feet(m.value * 3.281)
def main(args: Array[String]): Unit =
println(toFeet(Meters(2.0)))Wanneer gebruik je newtypes
Gebruik newtypes zodra een primitief type een betekenis in het domein heeft.
- Identificatiegegevens, eenheden en opgemaakte tekenreeksen.
- Gebruik een case class voor eenvoud en een opaque type voor prestaties.
- Voeg een slimme constructor toe wanneer er invarianten zijn.
object Domain:
opaque type Sku = String
def of(s: String): Option[Sku] =
if s.startsWith("SKU-") then Some(s) else None
extension (k: Sku) def raw: String = k
object Main:
def main(args: Array[String]): Unit =
println(Domain.of("SKU-9").map(_.raw))Korte controle
Test je begrip van newtypes.
Samenvatting
Je hebt newtypes geleerd.
- Newtypes omhullen één onderliggende waarde in een afzonderlijk type.
- Ze verhelpen primitieve fixatie en voorkomen verwisselingen van argumenten.
- Gebruik
case classvoor eenvoud enopaque typevoor nul kosten. - Voeg een slimme constructor toe voor gevalideerde wrappers.
- Conversies tussen newtypes zijn altijd expliciet.
object Ids:
opaque type AccountId = Long
def apply(n: Long): AccountId = n
extension (a: AccountId) def value: Long = a
object Main:
def main(args: Array[String]): Unit =
val acc = Ids(1001L)
println(acc.value)Leer Scala met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 39
- Lessen
- 143
Veelgestelde vragen
Is de les “Newtypes” gratis?
Ja — de volledige tekst van “Newtypes” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus Scala voor backend-engineering en functioneel programmeren wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus Scala voor backend-engineering en functioneel programmeren bevat in totaal 4 lessen.
Wat leer ik in “Newtypes”?
Typesafe wrappers Je oefent met Scala voor backend-engineering en functioneel programmeren door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met Scala voor backend-engineering en functioneel programmeren te beginnen?
Ervaring vooraf is niet nodig. Scala voor backend-engineering en functioneel programmeren op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 3 van 4.
Hoe lang duurt de les “Newtypes”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over Scala voor backend-engineering en functioneel programmeren?
Ja. Elke les over Scala voor backend-engineering en functioneel programmeren bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.