From: "mame (Yusuke Endoh) via ruby-core" Date: 2024-08-02T01:20:51+00:00 Subject: [ruby-core:118776] [Ruby master Misc#20509] Document importance of #to_ary and #to_hash for Array#== and Hash#== Issue #20509 has been updated by mame (Yusuke Endoh). As you may know, but for the record, I add just some background. The rationale for `to_ary` is a compromise between duck typing and efficiency. Following the principles of duck typing, a method that accepts an Array should access its argument via methods such as `#size`, `#[]`, `#each`, etc. However, this is too inefficient for builtin methods that are implemented in C. So, C methods access their arguments in a way that depends on the implementation details of the Array, such as `RARRAY_LEN`. Then, the C method cannot accept an non-Array object that behaves as an Array. So, the protocol of `to_ary` was introduced: an object that behaves as an Array implements `#to_ary`; C methods that accept an Array will attempt to convert them using `#to_ary` if the argument is not an Array. This allows both duck typing and efficiency. This means that an object that implements `#to_ary` is supposed to have their other methods also behave Array-compatible to a reasonable extent. I have heard this several times from matz, but am not sure if it is documented. At least it wasn't in doc/implicit_conversion.rdoc. I think this should be added. In the case of this ticket, this `to_ary` protocol is applied in a different way. `Array#==(other)` delegates to `other == self`, because the fact that `other` implements `#to_ary` implies that `other`'s `==` must behave as `Array#==`. This is because calling `to_ary` is likely to generate an array, but `other`'s `==` may be implemented to compare arrays without generating an array. ---------------------------------------- Misc #20509: Document importance of #to_ary and #to_hash for Array#== and Hash#== https://bugs.ruby-lang.org/issues/20509#change-109330 * Author: gettalong (Thomas Leitner) * Status: Open ---------------------------------------- Both `Array#==` and `Hash#==` provide special behaviour in case the `other` argument is not an Array/Hash but defines the special `#to_ary`/`#to_hash` methods. Those methods are never called, they are just checked for existence. And if they exist, `other#==` is called to allow the `other` argument to decide whether the two objects are equal. I think this is worth mentioning in the documentation for `Array#==` and `Hash#==`. [Background: In my PDF library HexaPDF I have defined two classes `PDFArray` and `Dictionary` which act like Array and Hash but provide special PDF specific behaviour. For PDFArray I defined the `#to_ary` method but for Dictionary just the `#to_h` method. I have come across a bug where comparing Arrays with PDFArrays just works as it should be but comparing Hashes with Dictionaries doesn't due to the absence of `#to_hash` (it seems I removed `Dictionary#to_hash` in 2017 due to problems with automatic destructuring when passing a Dictionary as argument; from what I see that should be no problem anymore, so I will just add it back).] -- 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/