Skip to content

Commit 42adb33

Browse files
authored
revision: Add update to Contrarian (#56)
1 parent f8093f9 commit 42adb33

File tree

1 file changed

+43
-0
lines changed

1 file changed

+43
-0
lines changed

pages/blog/garbage-collection-is-contrarian.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,3 +466,46 @@ benefit from contravariant lifetimes joining the two together.
466466
I expect it might bring some surprising and positive results! Either that, or I
467467
am being a total crackpot. I guess time and effort will tell. Until then, stay
468468
contrary!
469+
470+
### Update (11th of January, 2026)
471+
472+
This post received some excellent feedback / pushback on
473+
[Lobsters](https://lobste.rs/s/jydyuw/garbage_collected_handles_are_lifetime).
474+
While I do not agree with what is, perhaps, the thrust of the feedback
475+
("contravariance has nothing to do with GC or self-reference" or in other words
476+
that this entire approach is flawed), the following discussion did strongly
477+
underline a meaningful point: a fully safe representation of unrooted handles is
478+
possible as shown by [`gc-arena`](https://github.com/kyren/gc-arena) and it
479+
relies on _invariance_ which can be viewed as a combination of covariance and
480+
contravariance.
481+
482+
In terms of contravariant references, this is exactly what I get with the
483+
combination of a contravariant reference and a covariant reference of a proof
484+
value:
485+
486+
```rust
487+
let handle: Handle<'_> = ...; // Contravariant.
488+
let proof: &Proof = ...; // Covariant.
489+
handle.join(proof); // Invariant, sort of.
490+
```
491+
492+
The difference between the proven `gc-arena` solution based on invariance and my
493+
approach based on contravariant references (currently unsound/incomplete,
494+
requiring runtime checks or new Rust features to make it safe) is, I believe
495+
(again without proof), that the invariant approach gives the "least upper bound"
496+
of the solution with a lot of limitations (basically, garbage collection must
497+
happen outside of the interpreter's Rust call stack thereby forcing a stackless
498+
interpreter design, and heap data cannot be accessed mutably even in a
499+
single-threaded system; I recommend reading
500+
[this](https://kyju.org/blog/rust-safe-garbage-collection/) blog post and its
501+
[follow-up](https://kyju.org/blog/piccolo-a-stackless-lua-interpreter/) for more
502+
details) whereas the contravariant approach seems to give the "greatest lower
503+
bound" with less limitations (garbage collection can happen inside the
504+
interpreter's Rust call stack and the heap can be accessed mutably but of course
505+
only within Rust's normal aliasing rules).
506+
507+
That being said, if you want a solution that works and gives compile-time
508+
guarantees today in a fully sound way, `gc-arena` is your ticket to victory. Me?
509+
I plan on researching where this contrarian road takes me, and until I find a
510+
solution (or a dead-end wall that cannot be overcome) I will accept some runtime
511+
checks.

0 commit comments

Comments
 (0)