DevMeeting-2022-03-17
https://bugs.ruby-lang.org/issues/18591
DateTime and location
- 2022/03/17 (Thu) 13:00-17:00 JST @ Online
Next Date
- 2022/04/21 (Thu) 13:00-17:00 JST @ Online
Announce
About release timeframe
- 3.2.0 preview 1: in progress
Check security tickets
[secret]
Ordinary tickets
- I withdrew the proposal of String#bytesplice in #13110 because it may cause problems if the specified offset does not land on character boundary. But how about to raise IndexError in such cases?
# encoding: utf-8
s = "あいうえおかきくけこ"
s.bytesplice(9, 6, "xx")
p s #=> "あいうxxかきくけこ"
s.bytesplice(2, 3, "x") #=> offset 2 does not land on character boundary (IndexError)
s.bytesplice(3, 4, "x") #=> offset 7 does not land on character boundary (IndexError)
Preliminary discussion:
Discussion:
- naruse: I agree to merge it.
Conclusion:
[Feature #18576] Rename ASCII-8BIT
encoding to BINARY
(byroot)
- The patch is ready.
- I'd like to make the change for 3.2.0-preview1, so that we can get early feedback and if it's negative revert before final release.
- Matz last statement is ambiguous, does it means OK for 3.2.0-preview1?
- There's an open question on wether C API should alias
*ascii8bit*
functions too.
Preliminary discussion:
(https://github.com/ruby/ruby/pull/5571/files#diff-51920e95310ebfbc1ae31709f3b95f89afffbf4f1a6e38e8b2b406e2fb6197eaR57)
- Encoding::ASCII_8BIT was renamed to Encoding::BINARY.
https://github.com/ruby/ruby/pull/5571/files#diff-0b652aaedd3286ea21ba6f6db9f4ec65360d348647c9a2fe4ca457bbe95a9721R44
rb_encdb_declare("BINARY");
Discussion:
- ko1: I showed affected gems before meeting, but there may be also applications (not in gems)
- matz: application users may not try pre-relese version so it is hard to find out the compatibility issues.
- akr: This change doesn't introduce another advantage such as performance improvement, so it can only introduce incompatibility hurts.
Conclusion:
- matz: I'll write I'm negative on it.
[Feature #18589] Finer-grained constant invalidation (kddeisz)
- We want to trade a very small memory increase for much better constant cache invalidation.
- This will allow relying on more stable constant caches for better code specialization in JITs.
- This can also help speed up initial boot times since caches are currently invalidated each time a class is created.
- Because of APIs like Object#extend, ActiveRecord::Relation#extending, and autoload, constant caches get busted far more often than they should in production applications, and has a measurable impact on request speed.
Preliminary discussion:
module M0
CONST0 = 0
end
module M1
include M0
CONST1 = 1
end
class C
include M1
end
p C::CONST0 #=> 0
p C::CONST1 #=> 1
Conclusion:
- matz: accepted. It doesn't change the behavior so we can consider later if it has an issue.
[Feature #18615] Use -Werror=implicit-function-declaration by default for building C extensions (eregon)
- OK to do it? It seems an obvious gain and will avoid many confusing errors which happen too late and instead make them clear and early.
Preliminary discussion:
- nobu: Currently Ruby uses
RTLD_LAZY
for dlopen
, so Ruby can require an extension library even if some symbol is undefined. It aborts when the undefined symbol is actually used. If this -Werror
is enabled, a user will not be able to "gem install".
- nobu: Personally, I'd like to enable the option too
- mame: I like to enable it by default too, but also I want some workaround to disable it by external environment variable or what not
Discussion:
- shyouhei: I don't against about this proposal, but I'm afraid the compatibility.
- akr: try it on 3.2? It is 2022.
- nobu: now we replace
s/Werror/W/
for extensions for -Werror=implicit-function-declaration
to show only warning.
- mame: can we ask shopify people to try?
Conclusion:
- matz: go aheed.
- mame: if we have one or more issues, the reports are very welcome.
[Feature #18566] Merge io-wait
gem into core IO
class. (byroot)
- It's very small and any non-trivial IO code will require it.
- Merge io-wait into io.c for Ruby 3.2
- Remove io-wait as a dependency of all gems maintained by ruby-core (e.g. net-protocol).
- Publish a new io-wait version that is simply an empty gem.
- Add a
lib/io/wait.rb
stub, with eventually a verbose deprecation warning.
- It was suggested to do the same with
io-nonblock
.
Discussion:
- nobu: The reason why I created it as an extention library is because it was just possible
- shyouhei: Is there any reason to merge it to the core?
- mame: I think there is no special reason. It once caused a dependency problem: net-protocol depended on io-wait gem, but older rubies cannot handle it because they have not io-wait "gem" even though it has io-wait extension library.
- mame: Now net-protocol does NOT depend on io-wait gem, so there is no problem even if we keep the current status (keep io-wait as a default gem)
- ko1: Is there a good reason to keep it as a separate gem/ext?
- mame: IMO there is no reason.
- nobu: I regret to have introduced some methods like
nread
a little.
- akr: Do we merge all the methods of io-wait gem?
- ko1: It would be good if the number of methods being merged is smaller.
/srv/gems/ruby_volt-0.0.5/lib/ruby_volt/connection.rb: socket.read(socket.nread) if socket_open? && socket.nread > 0 # Flush data waiting to be read
/srv/gems/shopify-cli-2.14.0/vendor/deps/webrick/lib/webrick/server.rb: sp.read_nonblock([sp.nread, 8].max, buf, exception: false)
/srv/gems/smart_proxy_dynflow-0.7.0/lib/smart_proxy_dynflow/runner/command.rb: if @command_out.nread.positive?
/srv/gems/smart_proxy_dynflow-0.7.0/lib/smart_proxy_dynflow/runner/command.rb: lines = @command_out.read_nonblock(@command_out.nread)
/srv/gems/yahns-1.18.0/test/test_wbuf.rb: Timeout.timeout(10) { b.read(b.nread) until b.nread == 0 }
- ko1: We need to consider each method, instead of the whole methods
- matz:
- ok:
- unknown:
wait
ready?
== wait_readable(0)
- naming issue:
ready_to_read?
?
wait_priority
- What is this??? No one knows it
nread
- what use case is it for?
- naming issue
- akr: io/nonblock should not be merged because it is not needed for most of applications.
Conclusion:
- matz: let's discuss in different tickets to merge methods respectively (listed above as unkonwn).
[Bug #18620] Not possible to partially curry lambda or proc's call
method (jeremyevans0)
- Should we make changes to allow this to work? It complicates the internals, and the benefits seem minimal.
- If we do decide to make this change, I've prepared a patch, but the implementation is suboptimal.
Preliminary discussion:
lambda { |a, b| a + b }.method(:call).curry[1][2]
#=> expected: 3
#=> actual: wrong number of arguments (given: 1, expected 2)
- mame: I vote for no change.
Proc#curry
should work as is
- nobu: Agree.
Discussion:
- usa: I think it is by design
lambda { |a, b| a + b }.curry[1][2]
#=> 3
lambda { |a, b| a + b }.method(:call).curry[1, 2]
#=> 3
lambda { |a, b| a + b }.method(:call).curry(2)[1][2]
#=> 3
Conclusion:
- matz: No change.
- matz: it would be good to add a dedicated documentation to Proc#curry, such as "it does not work if the arity is -1"
- Last discussed at the March 2020 developer meeting, but no decision was made.
- I still think it makes sense to consider a lambda keyword argument for Proc#parameters.
Preliminary discussion:
pr = proc{|a,b=2| [a,b] }
pr.call(:a) # => [:a, 2] # :a is interpret as the first parameter
pr.parameters # => [[:opt, :a], [:opt, :b]]
pr.parameters(lambda: true) # => [[:req, :a], [:opt, :b]]
pr = proc{|a=1,b| [a,b] }
pr.call(:a) # => [1, :a] # :a is interpret as the second parameter
pr.parameters # => [[:opt, :a], [:opt, :b]]
pr.parameters(lambda: true) # => [[:opt, :a], [:req, :b]]
Discussion:
- mame: What is the use case?
- matz: Umm, okay?
- ko1: Do we need the same keyword for
Method#parameters
too?
- matz: Only
Proc#parameters
- matz: The name "lambda" is… okay
Conclusion:
- matz: accepted. Will reply
[Feature #18563] Add "graphemes" and "each_grapheme" aliases (znz)
- Some languages already use graphemes.
Preliminary discussion:
- nobu: I feel rather "grapheme" should be omitted.
- nobu: Unicode Consortium doesn't have a good brand-new word?
- ko1:
each_grapheme
makes it seem to me that it breaks down into graphemes from one graheme cluster.
- nobu: How about
graster
?
https://hexdocs.pm/elixir/1.12/String.html
Furthermore, this module also presents the concept of grapheme cluster (from now on referenced as graphemes).
https://www.php.net/manual/en/ref.intl.grapheme.php
Grapheme Functions (grapheme_extract, …)
https://jp.mathworks.com/help/textanalytics/ref/splitgraphemes.html
newStr = splitGraphemes(str)
splits the string str into graphemes. A grapheme (also known as grapheme cluster) is the Unicode term for human-perceived characters.
Discussion:
- naruse: If it is really a common word, we can use it.
- naruse: However, we should check only languages: PHP, Elixir, and Matlab.
- naruse: We should wait for other languages, don't we?
- matz: I want to wait too
- mame: We call a HashTable as "Hash" but some people critize the wording
- naruse: A string is conceptually important in Ruby, so we should use strict wording
- matz: I don't want the dishonor of wrong wording unless it is really common
Conclusion:
- matz: For now, I reject it. Will reply.
[Feature #12655] Accessing the method visibility (jeremyevans0)
- This issue discusses many things that have been discussed previously in other issues.
- I want to focus on one additional method:
Module#undefined_instance_methods
- We don't currently offer a way to see which methods are undefined in a module.
- Is this worth adding? The use case I know of is it would allow significantly simpler implementation of the looksee gem.
Preliminary discussion:
class C0
def foo = p :C0
end
class C1 < C0
undef foo
end
C1.new.bar #=> undefined method `bar' for #<C1:0x0000018f8acd15c0> (NoMethodError)
C1.new.foo #=> undefined method `foo' for #<C1:0x000002c703aa5678> (NoMethodError)
C1.undefined_instance_methods #=> [:foo]
With proposed Module#undefined_instance_methods
, we can get [:foo]
with C1.undefined_instance_methods
- ko1: I'm positive. Does it check with superclasses?
Discussion:
$ gem-codesearch 'undef_method\b' | grep '\.rb:' | wc
8674 39277 1150347
class C0
def foo = 1
def bar = 1
end
class C1 < C0
undef foo
undef bar
end
class C2 < C1
def bar = 2
end
C2.undefined_instance_methods #=> ?? []
#=> not supported
C2.undefined_instance_methods(true) #=> [:foo]
C2.undefined_instance_methods(false) #=> []
- matz: No need to check superclass? So the ability to check super classes are not needed.
Conclusion:
- matz: accepted. The
inherited_too
optional parameter is not needed.
[Bug #11063] Special singleton class should return true for singleton_class? test (jeremyevans0)
- I don't think it is worth changing the existing behavior.
- Can this be rejected?
Preliminary discussion:
nil.singleton_class #=> NilClass
nil.singleton_class.singleton_class? #=> false
true.singleton_class.singleton_class? #=> false
false.singleton_class.singleton_class? #=> false
Conclusion:
- matz: I think it is not worth to change. rejected
[Bug #18632] Struct.new wrongly treats a positional Hash as keyword arguments (eregon)
- Some C functions incorrectly treat a positional Hash as keyword arguments, e.g. Struct.new and Struct#initialize.
- This is inconsistent with the separation of positional and keyword arguments in Ruby 3
- Jeremy proposed to audit and fix them
Preliminary discussion:
h = { keyword_init: true }
Struct.new(:a, h)
# actual: it works
# expected: {:keyword_init=>true} is not a symbol (TypeError)
- nobu: I think we should fix this particular case
h = { cause: RuntimeError.new("bar") }
raise 'foo', h
#=> Now it works with the following error
# foo (RuntimeError)
# bar (RuntimeError)
#
#=> after fixed, it is handled as "raise: (Exception, String)":
# exception class/object expected (TypeError)
- mame: I'm basically positive for the change. If we find a big incompatibility, we can reconsider
Discussion:
- nobu: as long as I investigated, only the two methods (Struct.new and Kernel#raise) have the problem
Conclusion:
- matz: Please fix them. I want to give it a try. No deprecation seems to be needed to me
[Bug #18625] ruby2_keywords does not unmark the hash if the receiving method has a *rest parameter (eregon)
- This seems a clear inconsistency, and it hurts for 3 reasons:
- Can cause issues when migrating to other forms of delegation
- Makes the ruby2_keywords semantics confusing/inconsistent/more complex
- May force other Ruby implementations to replicate this bug if not fixed
- I believe we should fix it now. Fixing it later would cause issues when migrating to
(*args, **kwargs)
or (...)
.
Preliminary discussion:
# A hash that has "ruby2_keywords" flag
marked_hash = Hash.ruby2_keywords_hash({ a: 1 })
args = [marked_hash]
def single(arg)
arg
end
def splat(*args)
args.last
end
after_usage = single(*args)
p Hash.ruby2_keywords_hash?(after_usage) #=> false
after_usage = splat(*args)
p Hash.ruby2_keywords_hash?(after_usage) #=> true
def target(a:)
p a
end
# after the patch, ruby2_keywords modifier is requried to bar
def bar(*args)
target(*args)
end
ruby2_keywords def foo(*args)
bar(*args)
end
p foo(a: 42) #=> 42 in Ruby 3.1
#=> ArgumentError after the patch
Conclusion:
- matz: I think it is good to fix
- mame: It may break (a lot of?) existing programs, but hopefully easy to fix. I'll discuss
[Bug #18633] proc { |a, **kw| a }
autosplats and treats empty kwargs specially (eregon)
- Intended or bug? Should we fix it?
Preliminary discussion:
proc {|a| a }.call([1, 2]) #=> [1, 2]
proc {|a, **kw| a }.call([1, 2]) #=> 1 # should be [1, 2]
proc {|a, kw: 42| a }.call([1, 2]) #=> 1 # should be [1, 2]
proc {|a,| a }.call([1, 2]) #=> 1
proc {|a, **kw| a }.call([1, 2]) #=> 1 # should be [1, 2]
proc {|a, **kw| a }.call([1, 2], **{}) #=> [1, 2]
- FYI: Jeremy has fixed this for #16166
proc {|*a, **kw| a }.call([1, 2]) #=> old: [1, 2], new: [[1, 2]]
Conclusion:
- matz: I think it should be fixed