Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 42 additions & 15 deletions lib/delegate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,19 +107,17 @@ def respond_to_missing?(m, include_private)
r
end

KERNEL_RESPOND_TO = ::Kernel.instance_method(:respond_to?)
private_constant :KERNEL_RESPOND_TO
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be enough to Ractor.make_shareable(KERNEL_RESPOND_TO) here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that unbound methods can't be made shareable right now. When I use make_shareable on KERNEL_RESPOND_TO, I get an error. So I think a workaround is needed for now.

Copy link
Member

@eregon eregon Dec 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah indeed:

irb(main):001:0> KERNEL_RESPOND_TO = ::Kernel.instance_method(:respond_to?)
=> #<UnboundMethod: Kernel#respond_to?(*)>
irb(main):002:0> Ractor.make_shareable KERNEL_RESPOND_TO
<internal:ractor>:816:in `make_shareable': can not make shareable object for #<UnboundMethod: Kernel#respond_to?(*)> (Ractor::Error)
        from (irb):2:in `<main>'                                              
        from /home/eregon/.rubies/ruby-3.1.2/lib/ruby/gems/3.1.0/gems/irb-1.4.1/exe/irb:11:in `<top (required)>'
        from /home/eregon/.rubies/ruby-3.1.2/bin/irb:25:in `load'             
        from /home/eregon/.rubies/ruby-3.1.2/bin/irb:25:in `<main>'     

I think it's worth reporting to https://bugs.ruby-lang.org/, could you do that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @ko1


# Handle BasicObject instances
private def target_respond_to?(target, m, include_private)
kernel_respond_to = ::Kernel.instance_method(:respond_to?)
case target
when Object
target.respond_to?(m, include_private)
else
if KERNEL_RESPOND_TO.bind_call(target, :respond_to?)
if kernel_respond_to.bind_call(target, :respond_to?)
target.respond_to?(m, include_private)
else
KERNEL_RESPOND_TO.bind_call(target, m, include_private)
kernel_respond_to.bind_call(target, m, include_private)
end
end
end
Expand Down Expand Up @@ -239,10 +237,15 @@ def freeze
super()
end

@delegator_api = self.public_instance_methods
def self.public_api # :nodoc:
@delegator_api
delegator_api = self.public_instance_methods
Ractor.make_shareable(delegator_api) if defined?(::Object::Ractor)

public_api_proc = Proc.new do
delegator_api
end
Ractor.make_shareable(public_api_proc) if defined?(::Object::Ractor)

define_singleton_method(:public_api, &public_api_proc) # :nodoc:
end

##
Expand Down Expand Up @@ -411,34 +414,58 @@ def __setobj__(obj) # :nodoc:
@delegate_dc_obj = obj
end
protected_instance_methods.each do |method|
define_method(method, Delegator.delegating_block(method))
method_block = Delegator.delegating_block(method)
Ractor.make_shareable(method_block) if defined?(Ractor)
define_method(method, &method_block)
protected method
end
public_instance_methods.each do |method|
define_method(method, Delegator.delegating_block(method))
method_block = Delegator.delegating_block(method)
Ractor.make_shareable(method_block) if defined?(Ractor)
define_method(method, &method_block)
end
end
klass.define_singleton_method :public_instance_methods do |all=true|

public_instance_methods_proc = Proc.new do |all=true|
super(all) | superclass.public_instance_methods
end
klass.define_singleton_method :protected_instance_methods do |all=true|

protected_instance_methods_proc = Proc.new do |all=true|
super(all) | superclass.protected_instance_methods
end
klass.define_singleton_method :instance_methods do |all=true|

instance_methods_proc = Proc.new do |all=true|
super(all) | superclass.instance_methods
end
klass.define_singleton_method :public_instance_method do |name|

public_instance_method_proc = Proc.new do |name|
super(name)
rescue NameError
raise unless self.public_instance_methods.include?(name)
superclass.public_instance_method(name)
end
klass.define_singleton_method :instance_method do |name|

instance_method_proc = Proc.new do |name|
super(name)
rescue NameError
raise unless self.instance_methods.include?(name)
superclass.instance_method(name)
end

if defined?(Ractor)
Ractor.make_shareable(public_instance_methods_proc)
Ractor.make_shareable(protected_instance_methods_proc)
Ractor.make_shareable(instance_methods_proc)
Ractor.make_shareable(public_instance_method_proc)
Ractor.make_shareable(instance_method_proc)
end

klass.define_singleton_method(:public_instance_methods, &public_instance_methods_proc)
klass.define_singleton_method(:protected_instance_methods, &protected_instance_methods_proc)
klass.define_singleton_method(:instance_methods, &instance_methods_proc)
klass.define_singleton_method(:public_instance_method, &public_instance_method_proc)
klass.define_singleton_method(:instance_method, &instance_method_proc)

klass.module_eval(&block) if block
return klass
end