[#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:109772] [Ruby master Feature#18959] Handle gracefully nil kwargs eg. **nil

From: "austin (Austin Ziegler)" <noreply@...>
Date: 2022-08-29 14:17:29 UTC
List: ruby-core #109772
Issue #18959 has been updated by austin (Austin Ziegler).


LevLukomskyi (Lev Lukomskyi) wrote in #note-25:
> > 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.
> 
> When you pass `nil` you make less allocations, also you don't need to put `|| {}` at all calling sites. For an options which are just passed somewhere else inside the method it's a valid usage.

You don’t need to put `|| {}` at all calling sites. The method and its documentation should be very clear that, if provided, the second parameter must be a Hash. That is, passing `nil` should be discouraged. Or you make the specific case that you want `nil` to *clear* the tracking info, in which case you probably shouldn’t be using `|| {}` or `**kwargs` at all.

There may be value in `**nil => {}`, but I repeat that the examples you have provided are unconvincing, but are instead *likely* to have unintended side effects, especially as the examples you’ve given seem to be AR-ish in nature, and converting a hash to kwargs is not likely what you actually want with Active Record.

> > I suspect that it can’t be optimized easily, because arbitrarily complex expressions can be specified after `if` or `unless`.
> 
> I think it doesn't matter how complex condition there is, because the interpreter must fully evaluate it first anyway to check whether `if` is satisfied, then if the expression inside `if` is `{...}` and `**` operation is pending – just store entries in stack, not heap, and pass them to `**`. One more optimization could be to avoid creating an empty hash on `**nil`.

Such an optimization might be possible (or more likely detecting `**nil` and doing nothing).

> > I think that it’s *generally* a better change for the examples you have provided than `**nil` support.
> 
> Actually that's not consistent that you are ok for `merge(nil)` but not ok for `add_email_to_list(tracking_info: nil)` which is kind of the same.

Sure it is. The signature for `#merge` is `#merge(*hashes, &block)`, so the pseudo-code implementation could easily be:

```ruby
class Hash
  def merge(*hashes, &block)
    hashes.each do |hash|
      next if hash.nil?
      # … do merge magic and conflict resolution if block has been given here
    end
  end
end
```

Or, if you prefer

```ruby
class Hash
  def merge(*hashes, &block)
    hashes.compact.each do |hash|
      # … do merge magic and conflict resolution if block has been given here
    end
  end
end
```

Both of these options permit the "clever" code you’d eventually come to regret, but do so cleanly.

> 
> > 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 the way with `delete_if` is clearer since you mentally are doing two operations – first insert values into hash, and then remove them. In case of `**` you are doing only one operation – insert values.

You’re looking at the concept of a `#default_options` method wrong. You’re not inserting values in the hash, you’re merging the *provided* values with defaults.

Elixir has a function `Keyword.validate/2` that is called as `Keyword.validate(options, default_options)` and it ensures that the keyword list *only* has the keys present in `default_options` and that if those keys are missing, they’re set with the provided default value. This is more or less the same for mutable objects, and one additional step: having a way of removing values that should be omitted if not provided. I’ve done very similar things in JavaScript as well. The pattern is simple: `default_options.merge(*provided_options_list).delete_if { |h, k| omit_default?(h, k) }`. The use of `#merge` is intentional, because you don’t want to update the defaults (should they be stored in a constant), although `default_options.dup.update(*provided_option_list).delete_if {|h, k| omit_default?(h, k) }` would work as well. 

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

* 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

Prev Next