From: "cb341 (Daniel Bengl) via ruby-core" Date: 2025-08-26T06:37:03+00:00 Subject: [ruby-core:123073] [Ruby Feature#21545] #try_dig, a dig that returns early if it cannot dig deeper Issue #21545 has been updated by cb341 (Daniel Bengl). Dan0042 (Daniel DeLorme) wrote in #note-6: > I have never seen an API that can return either a string `"ok"` or a hash `{ code: 200 }` > Maybe the API status example is not the best suited one for `try_dig`. It has been my observation that in certain cases APIs can return various types on a given path. `try_dig` would be used in the case that you are only concerned by a specific case, where the long path exists and you can dig while dismissing the other cases. > Swallowing exceptions like that seems very dangerous to me, not a pattern we should have in ruby core. > I agree with you that Exception swallowing in the core might not be the best idea, so I'll rather propose this to ActiveSupport. > It seems to be functionally the same as `api_response.dig(:status, :code) rescue nil`... After further examination my proposed implementation of `rescue StandardError`, `return nil` is functionally identical to `rescue nil`. > ...what's the difference or advantage? Why shouldn't we have an alias for this behavior? ActiveSupport defines many aliases such as present?: ```rb # An object is present if it's not blank. # # @return [true, false] def present? !blank? end ``` https://github.com/rails/rails/blob/main/activesupport/lib/active_support/core_ext/object/blank.rb#L22C1-L27C6 Also if `dig!` would be introduced (#12282, #15563), it'd make sense to also introduce a rescue behaving `dig`. ---------------------------------------- Feature #21545: #try_dig, a dig that returns early if it cannot dig deeper https://bugs.ruby-lang.org/issues/21545#change-114386 * Author: cb341 (Daniel Bengl) * Status: Open ---------------------------------------- Ruby offers `dig` for traversing nested hashes and arrays. It is strict and will raise if an intermediary object does not support `dig`. In many cases we only want to attempt the lookup and return `nil` if it cannot be followed, without caring about the exact reason. **Example:** ```rb { a: "foo" }.dig(:a, :b) # TypeError: String does not have #dig method { a: "foo" }.try_dig(:a, :b) # => nil ``` This is especially useful when dealing with data from APIs or other inconsistent sources: ```rb api_response = { status: "ok" } api_response.try_dig(:status, :code) # => nil api_response = { status: { code: 200 } } api_response.try_dig(:status, :code) # => 200 ``` The name `try_dig` makes it clear that it behaves like `dig` but will never raise for structural mismatches. It complements `dig` and the proposed `dig!` ([#12282](https://bugs.ruby-lang.org/issues/12282), [#15563](https://bugs.ruby-lang.org/issues/15563)) by covering the tolerant lookup case. A possible sketch: ```rb class Object def try_dig(*path) current = self path.each do |key| return nil unless current.respond_to?(:dig) begin current = current.dig(key) rescue StandardError return nil end end current end end ``` _I initially proposed this in Ruby core ([PR #14203](https://github.com/ruby/ruby/pull/14203)) and even implemented it in C, but later realized that if this gets introduced at all it probably makes more sense to have it in ActiveSupport rather than in core Ruby._ **Advantages** - Simplifies tolerant lookups without repetitive rescue logic - Clear intent when the value is optional - Useful for working with inconsistent or partially known data structures - Complements `dig` and potential `dig!` by covering the tolerant case **Disatvantages** - May hide structural issues that should be noticed during development -- 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/