Releases: Iltotore/iron
v2.2.0-RC3
Introduction
This is the third release candidate for Iron v2.2.0.
Main changes (since 2.2.0-RC2)
- Make given instances for
RefinedTypeOps
compatible with Scala 3 - Documentation enhancements
Full Changelog: v2.2.0-RC2...v2.2.0-RC3
v2.2.0-RC2
Introduction
This is the second release candidate for Iron v2.2.0.
Main changes (since 2.1.0-RC1)
- Add
BigInt
/BigDecimal
support forDivide
andMultiple
- Minor fixes
Full Changelog: v2.2.0-RC1...v2.2.0-RC2
v2.2.0-RC1
Introduction
This release candidate features a way to create "new types" (like the eponym library), new constraints and minor fixes.
Main changes
- New types similar to the eponymous library in Scala 2.
BigDecimal
andBigInt
support innumeric
object.- Add
In[V1, V2, ..., VN]
constraint, alias forStrictEqual[V1] | StrictEqual[V2] | ... | StrictEqual[VN]
. - The documentation is now versioned like Scala 3 API's. You can change version in the upper left corner.
Contributors
Full Changelog: v2.1.0...v2.2.0-RC1
v2.1.0
Introduction
This release brings new ergonomic enhancements for type refinements, ScalaCheck support and some minor fixes.
Main changes
Better compile-time errors
Compile-time errors (constraint not satisfied or not evaluable) are now fancier and more helpful:
def log(x: Double :| Positive): Double = Math.log(x)
log(-1.0)
-- Constraint Error --------------------------------------------------------
Could not satisfy a constraint for type scala.Double.
Value: -1.0
Message: Should be strictly positive
----------------------------------------------------------------------------
val runtimeValue: Double = ???
log(runtimeValue)
-- Constraint Error --------------------------------------------------------
Cannot refine non full inlined input at compile-time.
To test a constraint at runtime, use the `refine` extension method.
Note: Due to a Scala limitation, already-refined types cannot be tested at compile-time (unless proven by an `Implication`).
Inlined input: runtimeValue
----------------------------------------------------------------------------
Refine further
You can now refine an already-refined constraints incrementally. This is particularly useful for fine-grained validation errors. Example from the docs:
type Username = DescribedAs[Alphanumeric, "Username should be alphanumeric"]
type Password = DescribedAs[
Alphanumeric & MinLength[5] & Exists[Letter] & Exists[Digit],
"Password should have at least 5 characters, be alphanumeric and contain at least one letter and one digit"
]
case class User(name: String :| Username, password: String :| Password)
def createUser(name: String, password: String): Either[String, User] =
for
validName <- name.refineEither[Username]
alphanumeric <- password.refineEither[Alphanumeric]
minLength <- alphanumeric.refineFurtherEither[MinLength[5]]
hasLetter <- minLength.refineFurtherEither[Exists[Letter]]
validPassword <- hasLetter.refineFurtherEither[Exists[Digit]]
yield
User(validName, validPassword)
createUser("Iltotore", "abc123") //Right(User("Iltotore", "abc123"))
createUser("Iltotore", "abc1") //Left("Should have a minimum length of 5")
createUser("Iltotore", "abcde") //Left("At least one element: (Should be a digit)")
createUser("Iltotore", "abc123 ") //Left("Should be alphanumeric")
Assuming constraints
You can now assume that a constraint holds using the .assume[C]
. It basically acts like an alias for asInstanceOf[A :| C]
.
val x: Int :| GreaterEqual[0] = util.Random.nextInt(10).assume //Compiles
Scalacheck support
Iron now provides via the iron-scalacheck
Arbitrary
instances for refined types:
import io.github.iltotore.iron.*
import io.github.iltotore.iron.constraint.numeric.*
import io.github.iltotore.iron.scalacheck.numeric.given
forAll { (x: Int :| Positive) => x > 0 } //Success
All refined types (including custom ones) are supported but some constraints have customized and more optimized generators.
Contributors
- @vbergeron: #107 and #112
Full Changelog: v2.0.0...v2.1.0
v2.1.0-RC2
Introduction
This is the second release candidate for Iron v2.1.0. It brings ergonomic enhancements and minor fixes.
Main changes (since 2.1.0-RC1)
- Add all alias for Scalacheck
- Minor fixes
Full Changelog: v2.1.0-RC1...v2.1.0-RC2
v2.1.0-RC1
Introduction
This is the first release candidate for Iron v2.1.0. It brings ergonomic enhancements and minor fixes.
Main changes
- Better compile-time errors, fancier and more helpful.
- Refine "further" methods to chain refinements and have a fine grained errors.
- Add "assume" methods used when you don't need to check the constraint.
- Scalacheck support for
Gen
/Arbitrary
instances. - New
FixedLength
constraint alias forLength[StrictEqual[V]]
- Fix
StrictEqual
not allowing comparison of different types
Contributors
- @vbergeron: #107 and #112
Full Changelog: v2.0.0...v2.1.0-RC1
v2.0.0
Introduction
This is the new major release of Iron, featuring a complete rewrite of the library on top of better foundations:
- Developer experience - Iron must be joyful to work with, making code cleaner and simpler to understand. This means simple API and no black magic.
- Safety - Iron must ensure that all refined values are actually valids, allowing developers to focus on what's important.
- Extension - Easily create your own constraints and integrations with other libraries.
- Performance - Libraries like Iron must impact runtime performance as little as possible to be seamlessly integrated in any project of any size.
Features
Developer experience
Refined types are now subtypes of their inner type: you can use them like any "normal" types.
val x: Int :| Positive = 1
x + 1 //2
Variance also works with refined types:
val x: List[Int :| Positive] = List.empty
val y: List[Int] = x
Imports have been improved. You don't need to import given anymore:
import io.github.iltotore.iron.* //Mandatory: contains implicit conversions and refinement methods
import io.github.iltotore.iron.constraint.numeric.Positive //Import a specific constraint
import io.github.iltotore.iron.constraint.numeric.* //A whole category
import io.github.iltotore.iron.constraint.all.* //Or simply everything
Iron now has several constraints out of the box for:
- Collections
- Numbers
- Characters
- Strings
There are operators like Not
. Iron also makes use of Scala 3's unions A | B
(or) and intersections A & B
(and).
Safety
In 2.0.0, refined values must be checked at compile-time. If a value does not fulfill its constraint or is not evaluable at runtime, the program will not compile:
val x: Int :| Positive = 1 //Compiles
val y: Int :| Positive = -1 //Does not compile because -1 is not positive
val z: Int :| Positive = runtimeValue //Does not compile because `runtimeValue` is (in this example) not evaluable at compile-time
To refine values at runtime, the user must use refine
, refineEither
or refineOption
extension types.
val runtimeValue: Int = 1
val anotherRuntimeValue: Int = -1
val x: Int :| Positive = runtimeValue.refine //OK
val y: Int :| Positive = anotherRuntimeValue.refine //thrown IllegalArgumentException: Should be positive
See this page for further details.
Iron also provides constraint-to-constraint implications. For example, this code compiles:
val x: Int :| Greater[10] = runtimeValue.refine
val y: Int :| Positive = x //No need to check `x` because `Greater[10]` implies `Positive`
Extension
Easily create your own constraints and implications. You can use already existing constraints combined with a type alias:
type Password =
DescribedAs[
Exists[Letter] & Exists[Digit] & Exists[Special],
"Should contain at least a letter, a digit and a special character"
]
val x: String :| Password = "abc123*"
Or building them from scratch:
final class Positive
inline given Constraint[Int, Positive] with
override inline def test(value: Int): Boolean = value > 0
override inline def message: String = "Should be positive"
val x: Int :| Positive = 5
val y: Int :| Positive = 0
You can also create your own implications:
given [V1, V2](using V1 > V2 =:= true): (Greater[V1] ==> Greater[V2]) = Implication()
val x: Int :| Greater[5] = 6
val y: Int :| Greater[0] = x
Performances
Refined types are no longer either-based and instead are an opaque type on top of their "unrefined" version. This mean they now completely disappear at compilation.
val x: Int :| Positive = 1
compiles to
val x: Int = 1
No overhead at runtime!
For runtime checking, only the condition remains:
val x: Int :| Positive = runtimeValue.refine
compiles to
val x: Int = if runtimeValue > 0 then x else throw IllegalArgumentException("Should be positive")
Note: there are functional variants like refineEither
and refineOption
.
Future releases
Iron took an entire year to rewrite and enhance! Moreover, this release breaks compatibility with Iron 1.x.
Now that Iron's codebase and foundations are much better and clearer, releases will come faster (when issues/suggestions are raised) and without breaking retrocompatibility. The semver conventions will be used:
- Major (a..) changes for API-incompatible changes
- Minor (.a.) new features, potentially binary incompatible changes (but API compatible)
- Patch (..a) bug fixes and internal improvements
Full Changelog: https://github.com/Iltotore/iron/commits/v2.0.0
Thank you to all contributors
- @gvolpe: ergonomics enhancement, suggested SJS support
- @kyri-petrou: fixed and added some constraints (like
Blank
) - @andrzejressel: first use of macros for less-trivial constraints (like
UpperCase
) - @SethTisue: corrected README english
- @nox213: fixed typo
v2.0.0-RC4
Introduction
This is the fourth release candidate for Iron 2.0.0.
The code is not subject to change until v2.0.0 if no bug or new issue appear.
Changes since v2.0.0-RC3
- Fix version number when auto-releasing artifact
- Fix logo not rendering in external websites (e.g Scaladex)
Full Changelog: v2.0.0-RC3...v2.0.0-RC4
v2.0.0-RC3
Introduction
This is the third release candidate for Iron 2.0.0.
The code is not subject to change until v2.0.0 if no bug or new issue appear.
Changes since v2.0.0-RC2
- Add ZIO support, bringing QoL methods for ZIO Prelude's
Validation
. Typeclasses likeOrd
should already be supported thanks to variance: #96 - Add Jsoniter support documentation: #102
- Update all docs examples and make sure they compile. #102
Full Changelog: v2.0.0-RC2...v2.0.0-RC3
v2.0.0-RC2
Introduction
This is the second release candidate for Iron 2.0.0.
The code is not subject to change if no bug or new issue appear. A new iron-zio
module will be created before releasing. See #88.
Changes since v2.0.0-RC1
- Enhance user experience by removing given imports: #71
- Add new commonly used constraints out of the box: #81
- Make numeric constraints more flexible: #93
TODO Before v2.0.0
- ZIO support
- Possibly some documentation changes