Issue #19231 has been reported by andrykonchin (Andrew Konchin).
----------------------------------------
Bug #19231: Integer#step and Float::INFINITY - inconsistent behaviour when called with and without a block
https://bugs.ruby-lang.org/issues/19231
* Author: andrykonchin (Andrew Konchin)
* Status: Open
* Priority: Normal
* ruby -v: 3.1.2
* Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
The initial issue was reported here https://github.com/oracle/truffleruby/issues/2797.
`0.step(Float::INFINITY, 10)` returns:
- `Integers` when called with a block
- `Floats` when called without a block
I would expect `Floats` to be returned in both cases.
Examples:
```ruby
0.step(100.0, 10).take(1).map(&:class)
# => [Float]
```
```ruby
0.step(Float::INFINITY, 10) { |offset| p offset.class; break }
# Integer
```
When `to` argument is a finite `Float` value then calling with a block returns `Floats` as well:
```ruby
0.step(100.0, 10) { |offset| p offset.class; break }
# Float
```
Wondering whether it's intentional behaviour.
I've found a related issue https://bugs.ruby-lang.org/issues/15518.
--
https://bugs.ruby-lang.org/
Issue #15554 has been updated by ko1 (Koichi Sasada).
Matz accepted to try it with `-w` (WOW!) so I'll make a patch.
----------------------------------------
Feature #15554: warn/error passing a block to a method which never use a block
https://bugs.ruby-lang.org/issues/15554#change-107218
* Author: ko1 (Koichi Sasada)
* Status: Open
* Assignee: matz (Yukihiro Matsumoto)
----------------------------------------
# Abstract
Warn or raise an ArgumentError if block is passed to a method which does not use a block.
In other words, detect "block user methods" implicitly and only "block user methods" can accept a block.
# Background
Sometimes, we pass a block to a method which ignores the passed block accidentally.
```
def my_open(name)
open(name)
end
# user hopes it works as Kernel#open which invokes a block with opened file.
my_open(name){|f| important_work_with f }
# but simply ignored...
```
To solve this issue, this feature request propose showing warnings or raising an exception on such case.
Last developer's meeting, matz proposed `&nil` which declares this method never receive a block. It is explicit, but it is tough to add this `&nil` parameter declaration to all of methods (do you want to add it to `def []=(i, e, &nil)`?).
(I agree `&nil` is valuable on some situations)
# Spec
## Define "use a block" methods
We need to define which method accepts a block and which method does not.
* (1) method has a block parameter (`&b`)
* (2) method body has `yield'
* (3) method body has `super` (ZSUPER in internal terminology) or `super(...)`
* (4) method body has singleton method (optional)
(1) and (2) is very clear. I need to explain about (3) and (4).
(3). `super` (ZSUPER) passes all parameters as arguments. So there is no surprise that which can accept `block`.
However `super(...)` also passes a block if no explicit block passing (like `super(){}` or `super(&b)`) are written.
I'm not sure we need to continue this strange specification, but to keep compatibility depending this spec, I add this rule.
(4). surprisingly, the following code invoke a block:
```
def foo
class << Object.new
yield
end
end
foo{ p :ok } #=> :ok
```
I'm also not sure we need to keep this spec, but to allow this spec, I added (4) rule.
Strictly speaking, it is not required, but we don't keep the link from singleton class ISeq to lexical parent iseq now, so I added it.
## Exceptional cases
A method called by `super` doesn`t warn warning even if this method doesn't use a block.
The rule (3) can pass blocks easily and there are many methods don`t use a block.
So my patch ignores callings by `super`.
## corner cases
There are several cases to use block without (1)-(4) rules.
### `Proc.new/proc/lambda` without a block
Now it was deprecated in r66772 (commit:9f1fb0a17febc59356d58cef5e98db61a3c03550).
Related discussion: [Bug #15539]
### `block_given?`
`block_given?` expects block, but I believe we use it with `yield` or a block parameter.
If you know the usecase without them, please tell us.
### `yield` in `eval`
We can't know `yield` (or (3), (4) rule) in an `eval` evaluating string at calling time.
```
def foo
eval('yield`)
end
foo{} # at calling time,
# we can't know the method foo can accept a block or not.
```
So I added a warning to use `yield` in `eval` like that: `test.rb:4: warning: use yield in eval will not be supported in Ruby 3.`
Workaround is use a block parameter explicitly.
```
def foo &b
eval('b.call')
end
foo{ p :ok }
```
# Implementation
Strategy is:
* [compile time] introduce `iseq::has_yield` field and check it if the iseq (or child iseq) contains `yield` (or something)
* [calling time] if block is given, check `iseq::has_yield` flag and show warning (or raise an exception)
https://gist.github.com/ko1/c9148ad0224bf5befa3cc76ed2220c0b
On this patch, now it raises an error to make it easy to detect.
It is easy to switch to show the warning.
# Evaluation and discussion
I tried to avoid ruby's tests.
https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786
Here is a patch.
There are several patterns to avoid warnings.
## tests for `block_given?`, `Proc.new` (and similar) without block
Add a dummy block parameter.
It is test-specific issue.
## empty `each`
Some tests add `each` methods do not `yield`, like: `def each; end`.
Maybe test-specific issue, and adding a dummy block parameter.
## Subtyping / duck typing
https://github.com/ruby/ruby/blob/c01a5ee85e2d6a7128cccafb143bfa694284ca87/…
This `parse` method doesn't use `yield`, but other sub-type's `parse` methods use.
## `super` with `new` method
https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786#file-tests-pat…
This method override `Class#new` method and introduce a hook with block (yield a block in this hook code).
https://github.com/ruby/ruby/blob/trunk/lib/rubygems/package/tar_writer.rb#…
In this method, call `super` and it also passing a block. However, called `initialize` doesn't use a block.
## Change robustness
This change reduce robustness for API change.
`Delegator` requires to support `__getobj__` for client classes.
Now `__getobj__` should accept block but most of `__getobj__` clients do not call given block.
https://github.com/ruby/ruby/blob/trunk/lib/delegate.rb#L80
This is because of delegator.rb's API change.
https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786#file-tests-pat…
Nobu says calling block is not required (ignoring a block is no problem) so it is not a bug for delegator client classes.
## Found issues.
```
[ 2945/20449] Rinda::TestRingServer#test_do_reply = 0.00 s
1) Error:
Rinda::TestRingServer#test_do_reply:
ArgumentError: passing block to the method "with_timeout" (defined at /home/ko1/src/ruby/trunk/test/rinda/test_rinda.rb:787) is never used.
/home/ko1/src/ruby/trunk/test/rinda/test_rinda.rb:635:in `test_do_reply'
[ 2946/20449] Rinda::TestRingServer#test_do_reply_local = 0.00 s
2) Error:
Rinda::TestRingServer#test_do_reply_local:
ArgumentError: passing block to the method "with_timeout" (defined at /home/ko1/src/ruby/trunk/test/rinda/test_rinda.rb:787) is never used.
/home/ko1/src/ruby/trunk/test/rinda/test_rinda.rb:657:in `test_do_reply_local'
[10024/20449] TestGemRequestSetGemDependencyAPI#test_platform_mswin = 0.01 s
3) Error:
TestGemRequestSetGemDependencyAPI#test_platform_mswin:
ArgumentError: passing block to the method "util_set_arch" (defined at /home/ko1/src/ruby/trunk/lib/rubygems/test_case.rb:1053) is never used.
/home/ko1/src/ruby/trunk/test/rubygems/test_gem_request_set_gem_dependency_api.rb:655:in `test_platform_mswin'
[10025/20449] TestGemRequestSetGemDependencyAPI#test_platforms = 0.01 s
4) Error:
TestGemRequestSetGemDependencyAPI#test_platforms:
ArgumentError: passing block to the method "util_set_arch" (defined at /home/ko1/src/ruby/trunk/lib/rubygems/test_case.rb:1053) is never used.
/home/ko1/src/ruby/trunk/test/rubygems/test_gem_request_set_gem_dependency_api.rb:711:in `test_platforms'
```
These 4 detection show the problem. `with_timeout` method (used in Rinda test) and `util_set_arch` method (used in Rubygems test) simply ignore the given block.
So these tests are simply ignored.
I reported them. (https://github.com/rubygems/rubygems/issues/2601)
## raise an error or show a warning?
At least, Ruby 2.7 should show warning for this kind of violation with `-w`.
How about for Ruby3?
--
https://bugs.ruby-lang.org/
Issue #20281 has been reported by mame (Yusuke Endoh).
----------------------------------------
Misc #20281: DevMeeting-2024-03-14
https://bugs.ruby-lang.org/issues/20281
* Author: mame (Yusuke Endoh)
* Status: Open
* Priority: Normal
----------------------------------------
# The next dev meeting
**Date: 2024/03/14 13:00-17:00** (JST)
Log: *TBD*
- Dev meeting *IS NOT* a decision-making place. All decisions should be done at the bug tracker.
- Dev meeting is a place we can ask Matz, nobu, nurse and other developers directly.
- Matz is a very busy person. Take this opportunity to ask him. If you can not attend, other attendees can ask instead of you (if attendees can understand your issue).
- We will write a record of the discussion in the file or to each ticket in English.
- All activities are best-effort (keep in mind that most of us are volunteer developers).
- The date, time and place of the meeting are scheduled according to when/where we can reserve Matz's time.
- *DO NOT* discuss then on this ticket, please.
# Call for agenda items
If you have a ticket that you want matz and committers to discuss, please post it into this ticket in the following format:
```
* [Ticket ref] Ticket title (your name)
* Comment (A summary of the ticket, why you put this ticket here, what point should be discussed, etc.)
```
Example:
```
* [Feature #14609] `Kernel#p` without args shows the receiver (ko1)
* I feel this feature is very useful and some people say :+1: so let discuss this feature.
```
- It is recommended to add a comment by 2024/03/11. We hold a preparatory meeting to create an agenda a few days before the dev-meeting.
- The format is strict. We'll use [this script to automatically create an markdown-style agenda](https://gist.github.com/mame/b0390509ce1491b43610b9ebb665eb86). We may ignore a comment that does not follow the format.
- Your comment is mandatory. We cannot read all discussion of the ticket in a limited time. We appreciate it if you could write a short summary and update from a previous discussion.
--
https://bugs.ruby-lang.org/
Issue #20298 has been reported by ioquatix (Samuel Williams).
----------------------------------------
Feature #20298: Introduce `Time()` type-cast / constructor.
https://bugs.ruby-lang.org/issues/20298
* Author: ioquatix (Samuel Williams)
* Status: Open
----------------------------------------
Many Ruby primitive types have constructors, e.g. `Integer(...)`, `String(...)`, `Float(...)`, etc. These usually convert from some subset of types, e.g. `Float(1) -> 1.0` will convert an Integer to a Float, and `Float("1") -> 1.0` will parse a String to a Float, and similar for other type casts/constructors.
I'd like to propose we introduce something similar for `Time` (and possibly this extends to `Date`/`DateTime` in a follow up proposal).
Suggested implementation could look something like this:
```ruby
def Time(value)
case value
when Time
value
when Integer
Time.at(value)
when String
Time.parse(value)
else
value.to_time
end
end
```
Alternatively, we might like to be a little more specific with the `else` clause/error handling.
## Background
In a project, I need to support multiple serialization formats/coders, including MessagePack, Marshal and JSON.
While Marshal and MessagePack are capable of serializing `Time` instances, `JSON` is not.
The code looks a bit like this:
```
data = fetch_job_data
job = @coder.load(data)
scheduled_at = Time(job[:scheduled_at]) # Hypothetical type-cast as outlined above
```
## Additional Observations
While some primitive data types accept themselves as arguments and construct by copy, e.g. `Array.new(Array.new)`, others do not, e.g. `Hash` and `Time`. Perhaps `Time.new(Time.new)` should behave similarly to `Array.new(Array.new)` - the outer instance is a copy of the inner.
--
https://bugs.ruby-lang.org/
Issue #20318 has been reported by bradgessler (Brad Gessler).
----------------------------------------
Feature #20318: Pattern matching `case ... in` support for triple-dot arguments
https://bugs.ruby-lang.org/issues/20318
* Author: bradgessler (Brad Gessler)
* Status: Open
----------------------------------------
# Premise
Sometimes when I'm creating a method for an API, I'd like to do pattern matching against the arguments. Today I have to do something like this:
```ruby
def foo(*args, **kwargs, &block)
case { args: args, kwargs: kwargs, block: block }
in args: [name]
puts name
in args: [first_name, last_name]
puts "Hi there #{first_name} #{last_name}"
in kwargs: {greeting:}
puts "Hello #{greeting}"
else
puts "No match: #{args}"
end
end
foo "Hi"
foo "Brad", "Gessler"
foo greeting: "Brad"
```
# Proposal
I'd like to propose the same thing, but for `...`, like this:
```ruby
def foo(...)
case ...
in args: [name]
puts name
in args: [first_name, last_name]
puts "Hi there #{first_name} #{last_name}"
in kwargs: {greeting:}
puts "Hello #{greeting}"
else
puts "No match: #{args}"
end
end
foo "Hi"
foo "Brad", "Gessler"
foo greeting: "Brad"
```
One thing I'm not sure sure about: the `args`, `kwargs`, and `block` names appear out of thin air, so ideally those could somehow be named or have a syntax that doesn't require those names.
--
https://bugs.ruby-lang.org/
Issue #20299 has been reported by MaxLap (Maxime Lapointe).
----------------------------------------
Bug #20299: Tracepoint staying enable after a disable
https://bugs.ruby-lang.org/issues/20299
* Author: MaxLap (Maxime Lapointe)
* Status: Open
* ruby -v: 3.3.0
* Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN
----------------------------------------
Problem is present in Ruby 3.2.2, 3.2.3, 3.3.0. Didn't check before.
It seems that TracePoint can sometime be "stuck" enabled after using disabled once on it.
Here is a reproduction step using a "check speed" method that just does some work and print out how long it takes. This makes it pretty clear when TracePoint was on.
Put this in a Ruby file:
```
def check_speed(msg)
t1 = Time.now.to_f
a = 0
1000000.times { |i|
a += 10
}
t2 = Time.now.to_f
puts "#{t2-t1} - #{msg}"
end
check_speed("before") # fast
trace = TracePoint.new(:line) {}
trace.enable
check_speed("after enable") # slow
trace.enable {
check_speed("in block enable") # slow
}
check_speed("after block enable") # slow
trace.disable
check_speed("after disable") # slow !!!!
trace.disable
check_speed("after disable again") # fast !!!!
# And yet, using enable multiple time doesn't have a "counter" or similar
trace.enable
trace.enable
trace.enable
check_speed("after triple enable") # slow
trace.disable
check_speed("after single disable") # fast
```
Running the file, we get this:
```
$ ruby -v
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-linux]
$ ruby local.rb
0.03473854064941406 - before
0.18935227394104004 - after enable
0.17757630348205566 - in block enable
0.18320131301879883 - after block enable
0.1818866729736328 - after disable
0.03412747383117676 - after disable again
0.18405628204345703 - after triple enable
0.033496856689453125 - after single disable
```
The first "after disable" should probably have been fast. If it's possible to have multiple nested enable/disable, then one would instead assume that after the last "single disable", things would still be slow.
Note: This code patterns comes directly for a ruby/spec: ctrl+f for "enables trace object on calling with a block if it was already enabled"
I note that in Ruby 3.2, the timing are a lot less similar. I don't know why. It would seem like TracePoint got slower in Ruby 3.3.0. Is that worth checking out / making a distincct bug for?
```
$ rvm use 3.2.3
Using /home/max/.rvm/gems/ruby-3.2.3
$ ruby local.rb
0.03246927261352539 - before
0.07910513877868652 - after enable
0.10309600830078125 - in block enable
0.12397646903991699 - after block enable
0.07114601135253906 - after disable
0.028218746185302734 - after disable again
0.12534689903259277 - after triple enable
0.02810525894165039 - after single disable
```
--
https://bugs.ruby-lang.org/
Issue #19742 has been reported by ioquatix (Samuel Williams).
----------------------------------------
Bug #19742: Introduce `Module#anonymous?`
https://bugs.ruby-lang.org/issues/19742
* Author: ioquatix (Samuel Williams)
* Status: Open
* Priority: Normal
* Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN
----------------------------------------
As a follow-on <from https://bugs.ruby-lang.org/issues/19521>, I'd like propose we introduce `Module#anonymous?`.
In some situations, like logging/formatting, serialisation/deserialization, debugging or meta-programming, we might like to know if a class is a proper constant or not.
However, this brings about some other issues which might need to be discussed.
After assigning a constant, then removing it, the internal state of Ruby still believes that the class name is permanent, even thought it's no longer true.
e.g.
```
m = Module.new
m.anonymous? # true
M = m
m.anonyomous # false
Object.send(:remove_const, :M)
M # uninitialized constant M (NameError)
M.anonymous? # false
```
Because RCLASS data structure is not updated after the constant is removed, internally the state still has a "permanent class name".
I want to use this proposal to discuss this issue and whether there is anything we should do about such behaviour (or even if it's desirable).
Proposed PR: https://github.com/ruby/ruby/pull/7966
cc @fxn
--
https://bugs.ruby-lang.org/
Issue #13557 has been updated by byroot (Jean Boussier).
@ko1 all the same use cases arrays of strings are currently used for:
E.g. raising an error with an existing backtrace:
```ruby
raise NicerError, "some message", original_error.backtrace_locations
```
Or with some frames skipped:
```ruby
raise SomeError, "some message", caller_locations(2) # skip 2 frames
```
Creating an exception with a thread backtrace:
```ruby
async_error = SomeError.new("thread timed out")
async_error.set_backtrace(other_thread.backtrace_locations)
report(async_error)
```
And probably plenty others I'm not thinking of. This is only an improved version of passing `set_backtrace(exc.backtrace)`.
----------------------------------------
Feature #13557: there's no way to pass backtrace locations as a massaged backtrace
https://bugs.ruby-lang.org/issues/13557#change-107188
* Author: sylvain.joyeux (Sylvain Joyeux)
* Status: Open
----------------------------------------
When re-raising exceptions, it is sometimes useful to "massage" the backtrace (especially in DSLs).
There is currently no way to do it using only backtrace locations. This causes the new exception to have #backtrace_locations return nil, and thus makes backtrace_locations unreliable as a whole.
Example:
~~~ruby
def test
raise ArgumentError, "", caller_locations
end
begin
test
rescue ArgumentError => e
p e.backtrace_locations
end
~~~
attempting to pass `caller_location` to `Kernel#raise` in the `test` method fails with ``bla.rb:2:in `set_backtrace': backtrace must be Array of String (TypeError)``
--
https://bugs.ruby-lang.org/
Issue #20277 has been reported by nobu (Nobuyoshi Nakada).
----------------------------------------
Bug #20277: Remove stale `String` test conditionals
https://bugs.ruby-lang.org/issues/20277
* Author: nobu (Nobuyoshi Nakada)
* Status: Open
* Priority: Normal
* Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN
----------------------------------------
I found three instance variables in `TestString`.
These select assertions:
+ `@aref_re_nth = true`
Enables `String#[regexp, index]` assertions.
+ `@aref_re_silent = false`
Assignment to unmatched region silently fails, if true.
+ `@aref_slicebang_silent = true`
Out of range argument to `String#slice!` returns `nil`, not raising an exception.
These instance variables for conditional execution have remained unchanged for nearly twenty years, since YARV merger.
It is questionable whether these behaviors can be changed anymore.
So I propose to remove these conditionals.
--
https://bugs.ruby-lang.org/