[ruby-core:114355] [Ruby master Feature#19832] Method#destructive?, UnboundMethod#destructive?
From:
"shyouhei (Shyouhei Urabe) via ruby-core" <ruby-core@...>
Date:
2023-08-08 08:23:56 UTC
List:
ruby-core #114355
Issue #19832 has been updated by shyouhei (Shyouhei Urabe).
Well yes this property could be very useful for Ractor, JIT, and many more... except it's impossible.
Consider for instance `Array#map`. Is this method destructive? Well it _could_ be used in a destructive way. But who knows.
Also because methods can (and actually tend to) be redefined on the fly, any methods that call other methods inside (~ 99.99% of the case) cannot tell if they are destructive or not. Situation changes from time to time.
Whether a method call modifies its receiver or not ultimately does not fix until that method call actually modifies its receiver. This is how the language is designed to be.
----------------------------------------
Feature #19832: Method#destructive?, UnboundMethod#destructive?
https://bugs.ruby-lang.org/issues/19832#change-104098
* Author: sawa (Tsuyoshi Sawada)
* Status: Open
* Priority: Normal
----------------------------------------
I propose to add `destructive?` property to `Method` and `UnboundMethod` instances, which shall behave like:
```ruby
String.instance_method(:<<).destructive? # => true
String.instance_method(:+).destructive? # => false
```
One main purpose of using these classes is to inspect and make sure how a certain method behaves. Besides arity and owner, whether a method is destructive or not is one important piece of information, but currently, you cannot achieve that from `Method` or `UnboundMethod` instances.
The problem is how to implement this. It is best if this information (whether or not a method is destructive) can be extracted automatically from the method definition.
Unlike owner and arity, it may or may not be straightforward by statically analyzing the code. I think that, if a method definition defined at the ruby level does not call a destructive method anywhere within its own definition, and no dynamic method calls (`send`, `eval`, etc.) are made, then we can say that the method is non-destructive. If it does call, then the method is most likely a destructive method (it would not be destructive if the internally-called destructive method is applied to a different object. Or, we could rather call that a destructive method in the sense that it has a destructive side effect).
If doing that turns out to be difficult for some or all cases, then a practical approach for the difficult cases is to label the methods as destructive or not, manually. We can perhaps have methods `Module#destructive` and `Module#non_destructive` which take (a) symbol/string argument(s) and return the method name(s) in symbol so that they can be used like:
```ruby
class A
destructive private def some_destructive_private_method
...
end
end
```
or
```ruby
class A
def foo; ... end
def bar; ... end
def baz; ... end
non_destructive :foo, :baz
destructive :bar
end
```
or
```ruby
class A
non_destructive
def foo; ... end
def baz; ... end
destructive
def bar; ... end
end
```
When the method is not (yet) specified whether destructive or not, the return value can be `"unknown"` (or `:unknown` or `nil`) by default.
```ruby
String.instance_method(:<<).destructive? # => "unknown"
```
--
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/