ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:120250] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols
@ 2024-12-15 16:32 zverok (Victor Shepelev) via ruby-core
  2024-12-15 23:29 ` [ruby-core:120255] " byroot (Jean Boussier) via ruby-core
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: zverok (Victor Shepelev) via ruby-core @ 2024-12-15 16:32 UTC (permalink / raw)
  To: ruby-core; +Cc: zverok (Victor Shepelev)

Issue #20953 has been reported by zverok (Victor Shepelev).

----------------------------------------
Feature #20953: Array#fetch_values vs #values_at protocols
https://bugs.ruby-lang.org/issues/20953

* Author: zverok (Victor Shepelev)
* Status: Open
----------------------------------------
I believe that the user might expect `#fetch_values` to be a stricter version of `#values_at`, confirming to the same protocol for arguments. 

But the current implementation for `#fetch_values` is simpler:
```ruby
[1, 2, 3, 4, 5].values_at(0, 3..4)    #=> [1, 4, 5]
[1, 2, 3, 4, 5].fetch_values(0, 3..4) # TypeError: in 'Array#fetch': no implicit conversion of Range into Integer
```

I believe aligning the implementations would lessen confusion (even if it makes `#fetch_values` implementation somewhat less trivial).

The practical example of usefulness:
```ruby
HEADERS = %w[Name Department]

def table_headers(rows)
  HEADERS.fetch_values(...rows.map(&:size).max) { '<unknown'> }
  # Or, alternatively:
  # HEADERS.fetch_values(...rows.map(&:size).max) { raise ArgumentError, "No header defined for column #{it + 1}" }
end

table_headers([
  ['John'],
  ['Jane'],
]) #=> ["Name"]

table_headers([
  ['John'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department"]

table_headers([
  ['John', 'Accounting', 'Feb 24'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department", "<unknown>"]
# or ArgumentError No header defined for column 3
```
(Obviously, we can use `fetch_values(*(0...max_row_size))` as an argument, but it feels like an unjustified extra work when `values_at` already can do this.)



-- 
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/

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [ruby-core:120255] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols
  2024-12-15 16:32 [ruby-core:120250] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols zverok (Victor Shepelev) via ruby-core
@ 2024-12-15 23:29 ` byroot (Jean Boussier) via ruby-core
  2024-12-16  9:23 ` [ruby-core:120258] " zverok (Victor Shepelev) via ruby-core
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: byroot (Jean Boussier) via ruby-core @ 2024-12-15 23:29 UTC (permalink / raw)
  To: ruby-core; +Cc: byroot (Jean Boussier)

Issue #20953 has been updated by byroot (Jean Boussier).


`Array#fetch_values` is modeled after `Hash#fetch_values`, not `Array#values_at`.

Since Array "keys" can only possibly be integers, it makes sense for a method that is specific to Array to cast the arguments this way.

But for the method that is meant to be used indiscriminately with either Array or Hash, I don't think it's a good idea.

----------------------------------------
Feature #20953: Array#fetch_values vs #values_at protocols
https://bugs.ruby-lang.org/issues/20953#change-111021

* Author: zverok (Victor Shepelev)
* Status: Open
----------------------------------------
I believe that the user might expect `#fetch_values` to be a stricter version of `#values_at`, confirming to the same protocol for arguments. 

But the current implementation for `#fetch_values` is simpler:
```ruby
[1, 2, 3, 4, 5].values_at(0, 3..4)    #=> [1, 4, 5]
[1, 2, 3, 4, 5].fetch_values(0, 3..4) # TypeError: in 'Array#fetch': no implicit conversion of Range into Integer
```

I believe aligning the implementations would lessen confusion (even if it makes `#fetch_values` implementation somewhat less trivial).

The practical example of usefulness:
```ruby
HEADERS = %w[Name Department]

def table_headers(rows)
  HEADERS.fetch_values(...rows.map(&:size).max) { '<unknown'> }
  # Or, alternatively:
  # HEADERS.fetch_values(...rows.map(&:size).max) { raise ArgumentError, "No header defined for column #{it + 1}" }
end

table_headers([
  ['John'],
  ['Jane'],
]) #=> ["Name"]

table_headers([
  ['John'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department"]

table_headers([
  ['John', 'Accounting', 'Feb 24'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department", "<unknown>"]
# or ArgumentError No header defined for column 3
```
(Obviously, we can use `fetch_values(*(0...max_row_size))` as an argument, but it feels like an unjustified extra work when `values_at` already can do this.)



-- 
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/

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [ruby-core:120258] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols
  2024-12-15 16:32 [ruby-core:120250] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols zverok (Victor Shepelev) via ruby-core
  2024-12-15 23:29 ` [ruby-core:120255] " byroot (Jean Boussier) via ruby-core
@ 2024-12-16  9:23 ` zverok (Victor Shepelev) via ruby-core
  2024-12-16 11:52 ` [ruby-core:120260] " byroot (Jean Boussier) via ruby-core
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: zverok (Victor Shepelev) via ruby-core @ 2024-12-16  9:23 UTC (permalink / raw)
  To: ruby-core; +Cc: zverok (Victor Shepelev)

Issue #20953 has been updated by zverok (Victor Shepelev).


> `Array#fetch_values` is modeled after `Hash#fetch_values`, not `Array#values_at`.

But in Hash, `#values_at` and `#fetch_values` have exactly the same protocol (they accept the list of keys), and can be substituted by each other. 

So, I understand it is all hand-wavy, yet I’d say that the common motive of similar methods between Hash and Array is that they are, well, similar, yet internal consistency inside one class is more important than consistency between classes.

In fact, we don’t need to go far to prove that: `values_at` is a good example: the same name, the similar signature `values_at(*objects)`, and yet Array’s one accepts ranges besides just indices. There are many more methods with the same name and sense (`#[]`, `#select`/`#reject`, `#include?`, etc.), all of them behaving slightly differently between classes, and matching the expectation of a particular class users.

> But for the method that is meant to be used indiscriminately with either Array or Hash, I don't think it's a good idea.

Do we have a lot of those, and what’s the reasoning/use cases behind this? I mean, methods that are exactly reconciled between Array and Hash (at the expense of the internal consistency inside any one class), to be used indiscriminately?

----------------------------------------
Feature #20953: Array#fetch_values vs #values_at protocols
https://bugs.ruby-lang.org/issues/20953#change-111024

* Author: zverok (Victor Shepelev)
* Status: Open
----------------------------------------
I believe that the user might expect `#fetch_values` to be a stricter version of `#values_at`, confirming to the same protocol for arguments. 

But the current implementation for `#fetch_values` is simpler:
```ruby
[1, 2, 3, 4, 5].values_at(0, 3..4)    #=> [1, 4, 5]
[1, 2, 3, 4, 5].fetch_values(0, 3..4) # TypeError: in 'Array#fetch': no implicit conversion of Range into Integer
```

I believe aligning the implementations would lessen confusion (even if it makes `#fetch_values` implementation somewhat less trivial).

The practical example of usefulness:
```ruby
HEADERS = %w[Name Department]

def table_headers(rows)
  HEADERS.fetch_values(...rows.map(&:size).max) { '<unknown'> }
  # Or, alternatively:
  # HEADERS.fetch_values(...rows.map(&:size).max) { raise ArgumentError, "No header defined for column #{it + 1}" }
end

table_headers([
  ['John'],
  ['Jane'],
]) #=> ["Name"]

table_headers([
  ['John'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department"]

table_headers([
  ['John', 'Accounting', 'Feb 24'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department", "<unknown>"]
# or ArgumentError No header defined for column 3
```
(Obviously, we can use `fetch_values(*(0...max_row_size))` as an argument, but it feels like an unjustified extra work when `values_at` already can do this.)



-- 
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/

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [ruby-core:120260] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols
  2024-12-15 16:32 [ruby-core:120250] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols zverok (Victor Shepelev) via ruby-core
  2024-12-15 23:29 ` [ruby-core:120255] " byroot (Jean Boussier) via ruby-core
  2024-12-16  9:23 ` [ruby-core:120258] " zverok (Victor Shepelev) via ruby-core
@ 2024-12-16 11:52 ` byroot (Jean Boussier) via ruby-core
  2024-12-18  7:59 ` [ruby-core:120294] " zverok (Victor Shepelev) via ruby-core
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: byroot (Jean Boussier) via ruby-core @ 2024-12-16 11:52 UTC (permalink / raw)
  To: ruby-core; +Cc: byroot (Jean Boussier)

Issue #20953 has been updated by byroot (Jean Boussier).


> Do we have a lot of those, and what’s the reasoning/use cases behind this? 

Things like `#dig`, so that you can traverse a tree of mixed Hash/Array with some sort of "path" argument.

Either way, I see pros and cons to both behavior, so it's not for me to decide, it's up to @matz.

The issue though is the release is imminent and the next developer meeting is scheduled for January. So if you wish to change this before the release you'll have to ping @matz on Twitter or something for him to make a decision in time.

----------------------------------------
Feature #20953: Array#fetch_values vs #values_at protocols
https://bugs.ruby-lang.org/issues/20953#change-111026

* Author: zverok (Victor Shepelev)
* Status: Open
----------------------------------------
I believe that the user might expect `#fetch_values` to be a stricter version of `#values_at`, confirming to the same protocol for arguments. 

But the current implementation for `#fetch_values` is simpler:
```ruby
[1, 2, 3, 4, 5].values_at(0, 3..4)    #=> [1, 4, 5]
[1, 2, 3, 4, 5].fetch_values(0, 3..4) # TypeError: in 'Array#fetch': no implicit conversion of Range into Integer
```

I believe aligning the implementations would lessen confusion (even if it makes `#fetch_values` implementation somewhat less trivial).

The practical example of usefulness:
```ruby
HEADERS = %w[Name Department]

def table_headers(rows)
  HEADERS.fetch_values(...rows.map(&:size).max) { '<unknown'> }
  # Or, alternatively:
  # HEADERS.fetch_values(...rows.map(&:size).max) { raise ArgumentError, "No header defined for column #{it + 1}" }
end

table_headers([
  ['John'],
  ['Jane'],
]) #=> ["Name"]

table_headers([
  ['John'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department"]

table_headers([
  ['John', 'Accounting', 'Feb 24'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department", "<unknown>"]
# or ArgumentError No header defined for column 3
```
(Obviously, we can use `fetch_values(*(0...max_row_size))` as an argument, but it feels like an unjustified extra work when `values_at` already can do this.)



-- 
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/

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [ruby-core:120294] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols
  2024-12-15 16:32 [ruby-core:120250] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols zverok (Victor Shepelev) via ruby-core
                   ` (2 preceding siblings ...)
  2024-12-16 11:52 ` [ruby-core:120260] " byroot (Jean Boussier) via ruby-core
@ 2024-12-18  7:59 ` zverok (Victor Shepelev) via ruby-core
  2025-01-09 11:35 ` [ruby-core:120569] " mame (Yusuke Endoh) via ruby-core
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: zverok (Victor Shepelev) via ruby-core @ 2024-12-18  7:59 UTC (permalink / raw)
  To: ruby-core; +Cc: zverok (Victor Shepelev)

Issue #20953 has been updated by zverok (Victor Shepelev).

Assignee set to matz (Yukihiro Matsumoto)

----------------------------------------
Feature #20953: Array#fetch_values vs #values_at protocols
https://bugs.ruby-lang.org/issues/20953#change-111059

* Author: zverok (Victor Shepelev)
* Status: Open
* Assignee: matz (Yukihiro Matsumoto)
----------------------------------------
I believe that the user might expect `#fetch_values` to be a stricter version of `#values_at`, confirming to the same protocol for arguments. 

But the current implementation for `#fetch_values` is simpler:
```ruby
[1, 2, 3, 4, 5].values_at(0, 3..4)    #=> [1, 4, 5]
[1, 2, 3, 4, 5].fetch_values(0, 3..4) # TypeError: in 'Array#fetch': no implicit conversion of Range into Integer
```

I believe aligning the implementations would lessen confusion (even if it makes `#fetch_values` implementation somewhat less trivial).

The practical example of usefulness:
```ruby
HEADERS = %w[Name Department]

def table_headers(rows)
  HEADERS.fetch_values(...rows.map(&:size).max) { '<unknown'> }
  # Or, alternatively:
  # HEADERS.fetch_values(...rows.map(&:size).max) { raise ArgumentError, "No header defined for column #{it + 1}" }
end

table_headers([
  ['John'],
  ['Jane'],
]) #=> ["Name"]

table_headers([
  ['John'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department"]

table_headers([
  ['John', 'Accounting', 'Feb 24'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department", "<unknown>"]
# or ArgumentError No header defined for column 3
```
(Obviously, we can use `fetch_values(*(0...max_row_size))` as an argument, but it feels like an unjustified extra work when `values_at` already can do this.)



-- 
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/

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [ruby-core:120569] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols
  2024-12-15 16:32 [ruby-core:120250] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols zverok (Victor Shepelev) via ruby-core
                   ` (3 preceding siblings ...)
  2024-12-18  7:59 ` [ruby-core:120294] " zverok (Victor Shepelev) via ruby-core
@ 2025-01-09 11:35 ` mame (Yusuke Endoh) via ruby-core
  2025-01-13 14:43 ` [ruby-core:120632] " byroot (Jean Boussier) via ruby-core
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: mame (Yusuke Endoh) via ruby-core @ 2025-01-09 11:35 UTC (permalink / raw)
  To: ruby-core; +Cc: mame (Yusuke Endoh)

Issue #20953 has been updated by mame (Yusuke Endoh).


Discussed at the dev meeting. @matz liked to align the behavior of Array#fetch_values with Array#values_at here in this case. So a Range should be expanded.

----------------------------------------
Feature #20953: Array#fetch_values vs #values_at protocols
https://bugs.ruby-lang.org/issues/20953#change-111393

* Author: zverok (Victor Shepelev)
* Status: Open
* Assignee: matz (Yukihiro Matsumoto)
----------------------------------------
I believe that the user might expect `#fetch_values` to be a stricter version of `#values_at`, confirming to the same protocol for arguments. 

But the current implementation for `#fetch_values` is simpler:
```ruby
[1, 2, 3, 4, 5].values_at(0, 3..4)    #=> [1, 4, 5]
[1, 2, 3, 4, 5].fetch_values(0, 3..4) # TypeError: in 'Array#fetch': no implicit conversion of Range into Integer
```

I believe aligning the implementations would lessen confusion (even if it makes `#fetch_values` implementation somewhat less trivial).

The practical example of usefulness:
```ruby
HEADERS = %w[Name Department]

def table_headers(rows)
  HEADERS.fetch_values(...rows.map(&:size).max) { '<unknown'> }
  # Or, alternatively:
  # HEADERS.fetch_values(...rows.map(&:size).max) { raise ArgumentError, "No header defined for column #{it + 1}" }
end

table_headers([
  ['John'],
  ['Jane'],
]) #=> ["Name"]

table_headers([
  ['John'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department"]

table_headers([
  ['John', 'Accounting', 'Feb 24'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department", "<unknown>"]
# or ArgumentError No header defined for column 3
```
(Obviously, we can use `fetch_values(*(0...max_row_size))` as an argument, but it feels like an unjustified extra work when `values_at` already can do this.)



-- 
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/

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [ruby-core:120632] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols
  2024-12-15 16:32 [ruby-core:120250] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols zverok (Victor Shepelev) via ruby-core
                   ` (4 preceding siblings ...)
  2025-01-09 11:35 ` [ruby-core:120569] " mame (Yusuke Endoh) via ruby-core
@ 2025-01-13 14:43 ` byroot (Jean Boussier) via ruby-core
  2025-01-13 15:08 ` [ruby-core:120633] " byroot (Jean Boussier) via ruby-core
  2025-01-13 15:17 ` [ruby-core:120634] " zverok (Victor Shepelev) via ruby-core
  7 siblings, 0 replies; 9+ messages in thread
From: byroot (Jean Boussier) via ruby-core @ 2025-01-13 14:43 UTC (permalink / raw)
  To: ruby-core; +Cc: byroot (Jean Boussier)

Issue #20953 has been updated by byroot (Jean Boussier).


Alright.

What's the expected behavior of:

```ruby
[1, 2, 3].fetch_values(42..)
[1, 2, 3].fetch_values(42..) { true }
[1, 2, 3].fetch_values(..42)
[1, 2, 3].fetch_values(..42) { true }
```


----------------------------------------
Feature #20953: Array#fetch_values vs #values_at protocols
https://bugs.ruby-lang.org/issues/20953#change-111461

* Author: zverok (Victor Shepelev)
* Status: Open
* Assignee: matz (Yukihiro Matsumoto)
----------------------------------------
I believe that the user might expect `#fetch_values` to be a stricter version of `#values_at`, confirming to the same protocol for arguments. 

But the current implementation for `#fetch_values` is simpler:
```ruby
[1, 2, 3, 4, 5].values_at(0, 3..4)    #=> [1, 4, 5]
[1, 2, 3, 4, 5].fetch_values(0, 3..4) # TypeError: in 'Array#fetch': no implicit conversion of Range into Integer
```

I believe aligning the implementations would lessen confusion (even if it makes `#fetch_values` implementation somewhat less trivial).

The practical example of usefulness:
```ruby
HEADERS = %w[Name Department]

def table_headers(rows)
  HEADERS.fetch_values(...rows.map(&:size).max) { '<unknown'> }
  # Or, alternatively:
  # HEADERS.fetch_values(...rows.map(&:size).max) { raise ArgumentError, "No header defined for column #{it + 1}" }
end

table_headers([
  ['John'],
  ['Jane'],
]) #=> ["Name"]

table_headers([
  ['John'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department"]

table_headers([
  ['John', 'Accounting', 'Feb 24'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department", "<unknown>"]
# or ArgumentError No header defined for column 3
```
(Obviously, we can use `fetch_values(*(0...max_row_size))` as an argument, but it feels like an unjustified extra work when `values_at` already can do this.)



-- 
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/

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [ruby-core:120633] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols
  2024-12-15 16:32 [ruby-core:120250] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols zverok (Victor Shepelev) via ruby-core
                   ` (5 preceding siblings ...)
  2025-01-13 14:43 ` [ruby-core:120632] " byroot (Jean Boussier) via ruby-core
@ 2025-01-13 15:08 ` byroot (Jean Boussier) via ruby-core
  2025-01-13 15:17 ` [ruby-core:120634] " zverok (Victor Shepelev) via ruby-core
  7 siblings, 0 replies; 9+ messages in thread
From: byroot (Jean Boussier) via ruby-core @ 2025-01-13 15:08 UTC (permalink / raw)
  To: ruby-core; +Cc: byroot (Jean Boussier)

Issue #20953 has been updated by byroot (Jean Boussier).


I opened https://github.com/ruby/ruby/pull/12565 as a draft, with some failing specs for the edge cases I found but I don't know how they should be handled.

----------------------------------------
Feature #20953: Array#fetch_values vs #values_at protocols
https://bugs.ruby-lang.org/issues/20953#change-111462

* Author: zverok (Victor Shepelev)
* Status: Open
* Assignee: matz (Yukihiro Matsumoto)
----------------------------------------
I believe that the user might expect `#fetch_values` to be a stricter version of `#values_at`, confirming to the same protocol for arguments. 

But the current implementation for `#fetch_values` is simpler:
```ruby
[1, 2, 3, 4, 5].values_at(0, 3..4)    #=> [1, 4, 5]
[1, 2, 3, 4, 5].fetch_values(0, 3..4) # TypeError: in 'Array#fetch': no implicit conversion of Range into Integer
```

I believe aligning the implementations would lessen confusion (even if it makes `#fetch_values` implementation somewhat less trivial).

The practical example of usefulness:
```ruby
HEADERS = %w[Name Department]

def table_headers(rows)
  HEADERS.fetch_values(...rows.map(&:size).max) { '<unknown'> }
  # Or, alternatively:
  # HEADERS.fetch_values(...rows.map(&:size).max) { raise ArgumentError, "No header defined for column #{it + 1}" }
end

table_headers([
  ['John'],
  ['Jane'],
]) #=> ["Name"]

table_headers([
  ['John'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department"]

table_headers([
  ['John', 'Accounting', 'Feb 24'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department", "<unknown>"]
# or ArgumentError No header defined for column 3
```
(Obviously, we can use `fetch_values(*(0...max_row_size))` as an argument, but it feels like an unjustified extra work when `values_at` already can do this.)



-- 
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/

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [ruby-core:120634] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols
  2024-12-15 16:32 [ruby-core:120250] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols zverok (Victor Shepelev) via ruby-core
                   ` (6 preceding siblings ...)
  2025-01-13 15:08 ` [ruby-core:120633] " byroot (Jean Boussier) via ruby-core
@ 2025-01-13 15:17 ` zverok (Victor Shepelev) via ruby-core
  7 siblings, 0 replies; 9+ messages in thread
From: zverok (Victor Shepelev) via ruby-core @ 2025-01-13 15:17 UTC (permalink / raw)
  To: ruby-core; +Cc: zverok (Victor Shepelev)

Issue #20953 has been updated by zverok (Victor Shepelev).


> What's the expected behavior of:

For `..42` versions, I believe that `values_at` behavior gives enough affordance:
```ruby
[1, 2, 3].values_at(..6)
#=> [1, 2, 3, nil, nil, nil, nil]
```
So, I suppose:
```ruby
[1, 2, 3].fetch_values(..6)
# IndexError at 3, same as...
[1, 2, 3].fetch_values(0, 1, 2, 3, 4, 5, 6)

[1, 2, 3].fetch_values(..6) { true }
#=> [1, 2, 3, true, true, true, true]
```

For `42..` it is not that straightforward, because `values_at` behavior is somewhat confusing here. 
```ruby
[1, 2, 3].values_at(6..)
#=> []
```

We might just follow it, though. I believe that it is implicitly treated as 
```ruby
[1, 2, 3].values_at(*(6..2).to_a)
```
(i.e. the apper bound is `(ary.size - 1)`), and, as this range is empty, nothing is tried to be fetched from the array. So it should just be the same:
```ruby
[1, 2, 3].fetch_values(6..)
#=> [] 
```

It is not an immediately obvious thing, but I am not sure what would be the one; and at least this behavior is already established.

Alternatively, if the range _beginning_ is out of bounds, `fetch_values` might raise. This would be explainable, too.

----------------------------------------
Feature #20953: Array#fetch_values vs #values_at protocols
https://bugs.ruby-lang.org/issues/20953#change-111463

* Author: zverok (Victor Shepelev)
* Status: Open
* Assignee: matz (Yukihiro Matsumoto)
----------------------------------------
I believe that the user might expect `#fetch_values` to be a stricter version of `#values_at`, confirming to the same protocol for arguments. 

But the current implementation for `#fetch_values` is simpler:
```ruby
[1, 2, 3, 4, 5].values_at(0, 3..4)    #=> [1, 4, 5]
[1, 2, 3, 4, 5].fetch_values(0, 3..4) # TypeError: in 'Array#fetch': no implicit conversion of Range into Integer
```

I believe aligning the implementations would lessen confusion (even if it makes `#fetch_values` implementation somewhat less trivial).

The practical example of usefulness:
```ruby
HEADERS = %w[Name Department]

def table_headers(rows)
  HEADERS.fetch_values(...rows.map(&:size).max) { '<unknown'> }
  # Or, alternatively:
  # HEADERS.fetch_values(...rows.map(&:size).max) { raise ArgumentError, "No header defined for column #{it + 1}" }
end

table_headers([
  ['John'],
  ['Jane'],
]) #=> ["Name"]

table_headers([
  ['John'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department"]

table_headers([
  ['John', 'Accounting', 'Feb 24'],
  ['Jane', 'Engineering'],
]) #=> ["Name", "Department", "<unknown>"]
# or ArgumentError No header defined for column 3
```
(Obviously, we can use `fetch_values(*(0...max_row_size))` as an argument, but it feels like an unjustified extra work when `values_at` already can do this.)



-- 
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/

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2025-01-13 15:18 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-12-15 16:32 [ruby-core:120250] [Ruby master Feature#20953] Array#fetch_values vs #values_at protocols zverok (Victor Shepelev) via ruby-core
2024-12-15 23:29 ` [ruby-core:120255] " byroot (Jean Boussier) via ruby-core
2024-12-16  9:23 ` [ruby-core:120258] " zverok (Victor Shepelev) via ruby-core
2024-12-16 11:52 ` [ruby-core:120260] " byroot (Jean Boussier) via ruby-core
2024-12-18  7:59 ` [ruby-core:120294] " zverok (Victor Shepelev) via ruby-core
2025-01-09 11:35 ` [ruby-core:120569] " mame (Yusuke Endoh) via ruby-core
2025-01-13 14:43 ` [ruby-core:120632] " byroot (Jean Boussier) via ruby-core
2025-01-13 15:08 ` [ruby-core:120633] " byroot (Jean Boussier) via ruby-core
2025-01-13 15:17 ` [ruby-core:120634] " zverok (Victor Shepelev) via ruby-core

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 NNTP newsgroup(s).