Skip to main content
Version: v1.16.0

Newtype

What is Newtype?

Newtype lets you create domain-specific types from existing value types with zero runtime overhead.

Newtype gives you:

  • stronger type-safety at compile-time
  • the same runtime representation as the original type
  • clear domain boundaries without wrappers or allocations

Newtype does not perform validation. If you need validation rules, use Refined or InlinedRefined.

Import

import refined4s.*

Define a Newtype

type NewtypeName = NewtypeName.Type
object NewtypeName extends Newtype[ActualType]

Example:

type Name = Name.Type
object Name extends Newtype[String]

Create Values

val newtypeName = NewtypeName(value)
val name = Name("Kevin")
// name: Type = "Kevin"

Get Actual Value

Use .value to unwrap the underlying value.

newtypeName.value
name.value
// res1: String = "Kevin"

Pattern Matching

Newtype provides unapply, so you can pattern match directly.

name match {
case Name(value) =>
println(s"Pattern matched value: $value")
}
// Pattern matched value: Kevin

Type-Safety Example

import refined4s.*

type Name = Name.Type
object Name extends Newtype[String]

type Email = Email.Type
object Email extends Newtype[String]

def hello(name: Name): Unit = println(s"Hello ${name.value}")

def send(email: Email): Unit = println(s"Sending email to ${email.value}")

val name = Name("Kevin")
// name: Type = "Kevin"
hello(name)
// Hello Kevin

val email = Email("kevin@blah.blah")
// email: Type = "kevin@blah.blah"
send(email)
// Sending email to kevin@blah.blah
hello("Kevin")
// error:
// Found: ("Kevin" : String)
// Required: repl.MdocSession.MdocApp1.Name
send("kevin@blah.blah")
// error:
// Found: ("kevin@blah.blah" : String)
// Required: repl.MdocSession.MdocApp1.Email

Functional Typeclass Derivation

Newtype can derive typeclass instances from its underlying type using deriving.

e.g.) Sorting the Name from the example above fails because Name does not have an Ordering instance.

List(Name("c"), Name("a"), Name("b")).sorted
// error:
// No given instance of type Ordering[repl.MdocSession.MdocApp1.Name.Type] was found for parameter ord of method sorted in trait StrictOptimizedSeqOps.
// I found:
//
// scala.math.Ordering.comparatorToOrdering[repl.MdocSession.MdocApp1.Name.Type](
// /* missing */summon[java.util.Comparator[repl.MdocSession.MdocApp1.Name.Type]]
// )
//
// But no implicit values were found that match type java.util.Comparator[repl.MdocSession.MdocApp1.Name.Type].
// List(Name("c"), Name("a"), Name("b")).sorted
// ^^^^^^

You can easily derive an Ordering instance for Name using deriving. So Ordering[Name] is derived from Ordering[String].

given Ordering[Name] = Name.deriving[Ordering]

List(Name("c"), Name("a"), Name("b")).sorted
// res9: List[Type] = List("a", "b", "c")