* [ruby-core:97588] [Ruby master Feature#16739] Allow Hash#keys and Hash#values to accept a block for filtering output
@ 2020-03-24 21:00 jacobevelyn
2020-03-25 3:31 ` [ruby-core:97590] " sawadatsuyoshi
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: jacobevelyn @ 2020-03-24 21:00 UTC (permalink / raw
To: ruby-core
Issue #16739 has been reported by jacobevelyn (Jacob Evelyn).
----------------------------------------
Feature #16739: Allow Hash#keys and Hash#values to accept a block for filtering output
https://bugs.ruby-lang.org/issues/16739
* Author: jacobevelyn (Jacob Evelyn)
* Status: Open
* Priority: Normal
----------------------------------------
I often see code like the following:
``` ruby
hash.select { |_, v| v == :some_value }.keys
hash.keys.select { |k| k.nil? || k.even? }
hash.select { |k, v| valid_key?(k) && valid_value?(v) }.values
```
Each of these code snippets must allocate an intermediate data structure. I propose allowing `Hash#keys` and `Hash#values` to accept optional block parameters that *take both key and value*. For example, the above code could be rewritten as:
```ruby
hash.keys { |_, v| v == :some_value }
hash.keys { |k, _| k.nil? || k.even? }
hash.values { |k, v| valid_key?(k) && valid_value?(v) }
```
This behavior:
1. Does not break any existing code (since `Hash#keys` and `Hash#values` do not currently accept blocks).
2. Is very readable—it's obvious what it does at a glance.
3. Is more efficient than current alternatives.
4. Is more concise than current alternatives.
5. Is flexible and useful in a variety of scenarios, because the block has access to both key and value (unlike the behavior proposed in #14788).
--
https://bugs.ruby-lang.org/
^ permalink raw reply [flat|nested] 7+ messages in thread
* [ruby-core:97590] [Ruby master Feature#16739] Allow Hash#keys and Hash#values to accept a block for filtering output
2020-03-24 21:00 [ruby-core:97588] [Ruby master Feature#16739] Allow Hash#keys and Hash#values to accept a block for filtering output jacobevelyn
@ 2020-03-25 3:31 ` sawadatsuyoshi
2020-03-25 15:14 ` [ruby-core:97595] " mame
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: sawadatsuyoshi @ 2020-03-25 3:31 UTC (permalink / raw
To: ruby-core
Issue #16739 has been updated by sawa (Tsuyoshi Sawada).
All it does is saves you from typing `select`. It does not look like the proposed feature makes much difference unless such situation is frequently met. Do you have use case?
----------------------------------------
Feature #16739: Allow Hash#keys and Hash#values to accept a block for filtering output
https://bugs.ruby-lang.org/issues/16739#change-84773
* Author: jacobevelyn (Jacob Evelyn)
* Status: Open
* Priority: Normal
----------------------------------------
I often see code like the following:
``` ruby
hash.select { |_, v| v == :some_value }.keys
hash.keys.select { |k| k.nil? || k.even? }
hash.select { |k, v| valid_key?(k) && valid_value?(v) }.values
```
Each of these code snippets must allocate an intermediate data structure. I propose allowing `Hash#keys` and `Hash#values` to accept optional block parameters that *take both key and value*. For example, the above code could be rewritten as:
```ruby
hash.keys { |_, v| v == :some_value }
hash.keys { |k, _| k.nil? || k.even? }
hash.values { |k, v| valid_key?(k) && valid_value?(v) }
```
This behavior:
1. Does not break any existing code (since `Hash#keys` and `Hash#values` do not currently accept blocks).
2. Is very readable—it's obvious what it does at a glance.
3. Is more efficient than current alternatives.
4. Is more concise than current alternatives.
5. Is flexible and useful in a variety of scenarios, because the block has access to both key and value (unlike the behavior proposed in #14788).
--
https://bugs.ruby-lang.org/
^ permalink raw reply [flat|nested] 7+ messages in thread
* [ruby-core:97595] [Ruby master Feature#16739] Allow Hash#keys and Hash#values to accept a block for filtering output
2020-03-24 21:00 [ruby-core:97588] [Ruby master Feature#16739] Allow Hash#keys and Hash#values to accept a block for filtering output jacobevelyn
2020-03-25 3:31 ` [ruby-core:97590] " sawadatsuyoshi
@ 2020-03-25 15:14 ` mame
2020-03-25 15:31 ` [ruby-core:97596] " jacobevelyn
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: mame @ 2020-03-25 15:14 UTC (permalink / raw
To: ruby-core
Issue #16739 has been updated by mame (Yusuke Endoh).
I doubt if it is obvious. See the following code. I believe that many people expect `.map`.
```ruby
hash.keys {|k| k.to_s }
```
If you want to avoid an intermediate array, you may want to use `.each_key` or `.filter_map`.
```ruby
hash.each_key.select {|k| k.nil? || k.even? }
hash.filter_map {|k, v| k if valid_key?(k) && valid_value?(v) }
```
Personally I like the following explicit code, though.
```ruby
keys = []
hash.each do |k, v|
keys << k if valid_key?(k) && valid_value?(v)
end
```
----------------------------------------
Feature #16739: Allow Hash#keys and Hash#values to accept a block for filtering output
https://bugs.ruby-lang.org/issues/16739#change-84779
* Author: jacobevelyn (Jacob Evelyn)
* Status: Open
* Priority: Normal
----------------------------------------
I often see code like the following:
``` ruby
hash.select { |_, v| v == :some_value }.keys
hash.keys.select { |k| k.nil? || k.even? }
hash.select { |k, v| valid_key?(k) && valid_value?(v) }.values
```
Each of these code snippets must allocate an intermediate data structure. I propose allowing `Hash#keys` and `Hash#values` to accept optional block parameters that *take both key and value*. For example, the above code could be rewritten as:
```ruby
hash.keys { |_, v| v == :some_value }
hash.keys { |k, _| k.nil? || k.even? }
hash.values { |k, v| valid_key?(k) && valid_value?(v) }
```
This behavior:
1. Does not break any existing code (since `Hash#keys` and `Hash#values` do not currently accept blocks).
2. Is very readable—it's obvious what it does at a glance.
3. Is more efficient than current alternatives.
4. Is more concise than current alternatives.
5. Is flexible and useful in a variety of scenarios, because the block has access to both key and value (unlike the behavior proposed in #14788).
--
https://bugs.ruby-lang.org/
^ permalink raw reply [flat|nested] 7+ messages in thread
* [ruby-core:97596] [Ruby master Feature#16739] Allow Hash#keys and Hash#values to accept a block for filtering output
2020-03-24 21:00 [ruby-core:97588] [Ruby master Feature#16739] Allow Hash#keys and Hash#values to accept a block for filtering output jacobevelyn
2020-03-25 3:31 ` [ruby-core:97590] " sawadatsuyoshi
2020-03-25 15:14 ` [ruby-core:97595] " mame
@ 2020-03-25 15:31 ` jacobevelyn
2020-03-25 18:28 ` [ruby-core:97597] " eregontp
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: jacobevelyn @ 2020-03-25 15:31 UTC (permalink / raw
To: ruby-core
Issue #16739 has been updated by jacobevelyn (Jacob Evelyn).
> All it does is saves you from typing `select`. It does not look like the proposed feature makes much difference unless such situation is frequently met. Do you have any use case?
I see code that could be improved with this all the time, including in projects like [Ruby](https://github.com/ruby/ruby/blob/master/lib/reline/key_stroke.rb#L19-L35), [JRuby](https://github.com/jruby/jruby/blob/master/lib/ruby/stdlib/ffi/enum.rb#L247-L283), [Rails](https://github.com/rails/rails/blob/master/actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb#L38), [Discourse](https://github.com/discourse/discourse/blob/master/lib/stylesheet/manager.rb#L22-L30), [GitLab](https://github.com/gitlabhq/gitlabhq/blob/master/app/models/repository.rb#L919), [Metasploit](https://github.com/rapid7/metasploit-framework/blob/master/modules/auxiliary/scanner/snmp/snmp_enumusers.rb#L41), [Active Admin](https://github.com/activeadmin/activeadmin/blob/master/lib/active_admin/resource.rb#L191-L195), and [Airbnb's Nerve](https://github.com/airbnb/nerve/blob/master/lib/nerve.rb#L100-L115) (see links).
As I mentioned in my original post, it does not just save you from typing `select`—it also *avoids an unnecessary Hash allocation*, making it **more efficient** as well as more concise.
> If you want to avoid an intermediate array, you may want to use `.each_key` or `.filter_map`.
Many of these use cases aren't supported by `.each_key` or `.each_value` because they require looking at the one that's not being returned (or both keys and values). Honestly I wasn't aware of `.filter_map`; you're right that it's an option but I find it a bit verbose and hard to read.
> the purpose of a block following the methods keys and values does not seem to be immediately clear.
Obviously we can disagree about this. I think about it like `Enumerable#count`, where *what the method returns* does not change (an `Integer`) but the method becomes more flexible and powerful when you use a block.
----------------------------------------
Feature #16739: Allow Hash#keys and Hash#values to accept a block for filtering output
https://bugs.ruby-lang.org/issues/16739#change-84780
* Author: jacobevelyn (Jacob Evelyn)
* Status: Open
* Priority: Normal
----------------------------------------
I often see code like the following:
``` ruby
hash.select { |_, v| v == :some_value }.keys
hash.keys.select { |k| k.nil? || k.even? }
hash.select { |k, v| valid_key?(k) && valid_value?(v) }.values
```
Each of these code snippets must allocate an intermediate data structure. I propose allowing `Hash#keys` and `Hash#values` to accept optional block parameters that *take both key and value*. For example, the above code could be rewritten as:
```ruby
hash.keys { |_, v| v == :some_value }
hash.keys { |k, _| k.nil? || k.even? }
hash.values { |k, v| valid_key?(k) && valid_value?(v) }
```
This behavior:
1. Does not break any existing code (since `Hash#keys` and `Hash#values` do not currently accept blocks).
2. Is very readable—it's obvious what it does at a glance.
3. Is more efficient than current alternatives.
4. Is more concise than current alternatives.
5. Is flexible and useful in a variety of scenarios, because the block has access to both key and value (unlike the behavior proposed in #14788).
--
https://bugs.ruby-lang.org/
^ permalink raw reply [flat|nested] 7+ messages in thread
* [ruby-core:97597] [Ruby master Feature#16739] Allow Hash#keys and Hash#values to accept a block for filtering output
2020-03-24 21:00 [ruby-core:97588] [Ruby master Feature#16739] Allow Hash#keys and Hash#values to accept a block for filtering output jacobevelyn
` (2 preceding siblings ...)
2020-03-25 15:31 ` [ruby-core:97596] " jacobevelyn
@ 2020-03-25 18:28 ` eregontp
2020-04-04 5:39 ` [ruby-core:97713] " sawadatsuyoshi
2020-07-10 16:09 ` [ruby-core:99112] " jacobevelyn
5 siblings, 0 replies; 7+ messages in thread
From: eregontp @ 2020-03-25 18:28 UTC (permalink / raw
To: ruby-core
Issue #16739 has been updated by Eregon (Benoit Daloze).
Thank you for the examples and links.
`filter_map` looks good enough for this to me.
In general I think we avoid adding blocks to core methods, because indeed it's not clear if people expect #map, #select or #filter_map behavior, and it's so much clearer with the explicit call.
----------------------------------------
Feature #16739: Allow Hash#keys and Hash#values to accept a block for filtering output
https://bugs.ruby-lang.org/issues/16739#change-84781
* Author: jacobevelyn (Jacob Evelyn)
* Status: Open
* Priority: Normal
----------------------------------------
I often see code like the following:
``` ruby
hash.select { |_, v| v == :some_value }.keys
hash.keys.select { |k| k.nil? || k.even? }
hash.select { |k, v| valid_key?(k) && valid_value?(v) }.values
```
Each of these code snippets must allocate an intermediate data structure. I propose allowing `Hash#keys` and `Hash#values` to accept optional block parameters that *take both key and value*. For example, the above code could be rewritten as:
```ruby
hash.keys { |_, v| v == :some_value }
hash.keys { |k, _| k.nil? || k.even? }
hash.values { |k, v| valid_key?(k) && valid_value?(v) }
```
This behavior:
1. Does not break any existing code (since `Hash#keys` and `Hash#values` do not currently accept blocks).
2. Is very readable—it's obvious what it does at a glance.
3. Is more efficient than current alternatives.
4. Is more concise than current alternatives.
5. Is flexible and useful in a variety of scenarios, because the block has access to both key and value (unlike the behavior proposed in #14788).
--
https://bugs.ruby-lang.org/
^ permalink raw reply [flat|nested] 7+ messages in thread
* [ruby-core:97713] [Ruby master Feature#16739] Allow Hash#keys and Hash#values to accept a block for filtering output
2020-03-24 21:00 [ruby-core:97588] [Ruby master Feature#16739] Allow Hash#keys and Hash#values to accept a block for filtering output jacobevelyn
` (3 preceding siblings ...)
2020-03-25 18:28 ` [ruby-core:97597] " eregontp
@ 2020-04-04 5:39 ` sawadatsuyoshi
2020-07-10 16:09 ` [ruby-core:99112] " jacobevelyn
5 siblings, 0 replies; 7+ messages in thread
From: sawadatsuyoshi @ 2020-04-04 5:39 UTC (permalink / raw
To: ruby-core
Issue #16739 has been updated by sawa (Tsuyoshi Sawada).
Includes a duplicate of #14788.
----------------------------------------
Feature #16739: Allow Hash#keys and Hash#values to accept a block for filtering output
https://bugs.ruby-lang.org/issues/16739#change-84918
* Author: jacobevelyn (Jacob Evelyn)
* Status: Open
* Priority: Normal
----------------------------------------
I often see code like the following:
``` ruby
hash.select { |_, v| v == :some_value }.keys
hash.keys.select { |k| k.nil? || k.even? }
hash.select { |k, v| valid_key?(k) && valid_value?(v) }.values
```
Each of these code snippets must allocate an intermediate data structure. I propose allowing `Hash#keys` and `Hash#values` to accept optional block parameters that *take both key and value*. For example, the above code could be rewritten as:
```ruby
hash.keys { |_, v| v == :some_value }
hash.keys { |k, _| k.nil? || k.even? }
hash.values { |k, v| valid_key?(k) && valid_value?(v) }
```
This behavior:
1. Does not break any existing code (since `Hash#keys` and `Hash#values` do not currently accept blocks).
2. Is very readable—it's obvious what it does at a glance.
3. Is more efficient than current alternatives.
4. Is more concise than current alternatives.
5. Is flexible and useful in a variety of scenarios, because the block has access to both key and value (unlike the behavior proposed in #14788).
--
https://bugs.ruby-lang.org/
^ permalink raw reply [flat|nested] 7+ messages in thread
* [ruby-core:99112] [Ruby master Feature#16739] Allow Hash#keys and Hash#values to accept a block for filtering output
2020-03-24 21:00 [ruby-core:97588] [Ruby master Feature#16739] Allow Hash#keys and Hash#values to accept a block for filtering output jacobevelyn
` (4 preceding siblings ...)
2020-04-04 5:39 ` [ruby-core:97713] " sawadatsuyoshi
@ 2020-07-10 16:09 ` jacobevelyn
5 siblings, 0 replies; 7+ messages in thread
From: jacobevelyn @ 2020-07-10 16:09 UTC (permalink / raw
To: ruby-core
Issue #16739 has been updated by jacobevelyn (Jacob Evelyn).
sawa (Tsuyoshi Sawada) wrote in #note-5:
> Includes a duplicate of #14788.
I just want to note that this is a *more powerful* feature than what's proposed in #14788, because both the key and value would be available to the block.
Eregon (Benoit Daloze) wrote in #note-4:
> In general I think we avoid adding blocks to core methods, because indeed it's not clear if people expect #map, #select or #filter_map behavior, and it's so much clearer with the explicit call.
That's fair! Would calling these methods `filter_keys`/`filter_values` or `select_keys`/`select_values` be more explicit?
----------------------------------------
Feature #16739: Allow Hash#keys and Hash#values to accept a block for filtering output
https://bugs.ruby-lang.org/issues/16739#change-86487
* Author: jacobevelyn (Jacob Evelyn)
* Status: Open
* Priority: Normal
----------------------------------------
I often see code like the following:
``` ruby
hash.select { |_, v| v == :some_value }.keys
hash.keys.select { |k| k.nil? || k.even? }
hash.select { |k, v| valid_key?(k) && valid_value?(v) }.values
```
Each of these code snippets must allocate an intermediate data structure. I propose allowing `Hash#keys` and `Hash#values` to accept optional block parameters that *take both key and value*. For example, the above code could be rewritten as:
```ruby
hash.keys { |_, v| v == :some_value }
hash.keys { |k, _| k.nil? || k.even? }
hash.values { |k, v| valid_key?(k) && valid_value?(v) }
```
This behavior:
1. Does not break any existing code (since `Hash#keys` and `Hash#values` do not currently accept blocks).
2. Is very readable—it's obvious what it does at a glance.
3. Is more efficient than current alternatives.
4. Is more concise than current alternatives.
5. Is flexible and useful in a variety of scenarios, because the block has access to both key and value (unlike the behavior proposed in #14788).
--
https://bugs.ruby-lang.org/
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2020-07-10 16:10 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-03-24 21:00 [ruby-core:97588] [Ruby master Feature#16739] Allow Hash#keys and Hash#values to accept a block for filtering output jacobevelyn
2020-03-25 3:31 ` [ruby-core:97590] " sawadatsuyoshi
2020-03-25 15:14 ` [ruby-core:97595] " mame
2020-03-25 15:31 ` [ruby-core:97596] " jacobevelyn
2020-03-25 18:28 ` [ruby-core:97597] " eregontp
2020-04-04 5:39 ` [ruby-core:97713] " sawadatsuyoshi
2020-07-10 16:09 ` [ruby-core:99112] " jacobevelyn
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).