You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+91-1Lines changed: 91 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -30,16 +30,105 @@ end
30
30
31
31
Even though the `+` operator works with both integers and floats, Elixir infers that `a` and `b` must be both integers, as the result of `+` is given to a function that expects an integer. The inferred type information is then used during type checking to find possible typing errors.
32
32
33
+
### Complete typing of maps keys
34
+
35
+
Maps were one of the first data-structures we implemented within the Elixir type system however, up to this point, they only supported atom keys. If they had additional keys, those keys were simply marked as `dynamic()`.
36
+
37
+
As of Elixir v1.20, we can track all possible domains as map keys. For example, the map:
38
+
39
+
```elixir
40
+
%{123=>"hello", 456.0=>:ok}
41
+
```
42
+
43
+
will have the type:
44
+
45
+
```elixir
46
+
%{integer() =>binary(), float() =>:ok}
47
+
```
48
+
49
+
It is also possible to mix domain keys, as above, with atom keys, yielding the following:
50
+
51
+
```elixir
52
+
%{integer() =>integer(), root:integer()}
53
+
```
54
+
55
+
This system is an implementation of [Polymorphic Records for Dynamic Languages, by Giuseppe Castagna and Loïc Peyrot (2024)](https://arxiv.org/abs/2404.00338).
56
+
57
+
### Typing of map operations
58
+
59
+
We have typed the majority of the functions in the `Map` module, allowing the type system to track how keys are added, updated, and removed across all possible key types.
60
+
61
+
For example, imagine we are calling the following `Map` functions with a variable `map`, which we don't know the exact shape of, and an atom key:
62
+
63
+
```elixir
64
+
Map.put(map, :key, 123)
65
+
#=> returns type %{..., key: integer()}
66
+
67
+
Map.delete(map, :key)
68
+
#=> returns type %{..., key: not_set()}
69
+
```
70
+
71
+
As you can see, when track when keys are set and also when they are removed.
72
+
73
+
Some operations, like `Map.replace/3`, only replace the key if it exists, and that is also propagated by the type system:
74
+
75
+
```elixir
76
+
Map.replace(map, :key, 123)
77
+
#=> returns type %{..., key: if_set(integer())}
78
+
```
79
+
80
+
In other words, if the key exists, it would have been replaced by an integer value. Furthermore, whenever calling a function in the `Map` module and the given key is statically proven to never exist in the map, an error is emitted.
81
+
82
+
By combining full type inference with bang operations like `Map.fetch!/2`, `Map.pop!/2`, `Map.replace!/2`, and `Map.update!/3`, Elixir is able to propagate information about the desired keys. Take this module:
83
+
84
+
```elixir
85
+
defmoduleUserdo
86
+
defname(map), do:Map.fetch!(map, :name)
87
+
end
88
+
89
+
defmoduleCallsUserdo
90
+
defcalls_namedo
91
+
User.name(%{})
92
+
end
93
+
end
94
+
```
95
+
96
+
The code above has a type violation, which is now caught by the type system:
97
+
98
+
```
99
+
warning: incompatible types given to User.name/1:
100
+
101
+
User.name(%{})
102
+
103
+
given types:
104
+
105
+
%{name: not_set()}
106
+
107
+
but expected one of:
108
+
109
+
dynamic(%{..., name: term()})
110
+
111
+
typing violation found at:
112
+
│
113
+
16 │ User.name(%{})
114
+
│ ~
115
+
│
116
+
└─ lib/calls_user.ex:7:5: CallsUser.calls_name/0
117
+
```
118
+
119
+
Once again, our goal is to propagate type information and help developers find bugs in their code, without a need to introduce type signatures (yet).
120
+
33
121
### Acknowledgements
34
122
35
-
The type system was made possible thanks to a partnership between [CNRS](https://www.cnrs.fr/) and [Remote](https://remote.com/). The development work is currently sponsored by [Fresha](https://www.fresha.com/) and [Dashbit](https://dashbit.co/).
123
+
The type system was made possible thanks to a partnership between [CNRS](https://www.cnrs.fr/) and [Remote](https://remote.com/). The development work is currently sponsored by [Fresha](https://www.fresha.com/) and [Tidewave](https://tidewave.ai/).
36
124
37
125
## v1.20.0-dev
38
126
39
127
### 1. Enhancements
40
128
41
129
#### Elixir
42
130
131
+
*[Calendar] Optimize `date_from_iso_days` by using the Neri-Schneider algorithm
43
132
*[Enum] Add `Enum.min_max` sorter
44
133
*[Integer] Add `Integer.ceil_div/2`
45
134
*[Kernel] Print intermediate results of `dbg` for pipes
@@ -52,6 +141,7 @@ The type system was made possible thanks to a partnership between [CNRS](https:/
0 commit comments