Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync Belt / Js doc headers #5361

Merged
merged 69 commits into from
Jun 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
d901677
Sync doc headers for belt.ml
ryyppy Feb 23, 2022
4609b2e
Sync doc headers for belt_Array.mli
ryyppy Feb 23, 2022
abb4d81
Update belt_Float.mli doc headers
ryyppy Feb 23, 2022
1728a0c
Sync docs for belt_HashMap.mli
ryyppy Feb 23, 2022
beb4478
Sync docs for belt_HashMapInt.mli
ryyppy Jun 6, 2022
2e994cb
Sync docs for belt_HashMapString.mli
ryyppy Jun 8, 2022
dc95a16
Sync belt_HashSet.mli
ryyppy Jun 8, 2022
f835e37
Update belt_HashMapInt
ryyppy Jun 8, 2022
3bed2cc
Sync belt_HashSetString.mli
ryyppy Jun 8, 2022
3270426
Sync docs for belt_Int.mli
ryyppy Jun 8, 2022
becaf84
Sync docs for belt_List.mli
ryyppy Jun 8, 2022
646081f
Sync docs for belt_Option.mli
nkrkv Jun 10, 2022
362d3a3
Adapt docs in belt_Option.mli for parts missing in rescript-lang.org MDX
nkrkv Jun 10, 2022
8035b05
Sync docs for belt_Result.mli
nkrkv Jun 10, 2022
8397ef9
Sync docs for belt_Set.mli
whitchapman Jun 11, 2022
2c0885f
Sync docs for belt_SetInt.mli
whitchapman Jun 11, 2022
9663bdf
Sync docs for belt_SetString.mli
whitchapman Jun 11, 2022
e733a6d
Sync docs for belt_SetDict.mli
whitchapman Jun 11, 2022
da3071e
Sync docs for belt_MutableSetInt.mli
whitchapman Jun 11, 2022
b794d0d
Sync docs for belt_MutableSetString.mli
whitchapman Jun 11, 2022
9d1dd6c
Sync all the docstring texts from sort-array.mdx
jihchi Jun 12, 2022
d4efae0
Merge pull request #5424 from nkrkv/sync-belt-doc-headers-option
ryyppy Jun 13, 2022
6e3063f
Merge pull request #5427 from nkrkv/sync-belt-doc-headers-result
ryyppy Jun 13, 2022
d8515e8
Remove duplication of type definitions
jihchi Jun 13, 2022
0a97557
Sync all the docstring texts from sort-array-int.mdx
jihchi Jun 13, 2022
428d3db
Sync docs for belt_Map.mli
BartSchuurmans Jun 13, 2022
261692a
Sync docs for belt_MapInt.mli
BartSchuurmans Jun 13, 2022
7ca7043
Sync docs for belt_MapString.mli
BartSchuurmans Jun 13, 2022
ad94bc3
Sync docs for belt_MutableMap.mli
BartSchuurmans Jun 13, 2022
9a49a37
Sync docs for belt_MutableMapInt.mli
BartSchuurmans Jun 13, 2022
30dc28d
Sync docs for belt_MutableMapString.mli
BartSchuurmans Jun 13, 2022
ed2aa3a
Remove duplicate type signatures
whitchapman Jun 13, 2022
712a52f
Merge pull request #5428 from whitchapman/sync-belt-doc-headers-set
ryyppy Jun 13, 2022
45bfce0
Sync all the docstring texts from sort-array-string.mdx
jihchi Jun 13, 2022
a8cc5ff
Sync docs for belt_MutableSet.mli
whitchapman Jun 14, 2022
fbd0c82
Merge pull request #5434 from whitchapman/sync-belt-doc-headers-mutab…
ryyppy Jun 14, 2022
4178507
Merge pull request #5432 from jihchi/sync-belt-doc-headers_sortarrays…
ryyppy Jun 14, 2022
2800a93
Merge pull request #5429 from Minnozz/sync-belt-doc-headers-map
ryyppy Jun 14, 2022
ae46303
Merge pull request #5430 from jihchi/sync-belt-doc-headers_sortarray
ryyppy Jun 14, 2022
0b0538a
Merge pull request #5431 from jihchi/sync-belt-doc-headers_sortarrayint
ryyppy Jun 14, 2022
824cc08
Sync docs for belt_Range.mli
ryyppy Jun 14, 2022
62634c8
Sync docs for belt_MutableQueue.mli
ryyppy Jun 14, 2022
d43bf15
Sync docs for belt_MutableStack.mli
ryyppy Jun 14, 2022
0407303
Sync docs for Js.ml
ryyppy Jun 15, 2022
a658afc
Sync docs for js_array.ml
ryyppy Jun 16, 2022
eb294cc
Sync docs for js_array2.ml
ryyppy Jun 16, 2022
a1faf34
Sync docs for js_date.ml
ryyppy Jun 16, 2022
c214954
Sync docs for js_dict.mli
ryyppy Jun 16, 2022
cb2474d
Sync docs for js_exn.mli
ryyppy Jun 16, 2022
7e00a94
Sync docs for js_float.ml
ryyppy Jun 16, 2022
c7caccb
Sync docs for js_math.ml
nkrkv Jun 16, 2022
19d74fd
Sync docs for js_option.ml
nkrkv Jun 16, 2022
8d7850c
Merge pull request #5441 from nkrkv/sync-belt-doc-headers-js-math
ryyppy Jun 18, 2022
9a60245
Merge pull request #5442 from nkrkv/sync-belt-doc-headers-js-option
ryyppy Jun 18, 2022
cd57c84
Sync docs of js_global.ml
ryyppy Jun 18, 2022
68213d9
Sync docs for js_int.ml
ryyppy Jun 18, 2022
634b6b9
Sync docs for js_re.ml
nkrkv Jun 16, 2022
b75250e
Merge pull request #5443 from nkrkv/sync-belt-doc-headers-js-re
ryyppy Jun 19, 2022
6f5242c
Sync docs for js_json.mli
ryyppy Jun 20, 2022
38dab88
Sync docs for js_null.mli
ryyppy Jun 20, 2022
5ffa57d
Sync docs for js_null_undefined
ryyppy Jun 20, 2022
fde71c9
Sync docs for js_obj.ml
ryyppy Jun 20, 2022
e1cc0ca
Sync docs for js_promise.ml
ryyppy Jun 20, 2022
cff9c68
Sync docs for js_string.ml
ryyppy Jun 20, 2022
3b8d625
Fix misplaced doc in js_array2
ryyppy Jun 20, 2022
89cda0c
Sync docs for js_string2.ml
ryyppy Jun 21, 2022
c99f880
Update docs for js_types.mli
ryyppy Jun 21, 2022
8c88fe1
Sync docs for js_undefined.mli
ryyppy Jun 22, 2022
776cdac
Sync docs for js_vector.mli
ryyppy Jun 22, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
225 changes: 155 additions & 70 deletions jscomp/others/belt.ml
Original file line number Diff line number Diff line change
Expand Up @@ -22,97 +22,183 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)

(** A stdlib shipped with ReScript
(** The ReScript standard library.

This stdlib is still in _beta_ but we encourage you to try it out and
give us feedback.
Belt is currently mostly covering collection types. It has no string or date functions yet, although Belt.String is in the works. In the meantime, use [Js.String](js/string) for string functions and [Js.Date](js/date) for date functions.

**Motivation**
## Motivation

The motivation for creating such library is to provide ReScript users a
better end-to-end user experience, since the original OCaml stdlib was not
written with JS in mind. Below is a list of areas this lib aims to
improve:
1. Consistency in name convention: camlCase, and arguments order
2. Exception thrown functions are all suffixed with _Exn_, e.g, _getExn_
3. Better performance and smaller code size running on JS platform
Belt provides:

**Name Convention**
- The **highest quality** immutable data structures in JavaScript.
- Safety by default: A Belt function will never throw exceptions, unless it is
indicated explicitly in the function name (suffix "Exn").
- Better performance and smaller code size running on the JS platform.
- Ready for [Tree Shaking](https://webpack.js.org/guides/tree-shaking/).

For higher order functions, it will be suffixed **U** if it takes uncurried
callback.
## Usage

```
val forEach : 'a t -> ('a -> unit) -> unit
val forEachU : 'a t -> ('a -> unit [@bs]) -> unit
```
To use modules from Belt, either refer to them by their fully qualified name (`Belt.List`, `Belt.Array` etc.) or open the `Belt` module by putting

In general, uncurried version will be faster, but it may be less familiar to
people who have a background in functional programming.
```
open Belt
```

**A special encoding for collection safety**
at the top of your source files. After opening Belt this way, `Array` will refer to `Belt.Array`, `List` will refer to `Belt.List` etc. in the subsequent code.

When we create a collection library for a custom data type we need a way to provide a comparator
function. Take _Set_ for example, suppose its element type is a pair of ints,
it needs a custom _compare_ function that takes two tuples and returns their order.
The _Set_ could not just be typed as `Set.t (int * int)`, its customized _compare_ function
needs to manifest itself in the signature, otherwise, if the user creates another
customized _compare_ function, the two collection could mix which would result in runtime error.
If you want to open Belt globally for all files in your project instead, you can put

The original OCaml stdlib solved the problem using _functor_ which creates a big
closure at runtime and makes dead code elimination much harder.
We use a phantom type to solve the problem:
```json
"bsc-flags": ["-open Belt"],
```

```
module Comparable1 = Belt.Id.MakeComparable(struct
type t = int * int
let cmp (a0, a1) (b0, b1) =
match Pervasives.compare a0 b0 with
| 0 -> Pervasives.compare a1 b1
| c -> c
end)
into your `bsconfig.json`.

let mySet1 = Belt.Set.make ~id:(module Comparable1)
**Note**: this is the **only** `open` we encourage.

module Comparable2 = Belt.Id.MakeComparable(struct
type t = int * int
let cmp (a0, a1) (b0, b1) =
match Pervasives.compare a0 b0 with
| 0 -> Pervasives.compare a1 b1
| c -> c
end)
Example usage:

let mySet2 = Belt.Set.make ~id:(module Comparable2)
```
```
let someNumbers = [1, 1, 4, 2, 3, 6, 3, 4, 2]

Here, the compiler would infer `mySet1` and `mySet2` having different type, so
e.g. a `merge` operation that tries to merge these two sets will correctly fail.
let greaterThan2UniqueAndSorted =
someNumbers
->Belt.Array.keep(x => x > 2)
// convert to and from set to make values unique
->Belt.Set.Int.fromArray
->Belt.Set.Int.toArray // output is already sorted

```
val mySet1 : ((int * int), Comparable1.identity) t
val mySet2 : ((int * int), Comparable2.identity) t
```
Js.log2("result", greaterThan2UniqueAndSorted)
```

`Comparable1.identity` and `Comparable2.identity` are not the same using our encoding scheme.
## Curried vs. Uncurried Callbacks

**Collection Hierarchy**
For functions taking a callback parameter, there are usually two versions
available:

In general, we provide a generic collection module, but also create specialized
modules for commonly used data type. Take _Belt.Set_ for example, we provide:
- curried (no suffix)
- uncurried (suffixed with `U`)

```
Belt.Set
Belt.Set.Int
Belt.Set.String
```
E.g.:

The specialized modules _Belt.Set.Int_, _Belt.Set.String_ are in general more
efficient.
```
let forEach: (t<'a>, 'a => unit) => unit

Currently, both _Belt_Set_ and _Belt.Set_ are accessible to users for some
technical reasons,
we **strongly recommend** users stick to qualified import, _Belt.Set_, we may hide
the internal, _i.e_, _Belt_Set_ in the future
let forEachU: (t<'a>, (. 'a) => unit) => unit
```

The uncurried version will be faster in some cases, but for simplicity we recommend to stick with the curried version unless you need the extra performance.

The two versions can be invoked as follows:

```
["a", "b", "c"]->Belt.Array.forEach(x => Js.log(x))

["a", "b", "c"]->Belt.Array.forEachU((. x) => Js.log(x))
```

## Specialized Collections

For collections types like set or map, Belt provides both a generic module as well as specialized, more efficient implementations for string and int keys.

For example, Belt has the following set modules:

- [Belt.Set](belt/set)
- [Belt.Set.Int](belt/set-int)
- [Belt.Set.String](belt/set-string)

## Implementation Details

### Array access runtime safety

One common confusion comes from the way Belt handles array access. It differs from than the default standard library's.

```
let letters = ["a", "b", "c"]
let a = letters[0] // a == "a"
let capitalA = Js.String.toUpperCase(a)
let k = letters[10] // Raises an exception! The 10th index doesn't exist.
```

Because Belt avoids exceptions and returns `options` instead, this code behaves differently:

```
open Belt
let letters = ["a", "b", "c"]
let a = letters[0] // a == Some("a")
let captialA = Js.String.toUpperCase(a) // Type error! This code will not compile.
let k = letters[10] // k == None
```

Although we've fixed the problem where `k` raises an exception, we now have a type error when trying to capitalize `a`. There are a few things going on here:

- Reason transforms array index access to the function `Array.get`. So `letters[0]` is the same as `Array.get(letters, 0)`.
- The compiler uses whichever `Array` module is in scope. If you `open Belt`, then it uses `Belt.Array`.
- `Belt.Array.get` returns values wrapped in options, so `letters[0] == Some("a")`.

Fortunately, this is easy to fix:

```res example
open Belt
let letters = ["a", "b", "c"]
let a = letters[0]

// Use a switch statement:
let capitalA =
switch a {
| Some(a) => Some(Js.String.toUpperCase(a))
| None => None
}

let k = letters[10] // k == None
```

With that little bit of tweaking, our code now compiles successfully and is 100% free of runtime errors!

### A Special Encoding for Collection Safety

When we create a collection library for a custom data type we need a way to provide a comparator function. Take Set for example, suppose its element type is a pair of ints, it needs a custom compare function that takes two tuples and returns their order. The Set could not just be typed as Set.t (int \* int) , its customized compare function needs to manifest itself in the signature, otherwise, if the user creates another customized compare function, the two collection could mix which would result in runtime error.

We use a phantom type to solve the problem:

```
module Comparable1 =
Belt.Id.MakeComparable(
{
type t = (int, int)
let cmp = ((a0, a1), (b0, b1)) =>
switch Pervasives.compare(a0, b0) {
| 0 => Pervasives.compare(a1, b1)
| c => c
}
}
)

let mySet1 = Belt.Set.make(~id=module(Comparable1))

module Comparable2 =
Belt.Id.MakeComparable(
{
type t = (int, int)
let cmp = ((a0, a1), (b0, b1)) =>
switch Pervasives.compare(a0, b0) {
| 0 => Pervasives.compare(a1, b1)
| c => c
}
}
)

let mySet2 = Belt.Set.make(~id=module(Comparable2))
```

Here, the compiler would infer `mySet1` and `mySet2` having different type, so e.g. a `merge` operation that tries to merge these two sets will correctly fail.

```
let mySet1: t<(int, int), Comparable1.identity>
let mySet2: t<(int, int), Comparable2.identity>
```

`Comparable1.identity` and `Comparable2.identity` are not the same using our encoding scheme.

*)

Expand Down Expand Up @@ -256,7 +342,6 @@ module Result = Belt_Result

module Int = Belt_Int


(** [`Belt.Float`]()

Utilities for Float.
Expand Down
Loading