Skip to content

Releases: Iltotore/iron

v2.2.0-RC3

17 Jul 18:53
Compare
Choose a tag to compare
v2.2.0-RC3 Pre-release
Pre-release

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

10 Jul 06:37
bd424f6
Compare
Choose a tag to compare
v2.2.0-RC2 Pre-release
Pre-release

Introduction

This is the second release candidate for Iron v2.2.0.

Main changes (since 2.1.0-RC1)

  • Add BigInt/BigDecimal support for Divide and Multiple
  • Minor fixes

Full Changelog: v2.2.0-RC1...v2.2.0-RC2

v2.2.0-RC1

30 Jun 16:27
da8629d
Compare
Choose a tag to compare
v2.2.0-RC1 Pre-release
Pre-release

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 and BigInt support in numeric object.
  • Add In[V1, V2, ..., VN] constraint, alias for StrictEqual[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

15 Apr 06:39
9465c5b
Compare
Choose a tag to compare

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

Full Changelog: v2.0.0...v2.1.0

v2.1.0-RC2

08 Apr 14:11
9465c5b
Compare
Choose a tag to compare
v2.1.0-RC2 Pre-release
Pre-release

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

29 Mar 06:31
c96e19f
Compare
Choose a tag to compare
v2.1.0-RC1 Pre-release
Pre-release

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 for Length[StrictEqual[V]]
  • Fix StrictEqual not allowing comparison of different types

Contributors

Full Changelog: v2.0.0...v2.1.0-RC1

v2.0.0

29 Jan 15:31
Compare
Choose a tag to compare

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

Scastie

Variance also works with refined types:

val x: List[Int :| Positive] = List.empty
val y: List[Int] = x

Scastie

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

Scastie

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

Scastie

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`

Scastie

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*"

Scastie

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

Scastie

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

Scastie

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

22 Jan 09:48
Compare
Choose a tag to compare
v2.0.0-RC4 Pre-release
Pre-release

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

16 Jan 18:44
b17c95d
Compare
Choose a tag to compare
v2.0.0-RC3 Pre-release
Pre-release

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 like Ord 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

31 Dec 11:55
6b327bd
Compare
Choose a tag to compare
v2.0.0-RC2 Pre-release
Pre-release

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