[#122973] [PATCH] Add Gem.default_install — Felipe Contreras via ruby-core <ruby-core@...>
We need a way to enable user installs by default so that tools like
3 messages
2025/08/17
[ruby-core:122893] [Ruby Bug#21525] Inconsistent execution order for methods with constant blocks
From:
"jeremyevans0 (Jeremy Evans) via ruby-core" <ruby-core@...>
Date:
2025-08-01 00:30:49 UTC
List:
ruby-core #122893
Issue #21525 has been updated by jeremyevans0 (Jeremy Evans).
Avoiding allocation is deliberate trade-off for these cases, and not the only case where Ruby does this. There are other corner cases where Ruby skips allocating in cases where pathological code could result in an evaluation order issue. For example:
```ruby
method(*args, **kwargs)
method(*args, &block)
method(**kwargs, &block)
```
All have similar evaluation order issues if `kwargs` isn't a hash or `block` isn't a proc, and `kwargs.to_hash` or `block.to_proc` modify `args` or `kwargs`.
Ruby deliberate skips allocating in these cases, because otherwise, all of these cases would require VM instructions that allocate, and it doesn't seem worth the performance hit just to handle pathlogical cases correctly.
Are you aware of any cases where production code could be affected by avoiding allocation for these case? Can you think of a case that is reasonable and not pathological? Do you think the benefits of require allocation in these cases outweigh the performance costs?
----------------------------------------
Bug #21525: Inconsistent execution order for methods with constant blocks
https://bugs.ruby-lang.org/issues/21525#change-114194
* 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/