Iron is a type constraint system for Scala. It allows creating type-level assertions, evaluable at compile time and/or runtime.
Summary:
Iron offers a simple way to create type-level assertions using Scala's givens and type aliases. This syntactic sugar allows the user to create more readable constraints.
Example of a constraint alias:
//This is mainly implicit functions/instances but if you prefer without star import, you can specify them.
import iron.*, constraint.*, numeric.constraint.{given, Greater}
type >[A, B] = A ==> Greater[B]
def log(x: Double > 0d): Refined[Double] = x.map(Math.log)
log(-1d) //Compile time error
Refined parameters return an Either to allow functional error handling when using runtime constraints:
def log(x: Double > 0d): Refined[Double] = x.map(Math.log)
val runtime = 1d
log(runtime) //Either[IllegalValueError[Double], Double] (Refined[Double])
More information on the wiki.
When evaluated at compile time, almost all traces of type constraint disappear. They desugar directly to a Right without unneeded assertion:
inline def log(x: Double > 0d): Refined[Double] = x.map(Math.log)
log(2d)
Desugars to:
Right(Constrained.apply(2d)).map(Math.log)
Note: Once compiled, Constrained.apply
returns the passed argument. This dummy method will be removed once
the next Dotty release.
Compile time assertions will fallback to runtime (disabled by default) only if they're not evaluable at compile time.
Iron relies heavily on Scala's inline feature instead of macros for compile time evaluation, leading to strong and consistent rules:
- Fully inline constraints with inline input are guaranteed to be evaluated at compile time
- Non-fully inline constraints or inputs will be as optimized as possible by the language through the inline feature and will be evaluated at runtime.
The fallback behaviour can be configured using the -Diron.fallback
argument to fit your needs:
- error (default): Throw an error if Iron is unable to evaluate the assertion at compile time
- warn: Warn and fallback to runtime evaluation if Iron is unable to evaluate the assertion at compile
- allow: Silently fallback to runtime evaluation if required
This behaviour can be configured individually using Constraint.RuntimeOnly[A, B]
or Constraint.CompileTimeOnly[A, B]
.
SBT
libraryDependencies += "io.github.iltotore" %% "iron" % "version"
Mill
ivy"io.github.iltotore::iron:version"
Note: Replace version
with the version of Iron
Iron modules are versioned using the schema ironMajorVersion-moduleVersion
.
Official modules:
There is two main ways to contribute to Iron:
- Opening an issue for bugs/feature requests
- Forking then opening a pull request for changes