Skip to content

Commit 023dfd4

Browse files
authored
docs: add docs for equality and comparison (#801)
* docs: add docs for equality and comparison * fix typo * adjust working about performance
1 parent 8aa01af commit 023dfd4

File tree

2 files changed

+128
-2
lines changed

2 files changed

+128
-2
lines changed

data/sidebar_manual_latest.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
"module",
3232
"import-export",
3333
"attribute",
34-
"reserved-keywords"
34+
"reserved-keywords",
35+
"equality-comparison"
3536
],
3637
"Advanced Features": [
3738
"extensible-variant",
@@ -72,4 +73,4 @@
7273
"project-structure",
7374
"faq"
7475
]
75-
}
76+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
---
2+
title: "Equality and Comparison"
3+
description: "Handling equality and comparison checks"
4+
canonical: "/docs/manual/latest/equality-comparison"
5+
---
6+
7+
# Equality and Comparison
8+
9+
ReScript has shallow equality `===`, deep equality `==`, and comparison operators `>`, `>=`, `<`, and `<=`.
10+
11+
## Shallow equality
12+
The shallow equality operator `===` compares two values and either compiles to `===` or a `bool` if the equality is known to the compiler.
13+
It behaves the same as the strict equality operator `===` in JavaScript.
14+
15+
Using `===` will never add a runtime cost.
16+
17+
<CodeTab labels={["ReScript", "JS Output"]}>
18+
19+
```res
20+
let t1 = 1 === 1 // true
21+
let t2 = "foo" === "foo" // true
22+
let t3 = { "foo": "bar" } === { "foo": "bar"} // false
23+
24+
let doStringsMatch = (s1: string, s2: string) => s1 === s2
25+
```
26+
```js
27+
var t1 = true;
28+
var t2 = "foo" === "foo";
29+
var t3 = ({ foo: "bar" }) === ({ foo: "bar" });
30+
31+
function doStringsMatch(s1, s2) {
32+
return s1 === s2;
33+
}
34+
```
35+
36+
</CodeTab>
37+
38+
## Deep equality
39+
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.
40+
41+
When using `==` in ReScript it will never compile to `==` in JavaScript,
42+
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.
43+
44+
<CodeTab labels={["ReScript", "JS Output"]}>
45+
46+
```res
47+
let t1 = 1 == 1 // true
48+
let t2 = "foo" == "foo" // true
49+
let t3 = { "foo": "bar" } == { "foo": "bar"} // true
50+
51+
let doStringsMatch = (s1: string, s2: string) => s1 == s2
52+
```
53+
```js
54+
import * as Caml_obj from "./stdlib/caml_obj.js";
55+
56+
var t1 = true;
57+
var t2 = true;
58+
var t3 = Caml_obj.equal({ foo: "bar" }, { foo: "bar" });
59+
60+
function doStringsMatch(s1, s2) {
61+
return s1 === s2;
62+
}
63+
```
64+
</CodeTab>
65+
66+
`==` will compile to `===` (or a `bool` if the compiler can determine equality) when:
67+
68+
- Comparing `string`, `char`, `int`, `float`, `bool`, or `unit`
69+
- Comparing variants or polymorphic variants that do not have constructor values
70+
71+
`==` will compile to a runtime check for deep equality when:
72+
- Comparing `array`, `tuple`, `list`, `object`, `record`, or regular expression `Re.t`
73+
- Comparing variants or polymorphic variants that have constructor values
74+
75+
> When using `==` pay close attention to the JavaScript output if you're not sure what `==` will compile to.
76+
77+
## Comparison
78+
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,
79+
80+
| operator | comparison |
81+
| --- | ----------- |
82+
| `>` | greater than |
83+
| `>=` | greater than or equal |
84+
| `<` | less than |
85+
| `<=` | less than or equal |
86+
87+
Comparison can be done on any type.
88+
89+
An operator will compile to the same operator (or a `bool` if the compiler can determine equality) when:
90+
- Comparing `int`, `float`, `string`, `char`, `bool`
91+
92+
An operator will compile to a runtime check for deep equality when:
93+
- Comparing `array`, `tuple`, `list`, `object`, `record`, or regular expression (`Re.t`)
94+
- Comparing variants or polymorphic variants
95+
96+
<CodeTab labels={["ReScript", "JS Output"]}>
97+
98+
```res
99+
let compareInt = (a: int, b: int) => a > b
100+
let t1 = 1 > 10
101+
let compareArray = (a: array<int>, b: array<int>) => a > b
102+
let compareOptions = (a: option<float>, b: option<float>) => a < b
103+
```
104+
```js
105+
import * as Caml_obj from "./stdlib/caml_obj.js";
106+
107+
function compareInt(a, b) {
108+
return a > b;
109+
}
110+
111+
var t1 = false;
112+
113+
var compareArray = Caml_obj.greaterthan;
114+
115+
var compareOptions = Caml_obj.lessthan;
116+
```
117+
</CodeTab>
118+
119+
## Performance of runtime equality checks
120+
The runtime equality check ReScript uses is quite fast and should be adequate for almost all use cases.
121+
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).
122+
123+
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.
124+
125+
[This repo](https://github.com/jderochervlk/rescript-perf) has benchmarks comparing results of different libraries compared to ReScript's built in equality function.

0 commit comments

Comments
 (0)