From: "ufuk (Ufuk Kayserilioglu)" Date: 2022-09-15T01:03:19+00:00 Subject: [ruby-core:109897] [Ruby master Feature#12084] `Class#instance` Issue #12084 has been updated by ufuk (Ufuk Kayserilioglu). matz (Yukihiro Matsumoto) wrote in #note-6: > * `attached_object` is better, at least for singleton classes. But there's still no real-world use-case. I recently ran into a real-world use-case inside one of the gems I maintain and I would like make another case for this request. ### Use Case - Introspection To give some context, [Tapioca](https://github.com/Shopify/tapioca) is a gem to generate RBI files for gems and for other DSL generated runtime methods. Tapioca needs to rely heavily on runtime reflection and introspection to achieve what it does so that it can generate a proper RBI representation of what a gem intended to export from its implementation. One feature we recently added was a way to attribute modules in the ancestor chain of a module/class to the correct gem that the module was mixed in from. In order to do this, we need to hook into the include/extend/prepend operations to keep track of where the mixins are coming from. This part is all working fine, until we get a mixin on the singleton class of a class like: ```ruby module Foo end class Bar class << self include Foo end end ``` In this case, the mixin is happening on `#` but Tapioca needs to match that to one of the ancestors of `Bar` so that it can generate the mixin in the RBI file. In order to do that, Tapioca needs to be able to find `Bar` from `#`. ### Workarounds Our first (naive and failed) attempt to do that was to parse the `to_s` representation of the singleton class to figure out the `Bar` part. This failed, because some classes override the `inspect` method on the class. Most prominently `ActiveRecord::Base` subclasses have [an overridden `inspect` class method](https://github.com/rails/rails/blob/3d1f38fa3066b1e93c7d11d0a2d61885252706b4/activerecord/lib/active_record/core.rb#L370) that has modified output. This ends up changing the output of the `inspect` method on the singleton class, since Ruby makes an internal call to `inspect` on the attached class to get the class name. It is impossible to get the original `inspect` method called via `bind_call` tricks, since the call to the attached class `inspect` method happens inside Ruby. Reluctantly, we had to resort to the `ObjectSpace` walk solution for matching a singleton class to its attached object (which is a class in our case), which really slowed down our implementation. Relevant work on Tapioca can be found [here](https://github.com/Shopify/tapioca/pull/1012) and [here](https://github.com/Shopify/tapioca/pull/1098) ### Suggestion However uncommon, this use-case does not currently have a good workaround, other than resorting to the terrible method of walking the object space for each identification we need to perform. If this is a compelling use-case for `Class#attached_object` feature, I would love to implement it such that a call to `Class#attached_object` throws if the receiver is not a singleton class to begin with. I think that has the cleanest semantics, since callers can always check with `Module#singleton_class?` before calling `Class#attached_object`. So the proposed implementation would work like this: ```ruby # Success cases Array.singleton_class.attached_object # => Array Array.singleton_class.singleton_class.attached_object # => # "foo".singleton_class.attached_object # => "foo" # Error cases Array.attached_object # => error "foo".attached_object # => error NilClass.attached_object # => error (since `NilClass.singleton_class? #=> false`) true.singleton_class.attached_object # => error (since `true.singleton_class.singleton_class? #=> false`) ``` ---------------------------------------- Feature #12084: `Class#instance` https://bugs.ruby-lang.org/issues/12084#change-99140 * Author: sawa (Tsuyoshi Sawada) * Status: Open * Priority: Normal ---------------------------------------- For meta-programming/debugging purposes, I would like to request the inverse of `Object#singleton_class`. Namely, a method that is called on a class that is a singleton class, and returns the object it is a singleton of. Since the `Singleton` module in the standard library http://ruby-doc.org/stdlib-2.3.0/libdoc/singleton/rdoc/Singleton.html assigns the method name `instance` to such classes, I think `Class#instance` should be the name for such feature. ~~~RUBY Array.singleton_class.instance # => Array "foo".singleton_class.instance # => "foo" ~~~ When the receiver is a class but is not a singleton class, then it should raise an error. ~~~RUBY Array.instance # => error ~~~ -- https://bugs.ruby-lang.org/ Unsubscribe: