ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:111859] [Ruby master Feature#15381] Let double splat call `to_h` implicitly
       [not found] <redmine.issue-15381.20181205082504.2963@ruby-lang.org>
@ 2023-01-17 18:11 ` sawa (Tsuyoshi Sawada) via ruby-core
  2024-10-21 21:30 ` [ruby-core:119581] " sanjioh (Fabio Sangiovanni) via ruby-core
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: sawa (Tsuyoshi Sawada) via ruby-core @ 2023-01-17 18:11 UTC (permalink / raw)
  To: ruby-core; +Cc: sawa (Tsuyoshi Sawada)

Issue #15381 has been updated by sawa (Tsuyoshi Sawada).


This feature has already been realized at some point (although I cannot specify which Ruby version first introduced this).

Please close this issue.

----------------------------------------
Feature #15381: Let double splat call `to_h` implicitly
https://bugs.ruby-lang.org/issues/15381#change-101272

* Author: sawa (Tsuyoshi Sawada)
* Status: Open
* Priority: Normal
----------------------------------------
The single splat calls `to_a` implicitly on the object (if it is not an array already) so that, for example, we have the convenience of writing conditions in an array literal:

```ruby
a = [
  *(:foo if some_condition),
  *(:bar if another_condition),
]
```

And the ampersand implicitly calls `to_proc` on the object (if it is not a proc already) so that we can substitute a block with an ampersand followed by a symbol:

```ruby
some_method(&:some_method_name)
```

Unlike the single splat and ampersand, the double splat does not seem to implicitly call a corresponding method. I propose that the double splat should call `to_h` implicitly on the object if it not already a Hash so that we can, for example, write a condition in a hash literal as follows:

```ruby
h = {
  **({a: 1} if some_condition),
  **({b: 2) if another_condition),
}
```

There may be some other benefits of this feature that I have not noticed yet.



-- 
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/postorius/lists/ruby-core.ml.ruby-lang.org/

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

* [ruby-core:119581] [Ruby master Feature#15381] Let double splat call `to_h` implicitly
       [not found] <redmine.issue-15381.20181205082504.2963@ruby-lang.org>
  2023-01-17 18:11 ` [ruby-core:111859] [Ruby master Feature#15381] Let double splat call `to_h` implicitly sawa (Tsuyoshi Sawada) via ruby-core
@ 2024-10-21 21:30 ` sanjioh (Fabio Sangiovanni) via ruby-core
  2024-10-22  6:12 ` [ruby-core:119585] " zverok (Victor Shepelev) via ruby-core
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: sanjioh (Fabio Sangiovanni) via ruby-core @ 2024-10-21 21:30 UTC (permalink / raw)
  To: ruby-core; +Cc: sanjioh (Fabio Sangiovanni)

Issue #15381 has been updated by sanjioh (Fabio Sangiovanni).


Eregon (Benoit Daloze) wrote in #note-4:
> Should `**` call `to_h` rather than `to_hash`, similar to `*` calling `to_a` and not `to_ary`?

Hi, I’m learning Ruby and the fact that `**` calls `to_hash` rather than `to_h` surprised me; I would expect it to be consistent to `*` calling `to_a`.

I suppose that changing this behavior would break to much code, though.

A pointer to the decision making process that lead to using `to_hash` would be helpful nonetheless.

Thanks!

----------------------------------------
Feature #15381: Let double splat call `to_h` implicitly
https://bugs.ruby-lang.org/issues/15381#change-110200

* Author: sawa (Tsuyoshi Sawada)
* Status: Open
----------------------------------------
The single splat calls `to_a` implicitly on the object (if it is not an array already) so that, for example, we have the convenience of writing conditions in an array literal:

```ruby
a = [
  *(:foo if some_condition),
  *(:bar if another_condition),
]
```

And the ampersand implicitly calls `to_proc` on the object (if it is not a proc already) so that we can substitute a block with an ampersand followed by a symbol:

```ruby
some_method(&:some_method_name)
```

Unlike the single splat and ampersand, the double splat does not seem to implicitly call a corresponding method. I propose that the double splat should call `to_h` implicitly on the object if it not already a Hash so that we can, for example, write a condition in a hash literal as follows:

```ruby
h = {
  **({a: 1} if some_condition),
  **({b: 2) if another_condition),
}
```

There may be some other benefits of this feature that I have not noticed yet.



-- 
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] 10+ messages in thread

* [ruby-core:119585] [Ruby master Feature#15381] Let double splat call `to_h` implicitly
       [not found] <redmine.issue-15381.20181205082504.2963@ruby-lang.org>
  2023-01-17 18:11 ` [ruby-core:111859] [Ruby master Feature#15381] Let double splat call `to_h` implicitly sawa (Tsuyoshi Sawada) via ruby-core
  2024-10-21 21:30 ` [ruby-core:119581] " sanjioh (Fabio Sangiovanni) via ruby-core
@ 2024-10-22  6:12 ` zverok (Victor Shepelev) via ruby-core
  2024-10-22 18:10 ` [ruby-core:119588] " Dan0042 (Daniel DeLorme) via ruby-core
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: zverok (Victor Shepelev) via ruby-core @ 2024-10-22  6:12 UTC (permalink / raw)
  To: ruby-core; +Cc: zverok (Victor Shepelev)

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


I believe that the general agreement is that short `to_{t}` methods (`to_s`, `to_i`, `to_h`, `to_a`) have a semantics of “have some {type} representation/can be converted to {type}", while long `to_{type}` ones have a meaning of “are kind-of {type}”. Mostly (though not exclusively), `to_{t}` is used via explicit calls, while `to_{type}` converts the object implicitly on various operators.

Now, I believe that using `to_h` (an explicit conversion method) implicitly on `**` would lead to a lot of unintended consequences. Things that typically have `to_h` but are not intended as “option hashes” are, for example:
* every Enumerable
* most of model-like things (from ActiveRecord to mere Struct)

Having them suddenly unpack when nobody intended that (say, typoing `**array` instead of `*array`; or by mistake passing model instance instead of some `options` to a place where it would be handled with `**options`) might lead to very confusing error messages at the very least, and mysterious, hard to debug behavior in worse cases.

PS: I actually believe that `*` invoking `to_a` and not `to_ary` brings more bad than good (things like `Time` or `Struct` can be unpacked when, again, nobody has intended it; it also breaks the mental model of explicit/implicit conversion methods). However, it is obviously too late to fix that.

----------------------------------------
Feature #15381: Let double splat call `to_h` implicitly
https://bugs.ruby-lang.org/issues/15381#change-110204

* Author: sawa (Tsuyoshi Sawada)
* Status: Open
----------------------------------------
The single splat calls `to_a` implicitly on the object (if it is not an array already) so that, for example, we have the convenience of writing conditions in an array literal:

```ruby
a = [
  *(:foo if some_condition),
  *(:bar if another_condition),
]
```

And the ampersand implicitly calls `to_proc` on the object (if it is not a proc already) so that we can substitute a block with an ampersand followed by a symbol:

```ruby
some_method(&:some_method_name)
```

Unlike the single splat and ampersand, the double splat does not seem to implicitly call a corresponding method. I propose that the double splat should call `to_h` implicitly on the object if it not already a Hash so that we can, for example, write a condition in a hash literal as follows:

```ruby
h = {
  **({a: 1} if some_condition),
  **({b: 2) if another_condition),
}
```

There may be some other benefits of this feature that I have not noticed yet.



-- 
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] 10+ messages in thread

* [ruby-core:119588] [Ruby master Feature#15381] Let double splat call `to_h` implicitly
       [not found] <redmine.issue-15381.20181205082504.2963@ruby-lang.org>
                   ` (2 preceding siblings ...)
  2024-10-22  6:12 ` [ruby-core:119585] " zverok (Victor Shepelev) via ruby-core
@ 2024-10-22 18:10 ` Dan0042 (Daniel DeLorme) via ruby-core
  2024-10-22 18:37 ` [ruby-core:119589] " zverok (Victor Shepelev) via ruby-core
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: Dan0042 (Daniel DeLorme) via ruby-core @ 2024-10-22 18:10 UTC (permalink / raw)
  To: ruby-core; +Cc: Dan0042 (Daniel DeLorme)

Issue #15381 has been updated by Dan0042 (Daniel DeLorme).


`to_{t}` methods are for explicit type conversion, and `to_{type}` methods are for implicit type conversion.

`{}.merge(obj)` => obj is implicitly expected to be Hash, or converted via #to_hash
`{}.merge(obj.to_h)` => obj is explicitly converted via #to_h
`{}.merge(**obj)` => obj is **explicitly** splatted but conversion is done via #to_hash instead of #to_h. It makes no sense, as many many people have commented through the years.

If you're double-splatting an object, of course you'd expect it to be convertible to a Hash. Please assume I'm not an idiot and that `**obj` is my intent, not a typo. Being overly restrictive (only true Hash-like objects can be used!) serves no purpose. Having to do `**obj.to_h` is silly, and adding #to_hash to a class in order to make it splattable is even more silly (possibly dangerous).

The fix is easy and backward-compatible; just let double splat convert the object with both #to_hash and #to_h. But instead the "fix" that we got is a weird (although useful) one-off exception for `**nil`. 🙄

----------------------------------------
Feature #15381: Let double splat call `to_h` implicitly
https://bugs.ruby-lang.org/issues/15381#change-110209

* Author: sawa (Tsuyoshi Sawada)
* Status: Open
----------------------------------------
The single splat calls `to_a` implicitly on the object (if it is not an array already) so that, for example, we have the convenience of writing conditions in an array literal:

```ruby
a = [
  *(:foo if some_condition),
  *(:bar if another_condition),
]
```

And the ampersand implicitly calls `to_proc` on the object (if it is not a proc already) so that we can substitute a block with an ampersand followed by a symbol:

```ruby
some_method(&:some_method_name)
```

Unlike the single splat and ampersand, the double splat does not seem to implicitly call a corresponding method. I propose that the double splat should call `to_h` implicitly on the object if it not already a Hash so that we can, for example, write a condition in a hash literal as follows:

```ruby
h = {
  **({a: 1} if some_condition),
  **({b: 2) if another_condition),
}
```

There may be some other benefits of this feature that I have not noticed yet.



-- 
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] 10+ messages in thread

* [ruby-core:119589] [Ruby master Feature#15381] Let double splat call `to_h` implicitly
       [not found] <redmine.issue-15381.20181205082504.2963@ruby-lang.org>
                   ` (3 preceding siblings ...)
  2024-10-22 18:10 ` [ruby-core:119588] " Dan0042 (Daniel DeLorme) via ruby-core
@ 2024-10-22 18:37 ` zverok (Victor Shepelev) via ruby-core
  2024-10-22 19:32 ` [ruby-core:119590] " Dan0042 (Daniel DeLorme) via ruby-core
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: zverok (Victor Shepelev) via ruby-core @ 2024-10-22 18:37 UTC (permalink / raw)
  To: ruby-core; +Cc: zverok (Victor Shepelev)

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


> `{}.merge(**obj)` => obj is explicitly splatted but conversion is done via #to_hash instead of #to_h. It makes no sense, as many many people have commented through the years.

I don’t think it can be treated as “explicitly” (invoking hash conversion); it is rather “we apply an operator, which would work with kind-of hash”. We can apply the same argument to `1 + obj`: “you see, I am _explicitly_ summing it with an integer; why is it not converted with `to_int`?”

> `**obj` is my intent, not a typo. 

What if it _is_ a typo/error? Assume this API (frequent in many long-living codebases, which are partially old-style “options hash” and partially new-style “keyword arguments”):

```ruby
def process(something, options = {})
  # ...
  other_method(**options)
end
```
Now, if the user misuses it (by mistake or misunderstanding) and passes some, say, ActiveRecord model as a second parameter, then, with `to_h`, it would be successfully unpacked, and might go this way (as “keyword arguments” which shouldn’t have been) through several more delegating methods before failing in completely different place—with an extremely hard to debug problem.

So, what we are weighting here are:
* convenience of unpacking non-hashes into keyword arguments (BTW, what exactly is the use case for this convenience?..), vs.
* problem of things being _unintentionally_ unpacked, considering how many objects have `to_h` method; basically failing to “fail early” (where the mistake was made) and instead passing the mistake for who-know-which depth.

I honestly fail to see the use case for `to_h` being used with `**` that outweighs the possible problems (other than `**(params if condition?)`, which was actually handled).

----------------------------------------
Feature #15381: Let double splat call `to_h` implicitly
https://bugs.ruby-lang.org/issues/15381#change-110210

* Author: sawa (Tsuyoshi Sawada)
* Status: Open
----------------------------------------
The single splat calls `to_a` implicitly on the object (if it is not an array already) so that, for example, we have the convenience of writing conditions in an array literal:

```ruby
a = [
  *(:foo if some_condition),
  *(:bar if another_condition),
]
```

And the ampersand implicitly calls `to_proc` on the object (if it is not a proc already) so that we can substitute a block with an ampersand followed by a symbol:

```ruby
some_method(&:some_method_name)
```

Unlike the single splat and ampersand, the double splat does not seem to implicitly call a corresponding method. I propose that the double splat should call `to_h` implicitly on the object if it not already a Hash so that we can, for example, write a condition in a hash literal as follows:

```ruby
h = {
  **({a: 1} if some_condition),
  **({b: 2) if another_condition),
}
```

There may be some other benefits of this feature that I have not noticed yet.



-- 
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] 10+ messages in thread

* [ruby-core:119590] [Ruby master Feature#15381] Let double splat call `to_h` implicitly
       [not found] <redmine.issue-15381.20181205082504.2963@ruby-lang.org>
                   ` (4 preceding siblings ...)
  2024-10-22 18:37 ` [ruby-core:119589] " zverok (Victor Shepelev) via ruby-core
@ 2024-10-22 19:32 ` Dan0042 (Daniel DeLorme) via ruby-core
  2024-10-22 19:58 ` [ruby-core:119591] " jeremyevans0 (Jeremy Evans) via ruby-core
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: Dan0042 (Daniel DeLorme) via ruby-core @ 2024-10-22 19:32 UTC (permalink / raw)
  To: ruby-core; +Cc: Dan0042 (Daniel DeLorme)

Issue #15381 has been updated by Dan0042 (Daniel DeLorme).


> I don’t think it can be treated as “explicitly”

The `**` is right there in the code, written out caller-side, you can't get more "explicit" than that.

> We can apply the same argument to `1 + obj`

No we can't; as you know `+` is a method (I guess that would make `**` a "true" operator?) so `1.+(obj)` is similar to `{}.merge(obj)` and falls under implicit conversion (which the method is free to do or not)

> What if it _is_ a typo/error?

Then I'll fix my stupid mistakes by my own stupid self, thank you very much.

> Now, if the user misuses it (by mistake or misunderstanding) and passes some, say, ActiveRecord model as a second parameter, then, with `to_h`, it would be successfully unpacked

I think that would be awesome. If I do `other_method(**model)` and that `model` is representable as a hash, passing it as keyword arguments is beautiful.
Imagine something like
```ruby
ValidOptions = Struct.new(:ssl, :host, :port)
opts = ValidOptions.new
opts.port = 999
setup_request(**opts)
```

> * problem of things being _unintentionally_ unpacked, considering how many objects have `to_h` method

That never happens. I have never ever written code where `foo(**opts)` throws "no implicit conversion of Object into Hash" and then I realize I really meant to use something other than `opts`.

> (other than `**(params if condition?)`, which was actually handled).

I'll admit that `**nil` covers 90% of the benefits, but the adhoc-ness of it all is a bit frustrating.


----------------------------------------
Feature #15381: Let double splat call `to_h` implicitly
https://bugs.ruby-lang.org/issues/15381#change-110211

* Author: sawa (Tsuyoshi Sawada)
* Status: Open
----------------------------------------
The single splat calls `to_a` implicitly on the object (if it is not an array already) so that, for example, we have the convenience of writing conditions in an array literal:

```ruby
a = [
  *(:foo if some_condition),
  *(:bar if another_condition),
]
```

And the ampersand implicitly calls `to_proc` on the object (if it is not a proc already) so that we can substitute a block with an ampersand followed by a symbol:

```ruby
some_method(&:some_method_name)
```

Unlike the single splat and ampersand, the double splat does not seem to implicitly call a corresponding method. I propose that the double splat should call `to_h` implicitly on the object if it not already a Hash so that we can, for example, write a condition in a hash literal as follows:

```ruby
h = {
  **({a: 1} if some_condition),
  **({b: 2) if another_condition),
}
```

There may be some other benefits of this feature that I have not noticed yet.



-- 
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] 10+ messages in thread

* [ruby-core:119591] [Ruby master Feature#15381] Let double splat call `to_h` implicitly
       [not found] <redmine.issue-15381.20181205082504.2963@ruby-lang.org>
                   ` (5 preceding siblings ...)
  2024-10-22 19:32 ` [ruby-core:119590] " Dan0042 (Daniel DeLorme) via ruby-core
@ 2024-10-22 19:58 ` jeremyevans0 (Jeremy Evans) via ruby-core
  2024-10-22 20:20 ` [ruby-core:119592] " Dan0042 (Daniel DeLorme) via ruby-core
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: jeremyevans0 (Jeremy Evans) via ruby-core @ 2024-10-22 19:58 UTC (permalink / raw)
  To: ruby-core; +Cc: jeremyevans0 (Jeremy Evans)

Issue #15381 has been updated by jeremyevans0 (Jeremy Evans).


There are certainly backwards compatibility issues from changing `**` from calling `to_hash` to `to_h`.  I'm sympathetic to the argument that calling `to_h` fits better, as the conversion is explicit and not implicit, but the backwards compatibility costs are probably too high.  Maybe in Ruby 4?

One possible approach is defining `**@` as an operator method, something like:

```ruby
class BasicObject
  def **@ = to_hash
end
```

Using the unary `**` operator on an object would call the `**@` method, which should return a hash (or raise an exception). The method name itself is designed to be similar to `+@` and `-@`, which are called when you use the unary `+` and `-` operators.  Users could then change the `**@` method to call `to_h` instead of `to_hash` if they want, and get the explicit conversion behavior (either for all objects, or for specific objects/classes).

I proposed `*@` as the method called by the unary `*` operator in #2013, with a working patch, before `**` was introduced for keywords.  This was the first issue I filed, back in 2009.  It was eventually rejected as there was not much discussion on it, but it was still thought an interesting idea at the time it was rejected.

----------------------------------------
Feature #15381: Let double splat call `to_h` implicitly
https://bugs.ruby-lang.org/issues/15381#change-110212

* Author: sawa (Tsuyoshi Sawada)
* Status: Open
----------------------------------------
The single splat calls `to_a` implicitly on the object (if it is not an array already) so that, for example, we have the convenience of writing conditions in an array literal:

```ruby
a = [
  *(:foo if some_condition),
  *(:bar if another_condition),
]
```

And the ampersand implicitly calls `to_proc` on the object (if it is not a proc already) so that we can substitute a block with an ampersand followed by a symbol:

```ruby
some_method(&:some_method_name)
```

Unlike the single splat and ampersand, the double splat does not seem to implicitly call a corresponding method. I propose that the double splat should call `to_h` implicitly on the object if it not already a Hash so that we can, for example, write a condition in a hash literal as follows:

```ruby
h = {
  **({a: 1} if some_condition),
  **({b: 2) if another_condition),
}
```

There may be some other benefits of this feature that I have not noticed yet.



-- 
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] 10+ messages in thread

* [ruby-core:119592] [Ruby master Feature#15381] Let double splat call `to_h` implicitly
       [not found] <redmine.issue-15381.20181205082504.2963@ruby-lang.org>
                   ` (6 preceding siblings ...)
  2024-10-22 19:58 ` [ruby-core:119591] " jeremyevans0 (Jeremy Evans) via ruby-core
@ 2024-10-22 20:20 ` Dan0042 (Daniel DeLorme) via ruby-core
  2024-10-23  7:57 ` [ruby-core:119595] " zverok (Victor Shepelev) via ruby-core
  2024-10-24 11:33 ` [ruby-core:119605] " Eregon (Benoit Daloze) via ruby-core
  9 siblings, 0 replies; 10+ messages in thread
From: Dan0042 (Daniel DeLorme) via ruby-core @ 2024-10-22 20:20 UTC (permalink / raw)
  To: ruby-core; +Cc: Dan0042 (Daniel DeLorme)

Issue #15381 has been updated by Dan0042 (Daniel DeLorme).


> There are certainly backwards compatibility issues from changing `**` from calling `to_hash` to `to_h`.

What kind of backwards compatibility issues exactly? My idea was to call #to_hash and fall back to #to_h, that should ensure no backwards incompatibility at all, unless I'm missing something?

> Using the unary `**` operator on an object would call the `**@` method, which should return a hash (or raise an exception).

That's a very intriguing solution, and very elegant I have to say.

----------------------------------------
Feature #15381: Let double splat call `to_h` implicitly
https://bugs.ruby-lang.org/issues/15381#change-110213

* Author: sawa (Tsuyoshi Sawada)
* Status: Open
----------------------------------------
The single splat calls `to_a` implicitly on the object (if it is not an array already) so that, for example, we have the convenience of writing conditions in an array literal:

```ruby
a = [
  *(:foo if some_condition),
  *(:bar if another_condition),
]
```

And the ampersand implicitly calls `to_proc` on the object (if it is not a proc already) so that we can substitute a block with an ampersand followed by a symbol:

```ruby
some_method(&:some_method_name)
```

Unlike the single splat and ampersand, the double splat does not seem to implicitly call a corresponding method. I propose that the double splat should call `to_h` implicitly on the object if it not already a Hash so that we can, for example, write a condition in a hash literal as follows:

```ruby
h = {
  **({a: 1} if some_condition),
  **({b: 2) if another_condition),
}
```

There may be some other benefits of this feature that I have not noticed yet.



-- 
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] 10+ messages in thread

* [ruby-core:119595] [Ruby master Feature#15381] Let double splat call `to_h` implicitly
       [not found] <redmine.issue-15381.20181205082504.2963@ruby-lang.org>
                   ` (7 preceding siblings ...)
  2024-10-22 20:20 ` [ruby-core:119592] " Dan0042 (Daniel DeLorme) via ruby-core
@ 2024-10-23  7:57 ` zverok (Victor Shepelev) via ruby-core
  2024-10-24 11:33 ` [ruby-core:119605] " Eregon (Benoit Daloze) via ruby-core
  9 siblings, 0 replies; 10+ messages in thread
From: zverok (Victor Shepelev) via ruby-core @ 2024-10-23  7:57 UTC (permalink / raw)
  To: ruby-core; +Cc: zverok (Victor Shepelev)

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


> I think that would be awesome. If I do `other_method(**model)` and that model is representable as a hash, passing it as keyword arguments is beautiful.

...until you passed it erroneously, and it was never meant to be, and the error happened not where it should happen but in some completely different place.

...until somebody tries to make heads or tails from the legacy codebase and assumes that something that is invoked with `**value` is hash-like, while in fact, it was a value object, and there is no way to know it without chasing it back and forth by call stack.

Now, _imagine_ if that was the author’s intention (“here we unpack our model into the keyword args”) and the author just wrote (like, five more characters)
```ruby
other_method(**model.to_h)
```
...and the reader immediately sees where the “transition point” is from value object/model to keyword args/hash-like data.


> Imagine something like
> ```ruby
> ValidOptions = Struct.new(:ssl, :host, :port)
> ```

Now imagine that if you want to have such options as kwarg-passable, you can just
```ruby
ValidOptions = Struct.new(:ssl, :host, :port) { alias to_hash to_h }
```
...and that immediately communicates “this particular value object (unlike many other value objects) thinks of it as a hash-like object that would be unpacked probably at some point”.

>> problem of things being unintentionally unpacked, considering how many objects have to_h method
>
> That never happens. I have never ever written code where `foo(**opts)` throws "no implicit conversion of Object into Hash" and then I realize I really meant to use something other than opts.

I saw this a lot (especially transitioning from older to newer syntaxes, libraries, and Ruby versions). Fighting anecdata with anecdata! :)

The conversion from “it had just one extra parameter” to “it has a hash of extra parameters” is a frequent refactoring when some library matures, and I really like to have it reported to me early that some object passed where it doesn’t correspond to the target method’s expectations. `NoMethodError`/“no implicit conversion” is a wonderful tool for this, but only if it happens _in the closest place to the possible error_.

PS: Honestly, I am still not sure which _problem_ we are trying to solve (that is not covered by the `**nil` addition) that is so frequent and has no other easy solution to be worth all the drawbacks.

----------------------------------------
Feature #15381: Let double splat call `to_h` implicitly
https://bugs.ruby-lang.org/issues/15381#change-110217

* Author: sawa (Tsuyoshi Sawada)
* Status: Open
----------------------------------------
The single splat calls `to_a` implicitly on the object (if it is not an array already) so that, for example, we have the convenience of writing conditions in an array literal:

```ruby
a = [
  *(:foo if some_condition),
  *(:bar if another_condition),
]
```

And the ampersand implicitly calls `to_proc` on the object (if it is not a proc already) so that we can substitute a block with an ampersand followed by a symbol:

```ruby
some_method(&:some_method_name)
```

Unlike the single splat and ampersand, the double splat does not seem to implicitly call a corresponding method. I propose that the double splat should call `to_h` implicitly on the object if it not already a Hash so that we can, for example, write a condition in a hash literal as follows:

```ruby
h = {
  **({a: 1} if some_condition),
  **({b: 2) if another_condition),
}
```

There may be some other benefits of this feature that I have not noticed yet.



-- 
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] 10+ messages in thread

* [ruby-core:119605] [Ruby master Feature#15381] Let double splat call `to_h` implicitly
       [not found] <redmine.issue-15381.20181205082504.2963@ruby-lang.org>
                   ` (8 preceding siblings ...)
  2024-10-23  7:57 ` [ruby-core:119595] " zverok (Victor Shepelev) via ruby-core
@ 2024-10-24 11:33 ` Eregon (Benoit Daloze) via ruby-core
  9 siblings, 0 replies; 10+ messages in thread
From: Eregon (Benoit Daloze) via ruby-core @ 2024-10-24 11:33 UTC (permalink / raw)
  To: ruby-core; +Cc: Eregon (Benoit Daloze)

Issue #15381 has been updated by Eregon (Benoit Daloze).


Regarding `**@`, I'm not a big fan because `**` on the caller side is very much syntax a bit like a keyword, and it has the meaning the pass the Hash/expression as keyword arguments and not as a position argument.
Of course you could have `**` the syntax and `**@` the unary operator called by it, but effectively it's not really an operator in the sense of unary +/- or binary operators, e.g. it can only be used in calls and in Hash literals.

Regarding trying `to_hash` then `to_h` or vice-versa it will have some overhead for the second method being tried for non-Hash.

`foo(**obj.to_h)` doesn't sound too bad to me as I would expect it's needed in only a few places (compared to all `**hash` usages) and it's probably clearer what is happening that way if `obj` is not a Hash/to_hash.

----------------------------------------
Feature #15381: Let double splat call `to_h` implicitly
https://bugs.ruby-lang.org/issues/15381#change-110227

* Author: sawa (Tsuyoshi Sawada)
* Status: Open
----------------------------------------
The single splat calls `to_a` implicitly on the object (if it is not an array already) so that, for example, we have the convenience of writing conditions in an array literal:

```ruby
a = [
  *(:foo if some_condition),
  *(:bar if another_condition),
]
```

And the ampersand implicitly calls `to_proc` on the object (if it is not a proc already) so that we can substitute a block with an ampersand followed by a symbol:

```ruby
some_method(&:some_method_name)
```

Unlike the single splat and ampersand, the double splat does not seem to implicitly call a corresponding method. I propose that the double splat should call `to_h` implicitly on the object if it not already a Hash so that we can, for example, write a condition in a hash literal as follows:

```ruby
h = {
  **({a: 1} if some_condition),
  **({b: 2) if another_condition),
}
```

There may be some other benefits of this feature that I have not noticed yet.



-- 
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] 10+ messages in thread

end of thread, other threads:[~2024-10-24 11:34 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <redmine.issue-15381.20181205082504.2963@ruby-lang.org>
2023-01-17 18:11 ` [ruby-core:111859] [Ruby master Feature#15381] Let double splat call `to_h` implicitly sawa (Tsuyoshi Sawada) via ruby-core
2024-10-21 21:30 ` [ruby-core:119581] " sanjioh (Fabio Sangiovanni) via ruby-core
2024-10-22  6:12 ` [ruby-core:119585] " zverok (Victor Shepelev) via ruby-core
2024-10-22 18:10 ` [ruby-core:119588] " Dan0042 (Daniel DeLorme) via ruby-core
2024-10-22 18:37 ` [ruby-core:119589] " zverok (Victor Shepelev) via ruby-core
2024-10-22 19:32 ` [ruby-core:119590] " Dan0042 (Daniel DeLorme) via ruby-core
2024-10-22 19:58 ` [ruby-core:119591] " jeremyevans0 (Jeremy Evans) via ruby-core
2024-10-22 20:20 ` [ruby-core:119592] " Dan0042 (Daniel DeLorme) via ruby-core
2024-10-23  7:57 ` [ruby-core:119595] " zverok (Victor Shepelev) via ruby-core
2024-10-24 11:33 ` [ruby-core:119605] " Eregon (Benoit Daloze) 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).