Skip to content

Commit dcb7b3d

Browse files
committed
Add recent note
1 parent c28a5c6 commit dcb7b3d

File tree

1 file changed

+4
-22
lines changed

1 file changed

+4
-22
lines changed

_posts/2025-12-02-lazier-bdds-for-set-theoretic-types.markdown

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -277,26 +277,7 @@ The issues we outlined above for intersections are even worse for differences. L
277277
{a2, B1 and not (C2 or U2), :bottom, B1 and not (D2 or U2)} when a1 > a2
278278
```
279279

280-
As you can see, all operations shuffle the union nodes and return `:bottom`. But this time, we know how to improve it! Let's start with `a1 == a2`. If we expand the difference in the constrained part, we get:
281-
282-
```elixir
283-
(C1 and not C2 and not U2) or (U1 and not C2 and not U2)
284-
```
285-
286-
If we do the same in the dual part, we have:
287-
288-
```elixir
289-
(D1 and not D2 and not U2) or (U1 and not D2 and not U2)
290-
```
291-
292-
Unfortunately, there are no shared union terms between the constrained and dual parts, unless C2 and D2 are `:bottom`. Therefore, instead of fully rewriting the difference of equal nodes, we add the following special case:
293-
294-
```elixir
295-
{a1, C1 and not U2, U1 and not U2, D1 and not U2}
296-
when a1 == a2 and C2 == :bottom and D2 == :bottom
297-
```
298-
299-
We can apply a similar optimization when `a1 < a2`. The current formula:
280+
As you can see, all operations shuffle the union nodes and return `:bottom`. However, after analyzing each condition carefully, we can apply a similar optimization when `a1 < a2`. The current formula:
300281

301282
```elixir
302283
{a1, (C1 or U1) and not B2, :bottom, (D1 or U1) and not B2} when a1 < a2
@@ -311,13 +292,14 @@ The constrained part can be written as `(C1 and not B2) or (U1 and not B2)` and
311292
Unfortunately, we can't apply this for `a2 > a1`, as differences are asymmetric and do not distribute over unions on the right side. Therefore, the updated formula for difference is:
312293

313294
```elixir
314-
{a1, C1 and not U2, U1 and not U2, D1 and not U2} when a1 == a2 and C2 == :bottom and D2 == :bottom
315295
{a1, (C1 or U1) and not (C2 or U2), :bottom, (D1 or U1) and not (D2 or U2)} when a1 == a2
316296
{a1, C1 and not B2, U1 and not B2, D1 and not B2} when a1 < a2
317297
{a2, B1 and not (C2 or U2), :bottom, B1 and not (D2 or U2)} when a1 > a2
318298
```
319299

320-
With these new formulas, all new typing features in Elixir v1.19 perform efficiently and most projects now type check faster than in Elixir v1.18. You can derive similar properties when `a1 == a2` and `(U1 == :bottom) or (U1 == U2)`. Give it a try!
300+
With these new formulas, all new typing features in Elixir v1.19 perform efficiently and most projects now type check faster than in Elixir v1.18.
301+
302+
> Note from 2026-03-18: a previous version of this article provided special cases for `a1 == a2` but we noticed it led to a performance degradation in Elixir v1.20, therefore they have been removed from the article. The original formula can be found in Guillaume Duboc's thesis. The formulas above represent the ones found in the Elixir compiler as of the day of this note.
321303
322304
## Acknowledgements
323305

0 commit comments

Comments
 (0)