Bug #21267
openrespond_to check in Class#allocate is inconsistent
Description
Class#allocate
has an additional rb_obj_respond_to(klass, rb_intern("allocate"))
check to forbid allocate being called on a class where it has been made private or undefined, even if used via ex. bind_call
.
>> Rational.allocate
(irb):1:in '<main>': undefined method 'allocate' for class Rational (NoMethodError)
>> Class.instance_method(:allocate).bind_call(Rational)
(irb):1:in 'Class#allocate': calling Rational.allocate is prohibited (TypeError)
However I don't think this provides any additional protection from users accessing an uninitialized object, as the user can redefine allocate to anything to bypass the check:
>> Class.instance_method(:allocate).bind_call(Class.new(Rational) {def self.allocate; end})
=> (0/1)
Or even override respond_to_missing?
>> Class.instance_method(:allocate).bind_call(Class.new(Rational) {def self.respond_to_missing? *; true; end})
=> (0/1)
So I think we should remove this check. For classes that we need to forbid allocation we should use rb_undef_alloc_func
.
The classes I see this used for are:
- MatchData
- Refinement
- Module
- Complex
- Rational
My main motivation is that this check makes Class#allocate
slow. There are ways we could improve that, but I don't think the check as-is is useful. If there's an alternative, more robust, check we'd like to do instead of simply removing this I'd be happy to implement it.
This makes allocate
~75% faster.
|allocate_no_params | 19.009M| 20.087M|
| | -| 1.06x|
|allocate_allocate | 20.587M| 35.882M|
| | -| 1.74x|
No data to display