Skip to content

Instantly share code, notes, and snippets.

@kevin-lee
Last active April 23, 2023 19:19
Show Gist options
  • Save kevin-lee/158d3d5c3e036560f8962087a34c95c5 to your computer and use it in GitHub Desktop.
Save kevin-lee/158d3d5c3e036560f8962087a34c95c5 to your computer and use it in GitHub Desktop.
trait Newtype[A] {
opaque type Type = A
inline def apply(a: A): Type = a
given newtypeCanEqual: CanEqual[Type, Type] = CanEqual.derived
extension (typ: Type) {
def value: A = typ
}
}
trait Refined[A] {
import compiletime.*
opaque type Type = A
given newRefinedCanEqual: CanEqual[Type, Type] = CanEqual.derived
inline def apply(a: A): Type =
inline if predicate(a) then a else error("Invalid value: " + codeOf(a))
def from(a: A): Either[String, Type] =
if predicate(a) then Right(a) else Left("Invalid value: " + a)
def predicate(a: A): Boolean
extension (typ: Type) {
def value: A = typ
}
}
type Name = Name.Type
object Name extends Newtype[String]
type PositiveInt = PositiveInt.Type
object PositiveInt extends Refined[Int] {
inline override def predicate(a: Int): Boolean = a > 0
}
type MyInt = MyInt.Type
object MyInt extends Newtype[PositiveInt]
def hello(name: Name): Unit = println(s"Hello ${name.value}")
@main def run(): Unit = {
val n = 1
val n2 = 0
println(PositiveInt.from(n)) // Right(1)
println(PositiveInt.from(n2)) // Left(Invalid value: 0)
hello(Name("Kevin")) // Hello Kevin
println(PositiveInt(1) == PositiveInt(1)) // true
println(PositiveInt(1) == PositiveInt(2)) // false
println(PositiveInt(1)) // 1
// println(PositiveInt(0)) // compile-time error
println(MyInt(PositiveInt(1)) == MyInt(PositiveInt(1))) // true
println(MyInt(PositiveInt(1))) // 1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment