Issue #19154 has been reported by fxn (Xavier Noria).
----------------------------------------
Bug #19154: Specify require and autoload guarantees in ractors
https://bugs.ruby-lang.org/issues/19154
* Author: fxn (Xavier Noria)
* Status: Open
* Priority: Normal
* ruby -v: ruby 3.2.0preview3 (2022-11-27) [x86_64-darwin22]
* Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
Given a file `c.rb`:
```ruby
class C
end
```
the following script:
```ruby
r1 = Ractor.new do
require './c.rb'
end
r2 = Ractor.new do
require './c.rb'
end
r1.take
r2.take
```
raises:
```
% ruby -v foo.rb
ruby 3.2.0preview3 (2022-11-27) [x86_64-darwin22]
foo.rb:1: warning: Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues.
#<Thread:0x000000010fee2928 run> terminated with exception (report_on_exception is true):
#<Thread:0x00000001102acfe0 run> terminated with exception (report_on_exception is true):
<internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:164:in `ensure in require': can not access non-shareable objects in constant Kernel::RUBYGEMS_ACTIVATION_MONITOR by non-main ractor. (Ractor::IsolationError)
from <internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:167:in `require'
from foo.rb:6:in `block in <main>'
<internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:37:in `require'<internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:164:in `ensure in require': : can not access non-shareable objects in constant Kernel::RUBYGEMS_ACTIVATION_MONITOR by non-main ractor. (Ractor::IsolationError)
from <internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:167:in `require'
can not access non-shareable objects in constant Kernel::RUBYGEMS_ACTIVATION_MONITOR by non-main ractor. (Ractor::IsolationError) from foo.rb:2:in `block in <main>'
<internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:37:in `require': can not access non-shareable objects in constant Kernel::RUBYGEMS_ACTIVATION_MONITOR by non-main ractor. (Ractor::IsolationError)
from foo.rb:2:in `block in <main>'
from foo.rb:6:in `block in <main>'
<internal:ractor>:698:in `take': thrown by remote Ractor. (Ractor::RemoteError)
from foo.rb:9:in `<main>'
<internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:164:in `ensure in require': can not access non-shareable objects in constant Kernel::RUBYGEMS_ACTIVATION_MONITOR by non-main ractor. (Ractor::IsolationError)
from <internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:167:in `require'
from foo.rb:2:in `block in <main>'
<internal:/Users/fxn/.rbenv/versions/3.2.0-preview3/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:37:in `require': can not access non-shareable objects in constant Kernel::RUBYGEMS_ACTIVATION_MONITOR by non-main ractor. (Ractor::IsolationError)
from foo.rb:2:in `block in <main>'
```
Would it be possible to have documentation about their interaction?
This is important also to understand autoloading within ractors, since constant references may trigger `require` calls.
--
https://bugs.ruby-lang.org/
Issue #19288 has been reported by maciej.mensfeld (Maciej Mensfeld).
----------------------------------------
Bug #19288: Ractor JSON parsing significantly slower than linear parsing
https://bugs.ruby-lang.org/issues/19288
* Author: maciej.mensfeld (Maciej Mensfeld)
* Status: Open
* Priority: Normal
* ruby -v: ruby 3.2.0 (2022-12-25 revision a528908271) [x86_64-linux]
* Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN
----------------------------------------
a simple benchmark:
```ruby
require 'json'
require 'benchmark'
CONCURRENT = 5
RACTORS = true
ELEMENTS = 100_000
data = CONCURRENT.times.map do
ELEMENTS.times.map do
{
rand => rand,
rand => rand,
rand => rand,
rand => rand
}.to_json
end
end
ractors = CONCURRENT.times.map do
Ractor.new do
Ractor.receive.each { JSON.parse(_1) }
end
end
result = Benchmark.measure do
if RACTORS
CONCURRENT.times do |i|
ractors[i].send(data[i], move: false)
end
ractors.each(&:take)
else
# Linear without any threads
data.each do |piece|
piece.each { JSON.parse(_1) }
end
end
end
puts result
```
Gives following results on my 8 core machine:
```shell
# without ractors:
2.731748 0.003993 2.735741 ( 2.736349)
# with ractors
12.580452 5.089802 17.670254 ( 5.209755)
```
I would expect Ractors not to be two times slower on the CPU intense work.
--
https://bugs.ruby-lang.org/
Issue #19165 has been reported by matsuda (Akira Matsuda).
----------------------------------------
Bug #19165: Method (with no param) delegation with *, **, and ... is slow
https://bugs.ruby-lang.org/issues/19165
* Author: matsuda (Akira Matsuda)
* Status: Open
* Priority: Normal
* ruby -v: ruby 3.2.0dev (2022-12-01T08:05:41Z master 4e68b59431) +YJIT [arm64-darwin21]
* Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
I found that method delegation via Forwardable is much slower than normal method call when delegating a method that does not take parameters.
Here's a benchmark that explains what I mean.
```
require 'forwardable'
require 'pp'
require 'benchmark/ips'
class Obj
extend Forwardable
attr_accessor :other
def initialize
@other = Other.new
end
def foo_without_splat
@other.foo
end
def foo_with_splat(*)
@other.foo(*)
end
def foo_with_splat_with_name(*args)
@other.foo(*args)
end
def foo_with_splat_and_double_splat(*, **)
@other.foo(*, **)
end
def foo_with_triple_dots(...)
@other.foo(...)
end
delegate :foo => :@other
end
class Other
def foo() end
end
o = Obj.new
Benchmark.ips do |x|
x.report 'simple call' do
o.other.foo
end
x.report 'delegate without splat' do
o.foo_without_splat
end
x.report 'delegate with splat' do
o.foo_with_splat
end
x.report 'delegate with splat with name' do
o.foo_with_splat_with_name
end
x.report 'delegate with splat and double splat' do
o.foo_with_splat_and_double_splat
end
x.report 'delegate with triple dots' do
o.foo_with_triple_dots
end
x.report 'delegate via forwardable' do
o.foo
end
end
(result)
simple call 38.918M (± 0.9%) i/s - 194.884M
delegate without splat
31.933M (± 1.6%) i/s - 159.611M
delegate with splat 10.269M (± 1.6%) i/s - 51.631M
delegate with splat with name
9.888M (± 1.0%) i/s - 49.588M
delegate with splat and double splat
4.117M (± 0.9%) i/s - 20.696M
delegate with triple dots
4.169M (± 0.9%) i/s - 20.857M
delegate via forwardable
9.204M (± 2.1%) i/s - 46.295M
```
It shows that Method delegation with a splat is 3-4 times slower (regardless of whether the parameter is named or not), and delegation with a triple-dot literal is 9-10 times slower than a method delegation without an argument.
This may be because calling a method taking a splat always assigns an Array object even when no actual argument was given, and calling a method taking triple-dots assigns five Array objects and two Hash objects (this is equivalent to `*, **`).
Are there any chance reducing these object assignments and making them faster? My concern is that the Rails framework heavily uses this kind of method delegations, and presumably it causes unignorable performance overhead.
--
https://bugs.ruby-lang.org/
Issue #19261 has been reported by ko1 (Koichi Sasada).
----------------------------------------
Feature #19261: `Data#members` is not important
https://bugs.ruby-lang.org/issues/19261
* Author: ko1 (Koichi Sasada)
* Status: Open
* Priority: Normal
----------------------------------------
`Data#members` is defined but it is calculated by `self.class.members` (in other words, `#members` is a shorthand for `self.class.members`).
So it is better to remove this method.
```ruby
P = Data.define(:x, :y)
p P.new(1, 2).members #=> [:x, :y]
Group = Data.define(:name, :members)
gs = Group.new('SasadaFamily', %w(ko1 yuki))
p gs.members #=> ["ko1", "yuki"]
```
--
https://bugs.ruby-lang.org/
Issue #19191 has been reported by YO4 (Yoshinao Muramatsu).
----------------------------------------
Feature #19191: Implicit console input transcoding is more desirable
https://bugs.ruby-lang.org/issues/19191
* Author: YO4 (Yoshinao Muramatsu)
* Status: Open
* Priority: Normal
----------------------------------------
In response to Bug #18353, STDIN.internal_encoding are set and encoding is converted explcitly on Windows platform.
For example, ```[STDIN.external_encoding, STDIN.internal_encoding] # => [Encoding::Windows-31J, Encoding::UTF-8]``` if STDIN is console.
I feel that internal_encoding should be reserved for specific applications. And I think setting internal_encoding to STDIN is not foreseened.
Today I found irb breaks STDIN encoding, like
```
>ruby -rirb -e "p [$stdin.external_encoding, $stdin.internal_encoding]; IRB.setup(''); IRB::Irb.new(); p [$stdin.external_encoding, $stdin.internal_encoding]"
[#<Encoding:Windows-31J>, #<Encoding:UTF-8>]
[#<Encoding:UTF-8>, nil]
```
We know input has console code page encoding. So we always can convert encoding from console code page to io_input_encoding().
### proposal
when reading from console on Windows, input encoding is enfoced to console code page and encoding conversion is implicitly applied.
when ```set_encoding("UTF-8")``` implicitly converts console code page to UTF-8.
when ```set_encoding("CP437", "UTF-8")``` implicitly converts console code page to UTF-8. external_encoding is ignored.
binmode or binary input method is not affected by these specifications.
set_encoding, etc. will continue to work as before, and this specification will affect only when encoding conversion on read (NEED_READCONV() and make_readconv()).
--
https://bugs.ruby-lang.org/
Issue #19171 has been reported by duerst (Martin Dürst).
----------------------------------------
Feature #19171: Update Unicode data to Unicode Version 15.1
https://bugs.ruby-lang.org/issues/19171
* Author: duerst (Martin Dürst)
* Status: Open
* Priority: Normal
* Assignee: duerst (Martin Dürst)
----------------------------------------
According to http://blog.unicode.org/2022/11/the-unicode-standard-2023-release.html, Unicode plans to release Version 15.1 in September 2023. According to https://www.unicode.org/versions/beta.html, public alpha review starts Feb. 7, 2023, and ends April 4, 2023. Because alpha review may not include all the files we use, it may be difficult for us to participate.
Public beta review is planned to start May 23, 2023, ending July 4, 2023. At this point, we should be able to test things.
--
https://bugs.ruby-lang.org/
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 #19266 has been reported by gareth (Gareth Adams).
----------------------------------------
Bug #19266: URI::Generic should use URI::RFC3986_PARSER instead of URI::DEFAULT_PARSER
https://bugs.ruby-lang.org/issues/19266
* Author: gareth (Gareth Adams)
* Status: Open
* Priority: Normal
* ruby -v: ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e) [arm64-darwin21]
* Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN
----------------------------------------
In June 2014, [`uri/common` was updated][1] to introduce a RFC3986-compliant parser (`URI::RFC3986_PARSER`) as an alternative to the previous RFC2396 parser, and common methods like `URI()` were updated to use that new parser by default. The only methods in `common` not updated were [`URI.extract` and `URI.regexp`][2] which are marked as obsolete. (The old parser was kept in the `DEFAULT_PARSER` constant despite it not being the default for those methods, presumably for backward compatibility.)
However, similar [methods called on `URI::Generic`][3] were never updated to use this new parser. This means that methods like `URI::Generic.build` fail when given input that succeeds normally, and this also affects subclasses like URI::HTTP:
```
$ pry -r uri -r uri/common -r uri/generic
[1] pry(main)> URI::Generic.build(host: "underscore_host.example")
URI::InvalidComponentError: bad component(expected host component): underscore_host.example
from /Users/gareth/.asdf/installs/ruby/3.1.3/lib/ruby/3.1.0/uri/generic.rb:591:in `check_host'
[2] pry(main)> URI::HTTP.build(host: "underscore_host.example")
URI::InvalidComponentError: bad component(expected host component): underscore_host.example
from /Users/gareth/.asdf/installs/ruby/3.1.3/lib/ruby/3.1.0/uri/generic.rb:591:in `check_host'
[3] pry(main)> URI("http://underscore_host.example")
=> #<URI::HTTP http://underscore_host.example>
```
`URI::Generic.new` allows a configurable `parser` positional argument to override the class' default parser, but other factory methods like `.build` don't allow this override.
Arguably this doesn't cause problems because at least in the case above, the URI can be built with the polymorphic constructor, but having the option to build URIs from explicit named parts is useful, and leaving the outdated functionality in the `Generic` class is ambiguous. It's possible that the whole Generic class and its subclasses aren't intended to be used directly how I'm intending here, but there's nothing I could see that suggested this is the case.
I'm not aware of the entire list of differences between RFC2396 and RFC3986. The relevant difference here is that in RFC2396 an individual segment of a host ([`domainlabel`s][4]) could only be `alphanum | alphanum *( alphanum | "-" ) alphanum`, whereas RFC3986 allows [hostnames][5] to include any of `ALPHA / DIGIT / "-" / "." / "_" / "~"`. It's possible that other differences might cause issues for developers, but since this has gone over 8 years without anyone else caring about this, this is definitely not especially urgent.
[1]: https://github.com/ruby/ruby/commit/bb83f32dc3e0424d25fa4e55d8ff32b061320e41
[2]: https://github.com/ruby/ruby/blob/28a17436503c3c4cb7a35b423a894b697cd80da9/…
[3]: https://github.com/ruby/ruby/blob/28a17436503c3c4cb7a35b423a894b697cd80da9/…
[4]: https://www.rfc-editor.org/rfc/rfc2396#section-3.2.2
[5]: https://www.rfc-editor.org/rfc/rfc3986#page-13
--
https://bugs.ruby-lang.org/
Issue #19236 has been reported by byroot (Jean Boussier).
----------------------------------------
Feature #19236: Allow to create hashes with a specific capacity from Ruby
https://bugs.ruby-lang.org/issues/19236
* Author: byroot (Jean Boussier)
* Status: Open
* Priority: Normal
* Target version: 3.3
----------------------------------------
Followup on [Feature #18683] which added a C-API for this purpose.
Various protocol parsers such as Redis `RESP3` or `msgpack`, have to create hashes, and they know the size in advance.
For efficiency, it would be preferable if they could directly allocate a Hash of the necessary size, so that large hashes wouldn't cause many re-alloccations and re-hash.
`String` and `Array` both already offer similar APIs:
```ruby
String.new(capacity: XXX)
Array.new(XX) / rb_ary_new_capa(long)
```
However there's no such public API for Hashes in Ruby land.
### Proposal
I think `Hash` should have a way to create a new hash with a `capacity` parameter.
The logical signature of `Hash.new(capacity: 1000)` was deemed too incompatible in [Feature #18683].
@Eregon proposed to add `Hash.create(capacity: 1000)`.
--
https://bugs.ruby-lang.org/