Project

General

Profile

Actions

Misc #21143

open

Speficy order of execution const_added vs inherited

Added by fxn (Xavier Noria) 5 days ago. Updated 5 days ago.

Status:
Open
Assignee:
-
[ruby-core:121077]

Description

The hooks const_added and inherited may need to be executed "together".

For example, consider:

module M
  def self.const_added(cname) = ...

  class C
    def self.inherited(subclass) = ...
  end

  class D < C; end
end

When D is defined, two hooks are set to run, but in which order?

Both orders make sense in a way:

  1. When inherited is called, you can observe that the subclass has a permanent name, ergo it was assigned to a constant, which must me stored in a class or module object. Therefore, the constant was added to said class/module before inherited was invoked.

  2. When const_added is called, you can const_get the symbol and observe the object is a class, hence with a superclass, hence inheritance already happened.

The patch in ruby#12759 documents and adds a test for (1). Rationale:

  1. I believe it would be nice to specify this order.

  2. Chose (1) because it is how it works today.

While the motivation for the patch was formal (to remove an ambiguity), after reflecting about this I realized users of Zeitwerk may depend on this. Nowadays, Zeitwerk uses const_added to set autoloads for child constants in namespaces. Thanks to the current order, code can be used in inherited hooks normally (it would not be ready if the order was different).

Actions #1

Updated by fxn (Xavier Noria) 5 days ago

  • Description updated (diff)
Actions #2

Updated by fxn (Xavier Noria) 5 days ago

  • Description updated (diff)

Updated by Eregon (Benoit Daloze) 5 days ago

For classes/modules not using the class/module keyword (e.g. C = Class.new(parent)), inherited must run first since the inheritance happens before the possible later assignment.

So maybe for consistency inherited should run first?
I'm unsure consistency matters too much here.

I checked and TruffleRuby currently behaves like CRuby, i.e. const_added before inherited for class/module cases.

Updated by Eregon (Benoit Daloze) 5 days ago

FWIW looking at this stuff I noticed rb_class_new() doesn't call inherited at all, but rb_define_class*() do.

Updated by fxn (Xavier Noria) 5 days ago

For classes/modules not using the class/module keyword (e.g. C = Class.new(parent)), inherited must run first since the inheritance happens before the possible later assignment.

Yes, that is why the proposed docs specifically mention the class keyword, because it is there where the ambiguity lies.

If you do two things in series, it is to be expected that their side-effects happen in series. Although when that is done in one line, the programmer needs to understand that the expression is evaluated first, and then the result assigned to the constant.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0