From: "jeremyevans0 (Jeremy Evans) via ruby-core" Date: 2024-10-24T13:10:23+00:00 Subject: [ruby-core:119607] [Ruby master Feature#20812] Proposal for Safe Include Method in Ruby Issue #20812 has been updated by jeremyevans0 (Jeremy Evans). 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`? ---------------------------------------- Feature #20812: Proposal for Safe Include Method in Ruby https://bugs.ruby-lang.org/issues/20812#change-110228 * 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/