Equals

stdtraits~ Equals

Source:

Trait to check whether two val­ues are equal.a

const {equals, eq, uneq, as­ser­tEquals, as­ser­tUneq} = re­quire('fer­rum');

// Im­ple­ment­ing this type
class Bar {
  con­structor(foo, bang) {
    this.foo = foo;
    this.bang = bang;
  }

  [Equals.sym](a, b) {
    re­turn b in­stanceof Bar
        && eq(a.foo, b.foo)
        && eq(a.bang, b.bang);
  }
}

// Or al­tern­at­ively
Equals.impl(Bar, (a, b) => {
  ...
});

// Test for equal­ity
eq(new Bar(42, 23), new Bar(42, 23)); // => true
eq(new Bar(42, 23), new Bar(0, 0)); // => falseAA

uneq(4, 3); // => true
uneq(4, 4); // => false

as­ser­tEquals({}, {}, 'Val­ues where dif­fer­ent!'); // OK!
as­ser­tEquals({}, {foo: 42}, 'Val­ues where dif­fer­ent!'); // As­ser­tion Er­ror!

as­ser­tUneq([], [{}], 'Val­ues where the same'); // OK!
as­ser­tUneq([], [], 'Val­ues where the same'); // As­ser­tion Er­ror!

Nor­mally this trait should not be used dir­ectly; con­sider us­ing eq() in­stead.

This trait should be used only in cases where ===/is() is too strict. Equals is for cases in which the con­tent of two vari­ables or data struc­tures is the same/​se­mantic­ally equi­val­ent.

In­ter­face

(value1: Any, value2: Any) => r: Boolean

Laws

  • Equals.in­voke(a, b) <=> Equals.in­voke(b, a)

This law seems trivial at first, but one ac­tu­ally needs to take some care to make this work: The trait re­solves to the im­ple­ment­a­tion for the first ar­gu­ment! So Equals.in­voke(a: Num­ber, b: String) and Equals.in­voke(a: String, b: Num­ber) will ac­tu­ally re­solve to two dif­fer­ent im­ple­ment­a­tions. The easi­est way to make this work is just to add a check (a, b) => type(b) === Num­ber to the im­ple­ment­a­tion for num­ber and adding an equi­val­ent check in string. If com­par­ing across types is ac­tu­ally de­sired (and might re­turn true), I sug­gest us­ing the same code for both im­ple­ment­a­tions: Con­sider the fol­low­ing con­trive ex­amples:

Equals.impl(Num­ber, (a, b) =>
  type(b) === (String || type(b) === Num­ber)
  && a.to­String() === b.to­String());
Equals.impl(String, (a, b) =>
  type(b) === (String || type(b) === Num­ber)
  && a.to­String() === b.to­String());

Spe­cial­iz­a­tion notes

Ex­tra im­ple­ment­a­tions provided for Date, Reg­Exp, URL and typed ar­rays.

Note that for sets: eq(new Set([{}]), new Set([{}])) does not hold true, since in sets keys and val­ues are the same thing and keys al­ways fol­low === se­mantics.

See: eq See: uneq See: as­ser­tEquals See: as­ser­tUneq