From: "zverok (Victor Shepelev) via ruby-core" <ruby-core@ml.ruby-lang.org>
To: ruby-core@ml.ruby-lang.org
Cc: "zverok (Victor Shepelev)" <noreply@ruby-lang.org>
Subject: [ruby-core:119595] [Ruby master Feature#15381] Let double splat call `to_h` implicitly
Date: Wed, 23 Oct 2024 07:57:18 +0000 (UTC) [thread overview]
Message-ID: <redmine.journal-110217.20241023075718.2963@ruby-lang.org> (raw)
In-Reply-To: <redmine.issue-15381.20181205082504.2963@ruby-lang.org>
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/
next prev parent reply other threads:[~2024-10-23 7:57 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <redmine.issue-15381.20181205082504.2963@ruby-lang.org>
2023-01-17 18:11 ` [ruby-core:111859] " 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 ` zverok (Victor Shepelev) via ruby-core [this message]
2024-10-24 11:33 ` [ruby-core:119605] " Eregon (Benoit Daloze) via ruby-core
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=redmine.journal-110217.20241023075718.2963@ruby-lang.org \
--to=ruby-core@ml.ruby-lang.org \
--cc=noreply@ruby-lang.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).