The name that feels natural to me would be `sequentiallyEquals`. I don't 
dispute that the term "lexicographical" is used correctly here, although at 
least for me personally, it's not a word that I encounter frequently enough to 
understand what this method would do without reading the documentation. Like 
Kevin, if I were to guess what the method did without checking, I would 
probably think that it compared lexicographically-sorted versions of the 
collections.

But the consistency with `lexicographicallyPrecedes` is a pretty strong 
argument, although `sequentiallyPrecedes` would also feel more natural to me 
there, and my suspicion about the mentioned lack of evidence that the method 
has been a pitfall for users is that it's not actually used often enough out in 
the wild to have heard much about it. That's just a guess though. This proposal 
is the first time I've learned of its existence.

In any case, my ideal version of this proposal would use `sequentiallyEquals` 
and also rename `lexicographicallyPrecedes` to `sequentiallyPrecedes`, but I 
still like the proposal overall as-is. Thanks for bringing it forward!

Jarod

On Oct 12, 2017, 16:24 -0700, Xiaodi Wu via swift-evolution 
<swift-evolution@swift.org>, wrote:
> Rename Sequence.elementsEqual
>
> • Proposal: SE-NNNN
> • Authors: Xiaodi Wu
> • Review Manager: TBD
> • Status: Awaiting review
>
> Introduction
> The current behavior of Sequence.elementsEqual is potentially confusing to 
> users given its name. Having surveyed the alternative solutions to this 
> problem, it is proposed that the method be renamed to 
> Sequence.lexicographicallyEquals.
> Motivation
> As outlined by Ole Begemann, use of Sequence.elementsEqual(_:) can lead to 
> surprising results if the sequences compared are unordered:
> var set1: Set<Int> = Set(1...5)
> var set2: Set<Int> = Set((1...5).reversed())
>
> set1 == set2 // true
> set1.elementsEqual(set2) // false
> This result does reflect the intended and documented behavior of the 
> elementsEqual(_:) method, which performs a lexicographical elementwise 
> comparison. That is, the method first compares set1.first to set2.first, then 
> (if the two elements compare equal) compares the next element stored 
> internally in set1 to the next element stored internally in set2, and so on.
> In almost all circumstances where a set is compared to another set, or a 
> dictionary is compared to another dictionary, users should use == instead of 
> elementsEqual(_:).
> Proposed solution
> The proposed solution is the result of an iterative process of reasoning, 
> presented here:
> The first and most obvious solution is to remove the elementsEqual(_:) method 
> altogether in favor of ==. This prevents its misuse. However, because 
> elementsEqual(_:) is a generic method on Sequence, we can use it to compare 
> an instance of UnsafeBufferPointer<Int> to an instance of [Int]. This is a 
> useful and non-redundant feature which would be eliminated if the method is 
> removed altogether.
> A second solution is to create overloads that forbid the use of the 
> elementsEqual(_:) method specifically in non-generic code. This would prevent 
> misuse in non-generic code; however, it would also forbid legitimate 
> mixed-type comparisons in non-generic code while failing to prevent misuse in 
> generic code. The solution also creates a difference in the behavior of 
> generic and non-generic code calling the same method, which is potentially 
> confusing, without solving the problem completely.
> A third solution is to dramatically overhaul the protocol hierarchy for Swift 
> sequences and collections so that unordered collections no longer have 
> members such as first and elementsEqual(_:). However, this would be a 
> colossal and source-breaking undertaking, and it is unlikely to be 
> satisfactory in addressing all the axes of differences among sequence and 
> collection types:
>
> • Finite versus infinite
> • Single-pass versus multi-pass
> • Ordered versus unordered
> • Lazy versus eager
> • Forward/bidirectional/random-access
>
> A fourth solution is proposed here. It is predicated on the following 
> observation:
> Another method similar to elementsEqual(_:) already exists on Sequence named 
> lexicographicallyPrecedes(_:). Like first, elementsEqual(_:), drop(while:), 
> and others, it relies on the internal order of elements in a manner that is 
> not completely suitable for an unordered collection. However, like first and 
> unlike elementsEqual(_:), this fact is called out in the name of the method; 
> unsurprisingly, like first and unlike elementsEqual(_:), there is no evidence 
> that lexicographicallyPrecedes(_:) has been a pitfall for users.
> This observation suggests that a major reason for confusion over 
> elementsEqual(_:) stems from its name. So, it is proposed that 
> elementsEqual(_:) should be renamed to lexicographicallyEquals(_:). The 
> function will remain somewhat of a poor fit for unordered collections, but no 
> more so than many other methods that cannot trivially be removed from the API 
> of unordered collections (as discussed above). The key is that, with such a 
> renaming, the behavior of this method will no longer be confusing.
> Detailed design
> extension Sequence where Element : Equatable {
> @available(*, deprecated, message: "Use '==' if possible to compare two 
> sequences of the same type, or use 'lexicographicallyEquals' to compare two 
> ordered sequences.")
> public func elementsEqual<Other : Sequence>(
>    _ other: Other
>  ) -> Bool where Other.Element == Element {
>    return lexicographicallyEquals(other)
>  }
>
> public func lexicographicallyEquals<Other : Sequence>(
>    _ other: Other
>  ) -> Bool where Other.Element == Element {
>    // The body of this method is unchanged.
>    var iter1 = self.makeIterator()
>    var iter2 = other.makeIterator()
>    while true {
>      switch (iter1.next(), iter2.next()) {
>      case let (e1?, e2?):
>        if e1 != e2 { return false }
>      case (_?, nil), (nil, _?):
>        return false
>      case (nil, nil):
>        return true
>      }
>    }
>  }
> }
> A parallel change will be made with respect to elementsEqual(_:by:); that is, 
> it will be deprecated in favor of lexicographicallyEquals(_:by:).
> Source compatibility
> Existing code that uses elementsEqual will gain a deprecation warning.
> Effect on ABI stability
> None.
> Effect on API resilience
> This proposal adds new methods to the public API of Sequence and conforming 
> types.
> Alternatives considered
> It is to be noted that lexicographicallyPrecedes(_:by:) and 
> elementsEqual(_:by:) are essentially the same method, since both perform a 
> lexicographical comparison using a custom predicate. However, there is not a 
> good unifying name. (lexicographicallyCompares(to:by:) reads poorly.) 
> Moreover, the predicate supplied is intended to have very different 
> semantics, and maintaining two distinct methods may be a superior fit with 
> the typical user's mental model of the intended behavior and may also be 
> clearer to readers of the code. Therefore, this proposal does not seek to 
> unify the two methods; instead, elementsEqual(_:by:) will be renamed 
> lexicographicallyEquals(_:by:) as detailed above.
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to