Skip to content

v2.3.0

Compare
Choose a tag to compare
@Iltotore Iltotore released this 01 Nov 08:10
· 44 commits to main since this release
0871457

Introduction

This release brings ergonomic improvements for new types and other minor additions.

Main changes

Improved new types

Refactoring

RefinedTypeOps has been refactored to be compatible with the future versions of Scala. RefinedTypeOps[T] is now RefinedTypeOps.Transparent[T] and RefinedTypeOpsImpl[A, C, T] becomes RefinedTypeOps[A, C, T]. Note that this introduces a minor compatibility break with 2.2.1.

It is recommended (but not mandatory) to use RefinedTypeOps.Transparent for transparent type aliases. Opaque types should use the more verbose RefinedTypeOps[A, C, T].

For examples, this code written with Iron 2.2.1:

opaque type Temperature = Double :| Positive
object Temperature extends RefinedTypeOpsImpl[Double, Positive, Temperature]

type Age = Double :| Positive
object Age extends RefinedTypeOps[Age]

becomes in 2.3.0:

opaque type Temperature = Double :| Positive
object Temperature extends RefinedTypeOps[Double, Positive, Temperature]

type Age = Double :| Positive
object Age extends RefinedTypeOps.Transparent[Age]

This change brings several improvements:

  • Compatibility with future versions of Scala. See scala/scala3#17984
  • Improvements on RefinedTypeOps companion's given instances. They no longer are orphans and no given import should be needed anymore.

New TypeTest given instances

The RefinedTypeOps trait (and IronType) now brings TypeTest instances. This is especially be useful in some typeclass derivation scenarios.

Runtime proxy for constraints

RuntimeConstraint[A, C] is a proxy for Constraint[A, C] usable at runtime. It significantly lowers the quantity of generated bytecode (by generating test. Unlike Constraint, a RuntimeConstraint given instance does not require the method to be inline:

//Compiles without `inline`
def refineOption[A, C](value: A)(using constraint: RuntimeConstraint[A, C]): Option[A :| C] =
  Option.when(constraint.test(value))(value.asInstanceOf[A :| C])

refineOption[Int, Positive](5) //Some(5)
refineOption[Int, Positive](-5) //None

Scastie

Note that RefinedTypeOps also makes use of it by reusing the same instance of RuntimeConstraint for companion object's methods (option, either, ...).

Ciris support

A new iron-ciris module (JVM/SJS/SN) has been added, providing typeclass instances for Ciris. For example:

import cats.syntax.all.*
import ciris.*

import io.github.iltotore.iron.*
import io.github.iltotore.iron.constraint.all.*
import io.github.iltotore.iron.cats.given
import io.github.iltotore.iron.ciris.given

type Username = String :| (Not[Blank] & MaxLength[32])
type Password = String :| (Not[Blank] & MinLength[9])

case class DatabaseConfig(username: Username, password: Secret[Password])

val databaseConfig: ConfigValue[Effect, DatabaseConfig] = (
  env("DB_USERNAME").as[Username],
  env("DB_PASSWORD").as[Password].secret
).mapN(DatabaseConfig.apply)

Both IronType and RefinedTypeOps are supported.

Circe key support

iron-circe now provides KeyEncoder/KeyDecoder instances given instances for refined types and new types.

Upgrade to Scala 3.3.1

Iron now uses Scala 3.3.1. The plan is to stick to the latest LTS version of Scala. See Scala's long-term compatibility plans.

This will require the consumers to update to Scala 3.3.1 or older to use Iron. The change should not break anything with Iron or other source code wrote in 3.2.x.

Adopters

Ledger was added to the list of adopters.

Contributors

Full Changelog: v2.2.1...v2.3.0