Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Clear class_proxy.class_binding after its one-time use - #50

Open
maedi wants to merge 3 commits into
mainfrom
feature/ractor-safe-clear-class-binding
Open

Clear class_proxy.class_binding after its one-time use#50
maedi wants to merge 3 commits into
mainfrom
feature/ractor-safe-clear-class-binding

Conversation

@maedi

@maedi maedi commented Sep 8, 2026

Copy link
Copy Markdown
Member

What

class_proxy.class_binding captures the class body's Binding via TracePoint :end, used once to eval default/type-expression values (e.g. the bare
String in def method(var: String)) against the class's own lexical scope.
I checked every consumer across low_type, lowkey, and every gem that
depends on either -- nothing reads it after that one evaluation.

Leaving it set matters for more than tidiness: a Binding can never be
made Ractor-shareable, even frozen:

b = binding
b.freeze          # => succeeds, b.frozen? == true
Ractor.make_shareable(b)
# => Ractor::Error: can not make shareable object for #<Binding:0x...>

So a live Binding sitting on class_proxy -- which lives inside Lowkey.keys,
the file/class/method-proxy registry every LowType-included class is stored
in -- permanently blocks Ractor.make_shareable(Lowkey.keys), i.e. sharing
that whole registry across Ractors, regardless of anything else.

Fix

Set class_proxy.class_binding = nil right after the one evaluation that
needs it. Confirmed via Adapter::Loader.load (the only other thing that runs
in the same TracePoint callback) that nothing downstream touches it either.

Testing

  • New spec: spec/units/class_binding_spec.rb -- loads a real fixture class
    and asserts class_binding is nil afterward.
  • Full suite: 142 examples, 0 failures.
  • Rubocop clean (one pre-existing, unrelated Metrics/AbcSize offense on
    .included, present on main before this change).

Second of three PRs from a look at what it'd take to make Raindeer's stack
Ractor-safe (see #49 for the first). This one is necessary but not
sufficient -- Lowkey itself still needs a way to actually call
Ractor.make_shareable on its registry; that's a separate PR against the
lowkey repo.

🤖 Generated with Claude Code

maedi and others added 3 commits August 17, 2026 11:09
class_binding exists solely to eval default/type-expression values
(e.g. the bare String in def method(var: String)) against the class's
own lexical scope, once, right when the class body finishes loading --
confirmed nothing else in low_type, lowkey, or any consumer reads it
afterward.

Leaving it set matters beyond just retaining an unused Binding: a
Binding can never be made Ractor-shareable, even frozen --
Ractor.make_shareable raises Ractor::Error unconditionally for one --
so a live Binding on class_proxy permanently blocks
Ractor.make_shareable(Lowkey.keys), i.e. sharing the whole
file/class/method-proxy registry across Ractors. Clearing it here
removes that specific blocker.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant