[#109403] [Ruby master Feature#18951] Object#with to set and restore attributes around a block — "byroot (Jean Boussier)" <noreply@...>

Issue #18951 has been reported by byroot (Jean Boussier).

23 messages 2022/08/01

[#109423] [Ruby master Misc#18954] DevMeeting-2022-08-18 — "mame (Yusuke Endoh)" <noreply@...>

Issue #18954 has been reported by mame (Yusuke Endoh).

10 messages 2022/08/04

[#109449] [Ruby master Feature#18959] Handle gracefully nil kwargs eg. **nil — "LevLukomskyi (Lev Lukomskyi)" <noreply@...>

Issue #18959 has been reported by LevLukomskyi (Lev Lukomskyi).

27 messages 2022/08/08

[#109456] [Ruby master Bug#18960] Module#using raises RuntimeError when called at toplevel from wrapped script — "shioyama (Chris Salzberg)" <noreply@...>

Issue #18960 has been reported by shioyama (Chris Salzberg).

15 messages 2022/08/09

[#109550] [Ruby master Feature#18965] Further Thread::Queue improvements — "byroot (Jean Boussier)" <noreply@...>

Issue #18965 has been reported by byroot (Jean Boussier).

14 messages 2022/08/18

[#109575] [Ruby master Bug#18967] Segmentation fault in stackprof with Ruby 2.7.6 — "RubyBugs (A Nonymous)" <noreply@...>

Issue #18967 has been reported by RubyBugs (A Nonymous).

10 messages 2022/08/19

[#109598] [Ruby master Bug#18970] CRuby adds an invalid header to bin/bundle (and others) which makes it unusable in Bash on Windows — "Eregon (Benoit Daloze)" <noreply@...>

Issue #18970 has been reported by Eregon (Benoit Daloze).

17 messages 2022/08/20

[#109645] [Ruby master Bug#18973] Kernel#sprintf: %c allows codepoints above 127 for 7-bits ASCII encoding — "andrykonchin (Andrew Konchin)" <noreply@...>

Issue #18973 has been reported by andrykonchin (Andrew Konchin).

8 messages 2022/08/23

[#109689] [Ruby master Misc#18977] DevMeeting-2022-09-22 — "mame (Yusuke Endoh)" <noreply@...>

Issue #18977 has been reported by mame (Yusuke Endoh).

16 messages 2022/08/25

[#109707] [Ruby master Feature#18980] Re-reconsider numbered parameters: `it` as a default block parameter — "k0kubun (Takashi Kokubun)" <noreply@...>

Issue #18980 has been reported by k0kubun (Takashi Kokubun).

40 messages 2022/08/26

[#109756] [Ruby master Feature#18982] Add an `exception: false` argument for Queue#push, Queue#pop, SizedQueue#push and SizedQueue#pop — "byroot (Jean Boussier)" <noreply@...>

Issue #18982 has been reported by byroot (Jean Boussier).

11 messages 2022/08/29

[#109773] [Ruby master Misc#18984] Doc for Range#size for Float/Rational does not make sense — "masasakano (Masa Sakano)" <noreply@...>

Issue #18984 has been reported by masasakano (Masa Sakano).

7 messages 2022/08/29

[ruby-core:109745] [Ruby master Feature#18959] Handle gracefully nil kwargs eg. **nil

From: "austin (Austin Ziegler)" <noreply@...>
Date: 2022-08-28 05:15:28 UTC
List: ruby-core #109745
Issue #18959 has been updated by austin (Austin Ziegler).


LevLukomskyi (Lev Lukomskyi) wrote in #note-22:
> > I also tend to do `**(options || {})` and I don’t write hard-to-read code like `**({id: id, name: name} if id.present?)`.

> That's interesting, that you are ok for
> ```ruby
> **(options || {})
> ```
> but not ok for
> ```ruby
> **(options if condition)
> ```
> which is kind of the same..

I disagree that it’s the same, but more to the point, I mistyped: I tend **not** to do `**(options || {})`. I disagree that it’s the same because putting an `if` expression *in a parameter position* is less immediately readable than `||` or a ternary.

> > I’d write that as:
> > 
> > ```ruby
> > def add_email_to_list(email:, tracking_info: {})
> >   EmailSubscriber.find_by(email: email) || EmailSubscriber.new(email: email, **tracking_info)
> > end
> > ```
> 
> This does not solve the issue, the method still can be called with `nil` eg.:
> ```ruby
> add_email_to_list(email: 'email@example.com', tracking_info: nil)
> ```
>
> and it'll raise the error, so you still need that boilerplate code `**(tracking_info || {})`

No, you don’t. You need to fail when someone passes you garbage (and `nil` is a garbage value in this case), or you need to ensure better default values (e.g., `{}`) at your call sites. I‘m not sure that `**nil` converting to `{}` is sensible behaviour, given that—especially since `**` uses implicit conversion (`#to_hash`) instead of explicit conversion (`#to_h`).

> > the example you’ve given is completely unconvincing because it is suboptimal, has unnecessary allocations, and is more reminiscent of what I’d see from Perl in 1998 than Ruby of 2022.
> that's true, it has an additional allocation if condition is satisfied, although it's not critical in most cases. Also, it could be probably optimized by interpreter in the future, similar to how `[3, 5].max` is optimized.

I suspect that it can’t be optimized easily, because arbitrarily complex expressions can be specified after `if` or `unless`.

> > 1. If we want to allow `**nil`, the argument should be made to switch `**` from calling `#to_hash` to calling `#to_h`, because that would give you `**nil` _for free_. That would require digging a bit deeper to determine why `**` calls `#to_hash` instead of `#to_h`.
> 
> Agree, `to_hash` method is weird, and it just adds confusion to people about why there are both `to_hash` and `to_h`, and which one they should use. I think `to_hash` should be deprecated and later removed.

It’s present of the same reason that `#to_ary` and `#to_a` are present. `#to_hash` implies "this object *is* a hash", whereas `#to_h` says "this object can be converted to a hash".

> BTW the issue with `**nil` can be also fixed by this code:
> 
> ```ruby
> class NilClass; alias to_hash to_h end
> ```

That introduces other problems because of implicit hash coercion.

> > 2. `Hash#merge` and `Hash#update` could be modified to ignore `nil` arguments (which would permit your use-case).
> 
> Agree, doing nothing on `.merge(nil)` would be good. It will remove redundant allocations like
> ```ruby
> hash.merge(other_hash_param || {})
> ```
>
> Although I guess it's a more radical change..

I think that it’s *generally* a better change for the examples you have provided than `**nil` support.

> One note though, your example:
>
> ```ruby
> { some: 'value' }.merge({ id: id, name: name } if id.present?)
> ```
>
> won't work as you expect, it raises _SyntaxError: unexpected ')', expecting end-of-input_
>
> The valid way would be:
> ```ruby
> { some: 'value' }.update(({ id: id, name: name } if id.present?))
> ```
>
> which looks not so nice..

Fair, but I’ll note that I was adapting your example. I would *never* write code where I use an `if` inline. If we extended the concept for `#merge` to ignore `false` or `nil` values, then we could write it as

```ruby
{some: 'value'}.update(id.present? && {id: id, name: name})
```

I’m still not fond of the pattern, and think that an explicit call to `Hash#delete_if` to remove defaulted values is clearer and more intentional, but whatever.

I *don’t* think that, in general, `**nil` is a good pattern to permit. There’s an easy fix to it by using `#to_h` instead of `#to_hash`, if it turns out to be a good pattern. More than that, I think that we need a *better* use case to demonstrate its need than has been shown to date, because the patterns that have been presented so far are (IMO) unconvincing.

----------------------------------------
Feature #18959: Handle gracefully nil kwargs eg. **nil
https://bugs.ruby-lang.org/issues/18959#change-98982

* Author: LevLukomskyi (Lev Lukomskyi)
* Status: Open
* Priority: Normal
----------------------------------------
The issue:

```ruby
def qwe(a: 1) end

qwe(**nil) #=> fails with `no implicit conversion of nil into Hash (TypeError)` error

{ a:1, **nil } #=>  fails with `no implicit conversion of nil into Hash (TypeError)` error
```

Reasoning:

I found myself that I often want to insert a key/value to hash if a certain condition is met, and it's very convenient to do this inside hash syntax, eg.:

```ruby
{
  some: 'value',
  **({ id: id } if id.present?),
}
```

Such syntax is much more readable than:

```ruby
h = { some: 'value' }
h[:id] = id if id.present?
h
```

Yes, it's possible to write like this:

```ruby
{
  some: 'value',
  **(id.present? ? { id: id } : {}),
}
```

but it adds unnecessary boilerplate noise.

I enjoy writing something like this in ruby on rails:

```ruby
content_tag :div, class: [*('is-hero' if hero), *('is-search-page' if search_page)].presence
```

If no conditions are met then the array is empty, then converted to nil by `presence`, and `class` attribute is not rendered if it's nil. It's short and so convenient! There should be a similar way for hashes!

I found this issue here: https://bugs.ruby-lang.org/issues/8507 where "consistency" thing is discussed. While consistency is the right thing to do, I think the main point here is to have fun with programming, and being able to write stuff in a concise and readable way.

Please, add this small feature to the language, that'd be so wonderful! 🙏



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>

In This Thread