Skip to content

Commit 82a6d7a

Browse files
VLanvinfacebook-github-bot
authored andcommitted
Remove strict mode from documentation
Summary: Remove all mentions of modes in documentation. Update `eqwalizer:dynamic()` to `dynamic()`. Some explanations about bounded dynamic should be added later, tracking here T196497521. Reviewed By: ilya-klyuchnikov Differential Revision: D60036860 fbshipit-source-id: b02f46ea83dec23ffaf777f0b276368836356da1
1 parent e4e9b5c commit 82a6d7a

File tree

7 files changed

+27
-53
lines changed

7 files changed

+27
-53
lines changed

docs/reference.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
- ### [Syntax of types and specs in eqWAlizer](./reference/types.md)
44

5-
- ### [Gradual and strict modes](./reference/modes.md)
5+
- ### [Gradual typing](./reference/gradual.md)
66

77
- ### [Narrowing and occurrence typing](./reference/narrowing.md)
88

docs/reference/advanced.md

+2-12
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,8 @@ eqWAlizer in most settings. For example, consider the following code:
9292
apply_neg(B) -> negb(B).
9393
```
9494
Since `B` has type `boolean()`, eqWAlizer cannot decide which sub-spec of
95-
`negb` to use to decide the type of `negb(B)`. Its behaviour depends on
96-
which setting is in use:
97-
98-
- in strict mode, eqWAlizer will report an error stating it does not have
99-
enough info to branch;
100-
- in gradual mode, eqWAlizer will simply assume type `eqwalizer:dynamic()`
101-
for the result of `negb(B)`, disregarding the spec.
95+
`negb` to use to decide the type of `negb(B)`. eqWAlizer will simply assume
96+
type `eqwalizer:dynamic()` for the result of `negb(B)`, disregarding the spec.
10297

10398
Hence, to get better signal in this case, `negb` should simply be
10499
specced as `(boolean()) -> boolean()`.
@@ -151,11 +146,6 @@ or not meant for casual use. They can be enabled by setting the corresponding
151146
environment variable when calling `elp eqwalize`, e.g.,
152147
`EQWALIZER_CHECK_REDUNDANT_GUARDS=1 elp eqwalize-all`.
153148

154-
### Gradual and strict mode
155-
156-
Enable strict mode with `EQWALIZER_GRADUAL_TYPING=false`. By default, eqWAlizer
157-
uses gradual mode. See [gradual and strict typing modes](./modes.md).
158-
159149
### Occurrence typing
160150

161151
Disable occurrence typing with `EQWALIZER_EQWATER=false`. By default, eqWAlizer

docs/reference/escape.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ To make eqWAlizer adoption practical, it features several mechanisms to make
44
the type checker less strict, or to bypass it entirely.
55

66

7-
### Type `eqwalizer:dynamic()`
7+
### Type `dynamic()`
88

9-
Gradual mode and the type `eqwalizer:dynamic()` (provided in app `eqwalizer_support`
9+
The built-in type `dynamic()` as well as `eqwalizer:dynamic/1` (provided in app `eqwalizer_support`
1010
for the open source release) are a good way to make the type-checker more lenient
11-
while still providing some signal. See [gradual and strict modes](./modes.md).
11+
while still providing some signal. See [gradual typing](./gradual.md).
1212

1313

1414
### Ignoring errors for a function completely

docs/reference/generics.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ Reversed = lists:foldl(Lambda, [], [1, 2, 3])
135135
```
136136
In such a setting, eqWAlizer will not be able to use information such as the
137137
spec of `foldl` to infer the type of `Lambda`, and will perform much more
138-
optimistic type-checking. In gradual mode, it will simply assume for `Lambda`
138+
optimistic type-checking. It will simply assume for `Lambda`
139139
the type `(dynamic(), dynamic()) -> dynamic()`. Therefore, the type-checking
140140
of `foldl` will be very optimistic, and eqWAlizer will deduce for `Reversed`
141141
the type `dynamic()`, which is much less precise than `[number()]`.

docs/reference/modes.md docs/reference/gradual.md

+16-33
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
1-
# Gradual and strict typing modes
1+
# Gradual typing
22

3-
EqWAlizer features two different modes: gradual mode, and strict mode. They differ in how
4-
unannotated functions are handled, and how the builtin constant `eqwalizer:dynamic()` behaves.
5-
Strict mode offer stronger type-checking guarantees, while gradual mode favours ease-of-use
6-
and better signal-to-noise.
7-
Strict mode is kept sound, however, current development of eqWAlizer focuses on optimising for
8-
gradual mode. The current distribution of eqWAlizer uses gradual mode by default.
3+
EqWAlizer features gradual typing, a typing discipline built on type `dynamic()`,
4+
that allows smooth migration of untyped code to typed code, and precise management
5+
of the signal-to-noise ratio of type errors.
96

107

11-
### Type `eqwalizer:dynamic()`
8+
### Type `dynamic()`
129

13-
`eqwalizer:dynamic()` (later abbreviated to `dynamic()`) is a special type which,
14-
in gradual mode, "slips through the fingers" of the type-checker. It is similar to
10+
Erlang's built-in type `dynamic()` is considered by eqWAlizer as a special type which
11+
"slips through the fingers" of the type-checker. It is similar to
1512
[any in TypeScript](https://www.typescriptlang.org/docs/handbook/basic-types.html#any),
1613
[dynamic in Hack](https://docs.hhvm.com/hack/built-in-types/dynamic),
1714
[untyped in Sorbet](https://sorbet.org/docs/untyped).
18-
Formally, in gradual mode, `dynamic()` is compatible with every type (and, conversely,
15+
Formally, `dynamic()` is compatible with every type (and, conversely,
1916
every type is compatible with `dynamic()`). This
2017
means that a function that expects an argument of type `dynamic()` can be used with any
2118
value, and a result of type `dynamic()` can be used anywhere.
@@ -27,35 +24,23 @@ This value can in particular be passed to a function expecting, say, an argument
2724
`{integer(), boolean()}`, but not to a function expecting an argument of type
2825
`{integer(), boolean(), atom()}`.
2926

30-
In strict mode, eqWAlizer considers `dynamic()` to be equivalent to `term()`. This is a
31-
completely different, stricter, behaviour. In strict mode, a function that accepts arguments
32-
of type `dynamic()` is considered by eqWAlizer as accepting arguments of type `term()`. Hence,
33-
this function can be applied to values of any type, which is basically the same behaviour as in
34-
gradual mode. However, in strict mode, a value of type `dynamic()` **cannot** be used in every
35-
context. It can only be used in contexts expecting a value of type `term()`, since
36-
the only supertype of `dynamic()` in strict mode is `term()`. As an example, consider the
37-
following function:
27+
As an example, consider the following function:
3828
```Erlang
39-
-spec dyn_to_int(eqwalizer:dynamic()) -> integer().
29+
-spec dyn_to_int(dynamic()) -> integer().
4030
dyn_to_int(X) -> X.
4131
```
42-
This function is accepted by eqWAlizer in gradual mode: `X` is of type `eqwalizer:dynamic()`
43-
which, in gradual mode, is compatible with every type, in particular `integer()`. However, in
44-
strict mode, `X` is considered to be of type `term()` which is not compatible with `integer()`.
32+
This function is accepted by eqWAlizer: `X` is of type `dynamic()`
33+
which is compatible with every type, in particular `integer()`.
4534

46-
The type `eqwalizer:dynamic()` is provided in the module `eqwalizer.erl`, which should be
47-
made available during analysis. This module is present in the open-source library
48-
[eqwalizer_support](https://github.com/WhatsApp/eqwalizer/tree/main/eqwalizer_support).
4935

50-
51-
### Using `eqwalizer:dynamic()` in gradual mode
36+
### Using `dynamic()`
5237

5338
The purpose of `dynamic()` is twofold:
5439

5540
- provide signal for unspecced functions;
5641
- handle mixtures of specced and unspecced code gracefully without much noise.
5742

58-
While it is possible to manually introduce the constant `eqwalizer:dynamic()`, the dynamic
43+
While it is possible to manually introduce the constant `dynamic()`, the dynamic
5944
type is introduced automatically by eqWAlizer in gradual mode in certain cases:
6045

6146
- as parameter types and result types of unspecced functions, both when type-checking their
@@ -124,10 +109,8 @@ truly be well-typed.
124109

125110
#### Example 2: less noise for invocations of unspecced functions
126111

127-
Consider an unspecced function `unspecced/1`. When invoking it and running eqWAlizer in
128-
strict mode, it would simply report that it does not know the spec of `unspecced/1` and
129-
give up. In gradual mode, eqWAlizer instead supposes that `unspecced/1` actually has the
130-
spec `dynamic() -> dynamic()` and uses this to report some actual
112+
Consider an unspecced function `unspecced/1`. To provide some signal, eqWAlizer supposes that
113+
`unspecced/1` actually has the spec `dynamic() -> dynamic()` and uses this to report some actual
131114
type errors:
132115
```Erlang
133116
-spec call_unspecced() -> binary().

docs/reference/subtyping.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ In this case, the refined record type `#bar{a :: number()}` is a subtype of `#ba
4242

4343
### Dynamic
4444

45-
In gradual mode, the dynamic type `eqwalizer:dynamic()` is, in essence, both a subtype
45+
The dynamic type `dynamic()` is, in essence, both a subtype
4646
and a supertype of every other type. That is, a value of type `dynamic()` can be used
4747
in any context, and a function whose return type is `dynamic()` can return anything.
4848
This differs from the interpretation of `term()`, which is a supertype but not a
@@ -69,6 +69,8 @@ specifies that `get_a(M)` *can* return `err`, which is not of type `binary()` an
6969
cannot be passed to `binary_to_atom`. In this case, it is necessary to perform
7070
some kind of check (e.g., pattern-matching) to handle the `err` case separately.
7171

72+
More info can be [found here](./gradual.md).
73+
7274

7375
### Opaque types
7476

docs/reference/types.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,7 @@ must contain a mapping *for every* atomic key, or *at least one* mapping with
5959
an atomic key. Similarly, one can define heterogeneous maps such as
6060
`#{a => binary(), atom() => atom()}`, in which case it is not clear what can
6161
be stated about a map such as `#{a => ok}`. To avoid such questions, eqWAlizer
62-
interprets all such maps as the dictionary `#D{term() => term()}` in strict mode,
63-
or `#D{dynamic() => dynamic()}` in gradual mode.
62+
interprets all such maps as the dictionary `#D{dynamic() => dynamic()}`.
6463

6564

6665
### List types

0 commit comments

Comments
 (0)