Issue #17881 has been updated by fxn (Xavier Noria).


Thanks a lot for working on this Jean.

If we add this, Zeitwerk would be using a somewhat more "normal" API. TracePoint is correct, but seems a bit off to me conceptually (also, I do not if I should revised that perception, maybe should I?)

However, the comments by Eregon are key. The JIT is WIP and it is going to be revised, there are JITs that work with TP just fine, current Ruby has no issue with a TP on the :class event, etc. It would be a patch in light of proposing an API that makes sense and would have at least this use case, and would make Zeitwerk a tad less hacky (again, modulus technically it is correct).

There's also something that makes me think. The constants API, in general, does not distinguish constants defined for real, from constants that have only an autoload configured that has not been triggered. For example, if you autoload :Foo, "file", and "file" is not evaluated, the constants API for Object tells you Foo is a constant in Object.

So, to be coherent with this, perhaps const_added should be triggered in autoload calls. But that would not help Zeitwerk, because what we need is to grab the class/module object at the top of its class/module body. And, we do not need to be called on reopenings (something the :class events does).

In 2018, I even played with the idea of decorating some low-level method in Module that allowed me to intercept new class objects being created, but that does not seem reachable from Ruby, so took the TP as a necessary evil. It is the only technique I know to support explicit namespaces.

----------------------------------------
Feature #17881: Add a Module#const_added callback
https://bugs.ruby-lang.org/issues/17881#change-92115

* Author: byroot (Jean Boussier)
* Status: Open
* Priority: Normal
----------------------------------------
### Use case

Autoloaders like `zeitwerk` need a callback when a new class or module is registered in the constant table.

Currently this is implemented with TracePoint's `:class` event. It works, but it is a bit unfortunate to have to use an API intended for debugging to implement production features. It doesn't feel "conceptually clean". 

It also [doesn't play well with MJIT](https://k0kubun.medium.com/ruby-3-jit-can-make-rails-faster-756310f235a), even though it's more of an MJIT limitation.

Additionally this usage of TracePoint cause [some incompatibilities with some debuggers like `byebug`](https://github.com/deivid-rodriguez/byebug/issues/564) (even though others don't have this issue). 

### Proposal

I believe that if Ruby was to call `Module#const_added` when a constant is registered, Zeitwerk could get rid of TracePoint.

For now I implemented it as: `const_added(const_name)` for similarity with `method_added`. But maybe it could make sense to have the signature be `const_added(const_name, const_value)`.

Also since `method_removed` exists, maybe `const_removed` would need to be added for consistency.

### Links

Patch: https://github.com/ruby/ruby/pull/4521
Zeitwerk side discussion: https://github.com/fxn/zeitwerk/issues/135

cc @k0kubun



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>