From: "ioquatix (Samuel Williams) via ruby-core" <ruby-core@...> Date: 2023-06-19T16:03:11+00:00 Subject: [ruby-core:113943] [Ruby master Feature#19521] Support for `Module#name=` and `Class#name=`. Issue #19521 has been updated by ioquatix (Samuel Williams). I am okay with restricting names to be not-constant-names, e.g. ```c if (rb_is_const_name(name)) { rb_raise(rb_eArgError, "name must not be valid constant name"); } ``` However, this will prevent `labeled_class`/`labeled_module` from using `set_temporary_name`, at least until those labels are updated to be "not a constant name" or we remove this restriction. When I did this change, ~35 tests failed. I don't know if all my use cases will be satisfied, so I can try to introduce this limitation, and if I'm satisfied, I can leave it. Otherwise, I might revisit it if such a restriction turns out to be an issue. Ultimately, I don't disagree that such things can be confusing. It's pretty obvious how such a feature can be used incorrectly, as can many features of Ruby. @ufuk your example is reasonable, but it seems like it's fairly trivial to make it confusing as the first: ```ruby old_string = String c = Class.new String = c s = c.new String = old_string p (s.upcase rescue $!) p String.new.upcase ``` I have yet to see an example of something that can be done with `set_temporary_name` that can't be done with a few lines of code that work on Ruby 3.2 today. Anyone can package the above code into a method, e.g. ```ruby def set_name(thing, name) thing.set_temporary_name(name) return thing rescue ArgumentError Object.class_eval do if current = const_get(name) remove_const(name) end const_set(name, thing) remove_const(name) ensure if current const_set(name, current) end end return thing end ``` Such an implementation is pretty trivial and bypasses any protections we can add to `set_temporary_name`. Yes, maybe we make it a little harder? But there are valid use cases which we now can't support directly. Ruby is a dynamic language, and this is a consequence of such dynamic behaviour which cannot, realistically, be completely prevented. ---------------------------------------- Feature #19521: Support for `Module#name=` and `Class#name=`. https://bugs.ruby-lang.org/issues/19521#change-103597 * Author: ioquatix (Samuel Williams) * Status: Open * Priority: Normal ---------------------------------------- See https://bugs.ruby-lang.org/issues/19450 for previous discussion and motivation. [This proposal](https://github.com/ruby/ruby/pull/7483) introduces `Module#name=` (and thus also `Class#name=`) to set the temporary class name. The name assignment has no effect if the module/class already has a permanent name. ```ruby c = Class.new do self.name = "fake name" end c = Class.new c.name = "fake name" ``` Alternatively, we could use `set_name`: ```ruby Class.new do set_name "fake_name" end ``` Setting the name of a class changes its current name, irrespective of whether it's been assigned a permanent name, or has nested modules/classes which have cached a previous name. We might like to limit the cases where a name is set, e.g. only once, only if the name is nil, or only if it's not already permanent. There is no real harm in any of those options, just inconsistency. ## Example usage The current Ruby test suite has code which shows the usefulness of this new method: ```ruby def labeled_module(name, &block) Module.new do singleton_class.class_eval { define_method(:to_s) {name} alias inspect to_s alias name to_s } class_eval(&block) if block end end module_function :labeled_module def labeled_class(name, superclass = Object, &block) Class.new(superclass) do singleton_class.class_eval { define_method(:to_s) {name} alias inspect to_s alias name to_s } class_eval(&block) if block end end module_function :labeled_class ``` The updated code would look like this: ```ruby def labeled_module(name, &block) Module.new do self.name = name class_eval(&block) if block end end def labeled_class(name, superclass = Object, &block) Class.new(superclass) do self.name = name class_eval(&block) if block end end module_function :labeled_class ``` Because the name cannot be set as part of `.new`, we have to have a separate block to set the name, before calling `class_eval`. I think the ergonomics and performance of this are slightly worse than the [counter proposal](https://bugs.ruby-lang.org/issues/19520). -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/