Project

General

Profile

Actions

Feature #20812

closed

Proposal for Safe Include Method in Ruby

Feature #20812: Proposal for Safe Include Method in Ruby

Added by rogerconsul (Roger Consul) about 1 year ago. Updated about 1 year ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:119606]

Description

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.

# 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:

module Enumerable def include_safe?(obj) return false if obj.nil? include?(obj) end end 

Usage Examples

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:

module Enumerable def include_safe?(obj) return false if obj.nil? include?(obj) end end 

Testing Strategy

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?

Updated by jeremyevans0 (Jeremy Evans) about 1 year ago Actions #1 [ruby-core:119607]

rogerconsul (Roger Consul) wrote:

The current include? method raises an error when passed nil as an argument.

Are you sure?

# 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?

Updated by rogerconsul (Roger Consul) about 1 year ago Actions #2 [ruby-core:119608]

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?

# 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

Updated by jeremyevans0 (Jeremy Evans) about 1 year ago Actions #3

  • Status changed from Open to Closed
Actions

Also available in: PDF Atom