Equality
Structural Equality by Default
Section titled “Structural Equality by Default”In v3, Equal.equals used reference equality for plain objects and arrays.
Structural comparison was only available inside a structuralRegion, which
temporarily enabled deep comparison. Outside a structural region, two distinct
objects with identical contents were not considered equal:
// v3import { Equal } from "effect"
Equal.equals({ a: 1 }, { a: 1 }) // false — reference equalityEqual.equals([1, 2], [1, 2]) // false — reference equalityIn v4, Equal.equals uses structural equality by default. Plain objects,
arrays, Maps, Sets, Dates, and RegExps are compared by value without
opting in:
// v4import { Equal } from "effect"
Equal.equals({ a: 1 }, { a: 1 }) // trueEqual.equals([1, [2, 3]], [1, [2, 3]]) // trueEqual.equals(new Map([["a", 1]]), new Map([["a", 1]])) // trueEqual.equals(new Set([1, 2]), new Set([1, 2])) // trueObjects that implement the Equal interface continue to use their custom
equality logic, same as v3.
Opting Out: byReference
Section titled “Opting Out: byReference”If you need reference equality for a specific object, v4 provides
Equal.byReference and Equal.byReferenceUnsafe:
import { Equal } from "effect"
const obj = Equal.byReference({ a: 1 })Equal.equals(obj, { a: 1 }) // false — reference equalitybyReference(obj)— creates aProxythat uses reference equality, leaving the original object unchanged.byReferenceUnsafe(obj)— marks the object itself for reference equality without creating a proxy. More performant but permanently changes how the object is compared.
NaN Equality
Section titled “NaN Equality”In v3, Equal.equals(NaN, NaN) returned false (following IEEE 754).
In v4, NaN is considered equal to NaN:
Equal.equals(NaN, NaN) // v3: false, v4: trueequivalence → asEquivalence
Section titled “equivalence → asEquivalence”The function that wraps equals as an Equivalence has been renamed:
// v3Equal.equivalence<number>()
// v4Equal.asEquivalence<number>()