[ruby-core:122892] [Ruby Bug#21525] Inconsistent execution order for methods with constant blocks
From:
"joel@... (Joel Drapper) via ruby-core" <ruby-core@...>
Date:
2025-07-31 23:09:50 UTC
List:
ruby-core #122892
Issue #21525 has been reported by joel@drapper.me (Joel Drapper).
----------------------------------------
Bug #21525: Inconsistent execution order for methods with constant blocks
https://bugs.ruby-lang.org/issues/21525
* Author: joel@drapper.me (Joel Drapper)
* Status: Open
* ruby -v: ruby 3.4.5 (2025-08-01 revision 07f7832cff) +PRISM [arm64-darwin24]
* Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN
----------------------------------------
If you call a method and pass in a splat of an array with a block argument coerced from calling a method, Ruby maintains the expected execution order and the called method receives a copy of the array prior to modification.
In this example, the output is `[1, 2, 3]` since the copy is made before the `bar` method can modify it.
```ruby
ARRAY = [1, 2, 3]
def bar
ARRAY.pop
-> {}
end
def example(*args, &)
puts args
end
example(*ARRAY, &bar)
```
However, when passing a constant, the block coercion itself is able to modify the array.
```ruby
ARRAY = [1, 2, 3]
module Foo
module Bar
def self.to_proc
ARRAY.pop
-> {}
end
end
end
def example(*args, &)
puts args
end
example(*ARRAY, &Foo::Bar)
```
Another way to trigger this is to define a `const_missing` method that modifies the array.
```ruby
ARRAY = [1, 2, 3]
module Foo
def self.const_missing(name)
ARRAY.pop
-> {}
end
end
def example(*args, &)
puts args
end
example(*ARRAY, &Foo::Bar)
```
In both these cases, the output is `[1, 2]` instead of the expected `[1, 2, 3]`.
--
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/lists/ruby-core.ml.ruby-lang.org/