SE-0494: Add `isIdentical(to:)` Methods for Quick Comparisons to Concrete Types

Just to give credit where it's due, @QuinceyMorris put forward isTriviallyIdentical(to:) above last week:

5 Likes

Yes, sorry, I didn't mean to say it hadn't been discussed at all. Several ideas were proposed at around the same time, and the LSG would like to get more focused feedback about this one in particular. I've edited my post.

3 Likes

SGTM! Could you please tell me what your expectations are for the following week? Is this a "run off" week where we debate isTriviallyIdentical(to:) against isIdentical(to:)? Or are we assuming that isIdentical(to:) is off the table for now and we focus only on debating the pros and cons of isTriviallyIdentical(to:) in isolation?

If we do ship this proposal under a different name has LSG also discussed if this same proposal then gives us the ability to deprecate the existing isIdentical(to:) methods on the Span family and adopt the new name over there on the next toolchain? I guess this could be its own separate proposal… but I think it might also save us some time if we make the decision here for a different name that this proposal itself is then all we need to ship the new name across Span.

We made a special exception here to the general rule that proposals must attach working implementations before review begins. This enabled us to add the String View families without implementations at this time.

Is the expectation that these new types are also being proposed without working implementations attached at this time? And this is something we understand can be built in the future after a potential approval has been made?

2 Likes

We'd like feedback around the ideas we raised:

  • how do people feel about isTriviallyIdentical(to:),
  • whether people agree that these are important things to emphasize,
  • whether people feel that other names would convey these points better,
  • etc.

The LSG has not reached a decision about renaming the Span methods, so feedback about them would be appreciated. Karoy's sentiment that these names should remain consistent is well-taken, but the idea has also been raised that perhaps Span is just different.

The LSG is not at all concerned about the implementability of any of these operations, so we are making an exception to the normal evolution process requirement of an implementation.

2 Likes

Hmm… but then if we do add this operation — whatever the name is — to UTF8Span then we probably do want to have an answer for what happens to the existing Span types. If UTF8Span ships isIdentical(to:) and String et al ship isTriviallyIdentical(to:)… that might not be The End of the World. But it might look kind of funky if we ship isTriviallyIdentical(to:) on UTF8Span without migrating the existing Span types. Right?

1 Like

If we decided to not change Span, one of the things we would need to decide is which types should follow Span and which should use the new method name, yes. The LSG is looking for input on this.

I personally do not think that there is an important distinction to draw between Span and the other types, so I favor consistency and therefore renaming the methods on Span. However, that is my opinion, not an official position of the LSG.

4 Likes

I feel isTriviallyIdentical(to:) consistent. While the word Trivially isn’t felt clear enough if I wasn’t a participant of this review, the overall meaning of the function is understood like isIdentical. So at least the word Trivially doesn’t introduce any syntatical noise like known in isKnownIdentical. At the same time I agree that such term handles important aspects listed by LSG:

  • it is felt quite far from equality check
  • trivial hints to something quick / fast

For me, as for one who read the proposal and clarifications during review, trivial is also associated with the following:

  • it is something near representation by meaning, but not a representation and it is clear and explicit.
  • the operation itself is very type specific
  • if it returns true then “it approaches substitutability from an operational angle, based on the public API surface“
  • it is something about comparing underlying imp details in a quick way without breaking encapsulation, particularly these comments:
    • “distinguish them from copies without breaking encapsulation”
    • “we simply have to compare all direct stored properties through isIdentical(to:), ===, bitPattern comparisons, or regular == invocations, as needed.“

If this term will finally be picked, I would prefer deprecation of current isIdentical(to:) defined for Span types and underscored _isKnownIdentical(to:) defined for String, for consistency.

3 Likes

How does this relate to the historical use of “trivial” to describe bitwise-copyable types without deinitializers? I can understand how someone familiar with that use of “trivial” would assume that isTriviallyIdentical(to:) must be implemented along the lines of memcmp.

1 Like

I think that's a fine name!

Please do remember to update the isIdentical operations on the span types that we shipped in Swift 6.2.

4 Likes

My own personal opinion is that there's a loose analogy here that sort of works. Consider two Arrays. Those would normally be compared by comparing their elements. But the "is trivially identical" check is comparing them almost as if they were trivial values—the bits of the underlying pointer rather than the actual data therein.

While we don't want to say that all implementations of this function must be implemented as some sort of memcmp or bitwise comparison, it's often the case that many will be implemented in that way (or otherwise by comparing simple fields as trivial values, like a slice comparing a base pointer and a count). So I think there's some subtle wordplay here that lines up nicely.

5 Likes

Agree here. If such a “trivial” check returns true, then two instances are identical / undistinguishable. If so, there are definitely no reasons for doing heavy(slow) equality check, as their underlying guts are, sorry for tautology, identical. It even handles that the type itself is not ‘trivial‘ but is able for “isIdentical” check by some trivial (and then constant time / fast) operations, and it has some incapsulated underlying guts that can represent identity.
If it returns false, then two instances can still be equal with ==, and String’s == comes to mind – two Strings can be not identical but at the level of comparing grapheme clusters can be equal. The words really play well here.
I’m really glad that during the proposal review we all managed to reduce all the debates and nuances with goals, semantics and imp differences to this combination of words. Such victories make Swift a great language with pleasant, clear and polished api.

So, as a term of art, isTriviallyIdentical guides to the right direction of thinking and understanding.

2 Likes

Love the updated isTriviallyIdentical name :+1: much more specific and clearly suggests the O(1) nature of the check.

1 Like

I like isTriviallyIdentical(to:).

I’m in favor of renaming existing Span method too. In general, isTriviallyIdentical is a more accurate description of how it supposed to be used. By keeping it consistent across standard library, we are also encouraging library authors to use the same terminology, and make this feature generally more discoverable.

2 Likes

+1. The false result of isTriviallyIdentical could be misinterpreted as "it is not trivially identical (but could be identical still, albeit non-trivially") which is not correct interpretation, but this name is better than isIdentical as it is more scary looking, so I think it's a good compromise.

3 Likes

isEffectivelyIdentical(to: )

I still think the false value of isTriviallyIdentical/isKnownIdentical/isIdentical is problematic, and we need to move away from an is spelling for that.

Also, the true value for isTriviallyIdentical can be problematic: the naming does not necessarily imply that it's also non-trivially identical (which is it guaranteed to).

passes is a verb choice that makes both a true and false return unequivocal in meaning:

passesUnderlyingIdentityCheck(with:)
passesKnownIdentityCheck(with:)

It also gets away from autocompleting this method upon typing .is.

Speaking personally, I’m not sure I understand that thinking about the true/false result feeling wrong. It seems like you’re taking for granted that there’s a formal concept of “identicality” which two values with the same abstract representation must have. I would say that that concept is real, but we are deciding a name for it. The suggestion here is to call it “trivially identical” for clarity and deliberately leave “identical” semantically uninhabited.

That is, you are parsing it as “is (trivially (identical))”, with all of the semantics being borne by “identical” and “trivial” just being a description of how the check is done, when you should instead parse it as “is (trivially identical)”, where the semantics are borne by the two words in combination.

This is not particularly unusual. Off the top of my head, there is a property of types where they can be “fully inhabited”, meaning that all bitwise representations are valid values of the type. This should be understood as its own formal property, not just a description of one way of having the “inhabited” property.

It’s nice that “is trivially identical” can be read largely correctly the way you’re reading it, but I think it’s fine to say that, if someone wants to be quite pedantic, it should really be read in this other way.

6 Likes

I'm very confused, this seems like the correct distinction to me. AIUI, If this method existed on String or Array, for instance, it would return true when applied to two identical small strings or direct copies of the same string/array, but false when applied to separately allocated large strings or arrays even though they could have identical contents.

2 Likes

Does anyone from LSG have some more clear feedback why the existing names on Span should not be changed? I really feel like we want to keep these names consistent. Could anyone share some more opinions or details? I'm not completely sure I understand what the argument is against choosing one name across all concrete types.

My personal thoughts on this remain unchanged from above:

2 Likes