Skip to content

Latest commit

 

History

History
104 lines (87 loc) · 2.84 KB

README.md

File metadata and controls

104 lines (87 loc) · 2.84 KB

Module Arrow Exact

Arrow Exact allows you to use Kotlin's type system to enforce exactness of data structures.

Introduction

Exact allows automatically projecting smart-constructors on a Companion Object. We can for example easily create a NotBlankString type that is a String that is not blank, leveraging the Arrow's Raise DSL to ensure the value is not blank.

import arrow.core.raise.Raise
import arrow.exact.Exact
import arrow.exact.ExactError
import arrow.exact.ensure
import kotlin.jvm.JvmInline

@JvmInline
value class NotBlankString private constructor(val value: String) { 
  companion object : Exact<String, NotBlankString> {
    override fun Raise<ExactError>.spec(raw: String): NotBlankString { 
      ensure(raw.isNotBlank())
      return NotBlankString(raw)
    }
  }
}

We can then easily create values of NotBlankString from a String, which returns us a Either with the ExactError or the NotBlankString. We can also use fromOrNull to get a nullable value, or fromOrThrow to throw an ExactException.

note: Make sure to define your constructor as private to prevent creating invalid values.

fun example() {
  println(NotBlankString.from("Hello"))
  println(NotBlankString.from(""))
}

The output of the above program is:

Either.Right(NotBlankString(value=Hello))
Either.Left(ExactError(message=Failed condition.))

You can also define Exact by using Kotlin delegation.

@JvmInline
value class NotBlankString private constructor(val value: String) {
   companion object : Exact<String, NotBlankString> by Exact({
     ensure(it.isNotBlank())
     NotBlankString(it)
   })
}

You can define a second type NotBlankTrimmedString that is a NotBlankString that is also trimmed. ensureExact allows us to compose Exact instances and easily reuse the NotBlankString type.

@JvmInline
value class NotBlankTrimmedString private constructor(val value: String) { 
  companion object : Exact<String, NotBlankTrimmedString> { 
    override fun Raise<ExactError>.spec(raw: String): NotBlankTrimmedString { 
      ensure(raw, NotBlankString)
      return NotBlankTrimmedString(raw.trim())
    }
  }
}