From: "rogerconsul (Roger Consul) via ruby-core" Date: 2024-10-24T13:19:43+00:00 Subject: [ruby-core:119608] [Ruby master Feature#20812] Proposal for Safe Include Method in Ruby Issue #20812 has been updated by rogerconsul (Roger Consul). jeremyevans0 (Jeremy Evans) wrote in #note-1: > rogerconsul (Roger Consul) wrote: > > The current `include?` method raises an error when passed `nil` as an argument. > > Are you sure? > > ```ruby > # No Error > [1, 2].include?(nil) > [Object.new].include?(nil) > > # Error, but due to custom ==, not include? > o = Object.new > def o.==(v) = (raise unless v) > [o].include?(nil) > ``` > > Maybe you are using some core extension that causes `include?` to raise an error if given `nil`? Can you provide a self-contained reproducible example that shows `include?` raising if the argument is `nil`? Well... After you mentioned it, I realized we were using version 2.7.5 ���� Error didn't reproduce on newer versions. We can close this thread. Thanks for your time, Jeremy <3 ---------------------------------------- Feature #20812: Proposal for Safe Include Method in Ruby https://bugs.ruby-lang.org/issues/20812#change-110229 * Author: rogerconsul (Roger Consul) * Status: Open ---------------------------------------- # Proposal for Safe Include Method in Ruby ## Description Add a new method `include_safe?` to Ruby's `Enumerable` module that safely handles nil arguments in inclusion checks. ## Problem Statement The current `include?` method raises an error when passed `nil` as an argument. This requires developers to write defensive code with explicit nil checks, leading to less readable and more error-prone code. ```ruby # Current problematic scenarios: collection.include?(nil) # Works, checks for nil in collection collection.include?(value) # Raises error if value is nil # Current workarounds: value && collection.include?(value) collection.include?(value.to_s) ``` ## Proposed Solution Add `include_safe?` method that returns `false` when the argument is `nil`: ```ruby module Enumerable def include_safe?(obj) return false if obj.nil? include?(obj) end end ``` ### Usage Examples ```ruby numbers = [1, 2, 3] document_id = nil # Current approach document_id && numbers.include?(document_id) # false # Proposed approach numbers.include_safe?(document_id) # false # Works normally for non-nil values numbers.include_safe?(2) # true numbers.include_safe?(4) # false # Edge cases handled [nil].include_safe?(nil) # false [].include_safe?(nil) # false ``` ## Benefits 1. **Improved Safety**: Eliminates a common source of runtime errors 2. **Better Readability**: Removes need for explicit nil checks 3. **Consistent Behavior**: Provides predictable handling of nil values 4. **Rails Alignment**: Similar to Rails' safe navigation patterns 5. **Reduced Boilerplate**: Eliminates common defensive coding patterns ## Implementation Notes This would be implemented in C as part of Ruby's core, but here's a Ruby reference implementation: ```ruby module Enumerable def include_safe?(obj) return false if obj.nil? include?(obj) end end ``` ## Testing Strategy ```ruby require 'minitest/autorun' class TestIncludeSafe < Minitest::Test def setup @array = [1, 2, 3] @array_with_nil = [1, nil, 3] end def test_basic_inclusion assert @array.include_safe?(1) refute @array.include_safe?(4) end def test_nil_handling refute @array.include_safe?(nil) refute @array_with_nil.include_safe?(nil) end def test_empty_collection refute [].include_safe?(nil) refute [].include_safe?(1) end end ``` ## Alternative Considerations 1. **Name Alternatives**: - `try_include?` - `safe_include?` - `includes_safely?` 2. **Alternative Approaches**: - Modify existing `include?` behavior (rejected due to backward compatibility) - Add parameter to existing `include?` (rejected for clarity) ## Impact Analysis ### Positive Impact - Reduces runtime errors - Improves code readability - Follows principle of least surprise ### Potential Concerns - Another method to learn - Possible confusion with regular `include?` ## Similar Features in Ruby - Safe navigation operator (`&.`) - `try` method in Rails - `fetch` method with default value ## Backward Compatibility This change is fully backward compatible as it introduces a new method without modifying existing behavior. ## Reference Implementation A gem implementing this feature is available at: [Link to gem if created] ## Questions for Core Team 1. Is `include_safe?` the best name for this method? 2. Should this be added to `Array` specifically rather than `Enumerable`? 3. Should we consider any additional edge cases? -- 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/