diff --git a/data/sidebar_manual_latest.json b/data/sidebar_manual_latest.json index 43a78c47a..097c77518 100644 --- a/data/sidebar_manual_latest.json +++ b/data/sidebar_manual_latest.json @@ -31,7 +31,8 @@ "module", "import-export", "attribute", - "reserved-keywords" + "reserved-keywords", + "equality-comparison" ], "Advanced Features": [ "extensible-variant", @@ -72,4 +73,4 @@ "project-structure", "faq" ] -} +} \ No newline at end of file diff --git a/pages/docs/manual/latest/equality-comparison.mdx b/pages/docs/manual/latest/equality-comparison.mdx new file mode 100644 index 000000000..7f7031d80 --- /dev/null +++ b/pages/docs/manual/latest/equality-comparison.mdx @@ -0,0 +1,125 @@ +--- +title: "Equality and Comparison" +description: "Handling equality and comparison checks" +canonical: "/docs/manual/latest/equality-comparison" +--- + +# Equality and Comparison + +ReScript has shallow equality `===`, deep equality `==`, and comparison operators `>`, `>=`, `<`, and `<=`. + +## Shallow equality +The shallow equality operator `===` compares two values and either compiles to `===` or a `bool` if the equality is known to the compiler. +It behaves the same as the strict equality operator `===` in JavaScript. + +Using `===` will never add a runtime cost. + + + +```res +let t1 = 1 === 1 // true +let t2 = "foo" === "foo" // true +let t3 = { "foo": "bar" } === { "foo": "bar"} // false + +let doStringsMatch = (s1: string, s2: string) => s1 === s2 +``` +```js +var t1 = true; +var t2 = "foo" === "foo"; +var t3 = ({ foo: "bar" }) === ({ foo: "bar" }); + +function doStringsMatch(s1, s2) { + return s1 === s2; +} +``` + + + +## Deep equality +ReScript has the deep equality operator `==` to check deep equality of two items, which is very different from the loose equality operator like `==` in JavaScript. + +When using `==` in ReScript it will never compile to `==` in JavaScript, +it will either compile to `===`, a runtime call to an internal function that deeply compares the equality, or a `bool` if the equality is known to the compiler. + + + +```res +let t1 = 1 == 1 // true +let t2 = "foo" == "foo" // true +let t3 = { "foo": "bar" } == { "foo": "bar"} // true + +let doStringsMatch = (s1: string, s2: string) => s1 == s2 +``` +```js +import * as Caml_obj from "./stdlib/caml_obj.js"; + +var t1 = true; +var t2 = true; +var t3 = Caml_obj.equal({ foo: "bar" }, { foo: "bar" }); + +function doStringsMatch(s1, s2) { + return s1 === s2; +} +``` + + +`==` will compile to `===` (or a `bool` if the compiler can determine equality) when: + +- Comparing `string`, `char`, `int`, `float`, `bool`, or `unit` +- Comparing variants or polymorphic variants that do not have constructor values + +`==` will compile to a runtime check for deep equality when: +- Comparing `array`, `tuple`, `list`, `object`, `record`, or regular expression `Re.t` +- Comparing variants or polymorphic variants that have constructor values + +> When using `==` pay close attention to the JavaScript output if you're not sure what `==` will compile to. + +## Comparison +ReScript has operators for comparing values that compile to the the same operator in JS, a runtime check using an internal function, or a `bool` if the equality is known to the compiler, + +| operator | comparison | +| --- | ----------- | +| `>` | greater than | +| `>=` | greater than or equal | +| `<` | less than | +| `<=` | less than or equal | + +Comparison can be done on any type. + +An operator will compile to the same operator (or a `bool` if the compiler can determine equality) when: +- Comparing `int`, `float`, `string`, `char`, `bool` + +An operator will compile to a runtime check for deep equality when: +- Comparing `array`, `tuple`, `list`, `object`, `record`, or regular expression (`Re.t`) +- Comparing variants or polymorphic variants + + + +```res +let compareInt = (a: int, b: int) => a > b +let t1 = 1 > 10 +let compareArray = (a: array, b: array) => a > b +let compareOptions = (a: option, b: option) => a < b +``` +```js +import * as Caml_obj from "./stdlib/caml_obj.js"; + +function compareInt(a, b) { + return a > b; +} + +var t1 = false; + +var compareArray = Caml_obj.greaterthan; + +var compareOptions = Caml_obj.lessthan; +``` + + +## Performance of runtime equality checks +The runtime equality check ReScript uses is quite fast and should be adequate for almost all use cases. +For small objects it can be 2x times faster than alternative deep compare functions such as Lodash's [`_.isEqual`](https://lodash.com/docs/4.17.15#isEqual). + +For larger objects instead of using `==` you could manually use a faster alternative such as [fast-deep-compare](https://www.npmjs.com/package/fast-deep-equal), or write a custom comparator function. + +[This repo](https://github.com/jderochervlk/rescript-perf) has benchmarks comparing results of different libraries compared to ReScript's built in equality function. \ No newline at end of file