refined: simple refinement types for Scala

refined is a Scala library for refining types with type-level predicates which constrain the set of values described by the refined type. It started as a port of the refined Haskell library (which also provides an excellent motivation why this kind of library is useful).

A quick example:

importeu.timepit.refined._importeu.timepit.refined.api.Refinedimporteu.timepit.refined.auto._importeu.timepit.refined.numeric._// This refines Int with the Positive predicate and checks via an// implicit macro that the assigned value satisfies it:
scala>vali1:IntRefinedPositive=5
i1:IntRefinedPositive=5// If the value does not satisfy the predicate, we get a meaningful// compile error:
scala>vali2:IntRefinedPositive=-5
<console>:22:error: Predicatefailed: (-5>0).
vali2:IntRefinedPositive=-5
^
// There is also the explicit refineMV macro that can infer the base// type from its parameter:
scala> refineMV[Positive](5)
res0:IntRefinedPositive=5// Macros can only validate literals because their values are known at// compile-time. To validate arbitrary (runtime) values we can use the// refineV function:
scala>valx=42// suppose the value of x is not known at compile-time
scala> refineV[Positive](x)
res1:Either[String, IntRefinedPositive] =Right(42)
scala> refineV[Positive](-x)
res2:Either[String, IntRefinedPositive] =Left(Predicatefailed: (-42>0).)

refined also contains inference rules for converting between different refined types. For example, Int Refined Greater[W.`10`.T] can be safely converted to Int Refined Positive because all integers greater than ten are also positive. The type conversion of refined types is a compile-time operation that is provided by the library:

scala>vala:IntRefinedGreater[W.`5`.T] =10
a:IntRefinedGreater[Int(5)] =10// Since every value greater than 5 is also greater than 4, `a` can be// ascribed the type Int Refined Greater[W.`4`.T]:
scala>valb:IntRefinedGreater[W.`4`.T] = a
b:IntRefinedGreater[Int(4)] =10// An unsound ascription leads to a compile error:
scala>valc:IntRefinedGreater[W.`6`.T] = a
<console>:23:error: typemismatch (invalid inference):Greater[Int(5)] does not imply
Greater[Int(6)]
valc:IntRefinedGreater[W.`6`.T] = a
^

This mechanism allows to pass values of more specific types (e.g. Int Refined Greater[W.`10`.T]) to functions that take a more general type (e.g. Int Refined Positive) without manual intervention.

refined is a Typelevel project. This means we embrace pure, typeful, functional programming, and provide a safe and friendly environment for teaching, learning, and contributing as described in the Typelevel code of conduct.

Performance concerns

Using refined's macros for compile-time refinement has zero runtime overhead for reference types and only causes boxing for value types. Refer to RefineJavapSpec and InferJavapSpec for a detailed analysis of the runtime component of refinement types on the JVM.