Skip to content

Constraint Creation

Iltotore edited this page Jun 24, 2021 · 5 revisions

This page details all steps to create a type constraint.

Overview

A type constraint consists of two parts:

  • Dummy: the shallow/API part of your constraint
  • Behaviour: the internal behaviour of your constraint

Basic constraint creation

Dummy

A dummy can be anything passable as a generic type. Iron's defaults use traits for dummies.

The dummy can contain information like values through singleton types.

Example:

import io.github.iltotore.numeric.Number

trait Greater[V <: Number] //A V singleton type is required

Note: Number is an alias for the union of all numerical primitives.

Behaviour

We need to attach a behaviour to our dummy. A constraint behaviour is a given instance of Constraint[A, B] where A is the input type and B the dummy.

Due to Dotty's nested inlines limitation, we need to create a class for constraints with parameters:

import io.github.iltotore.numeric.Number
import scala.compiletime.constValue

trait Greater[V <: Number]

class GreaterConstraint[A <: Number, V <: A] extends Constraint[A, Greater[V]] {
  override inline
  
  def assert(value: A): Boolean = NumberOrdering.gt(value, constValue[V])
}

Note: NumberOrdering is an instance of InlineOrdering for Number. It offers the same features as a normal Ordering but inline.

Now, we need to create a given method returning an instance of our constraint:

inline given[A <: Number, V <: A]: GreaterConstraint[A, V] = new GreaterConstraint

You can now use your constraint:

inline def log(x: Double ==> Greater[0d]): Double = Math.log(x)

Note: here, the log method is inline to reduce overhead (log(x) will desugar to Math.log(x)).

Constraint aliases

You can use Scala's type aliases to alias constraints. This can be useful for special cases or readability.

Example using the Greater constraint:

type >[A, V] = A ==> Greater[V]

Usage:

inline def log(x: Double > 0d): Double = Math.log(x)

//Desugars to
inline def log(x: Double ==> Greater[0d]): Double = Math.log(x)
Clone this wiki locally