C++ function template specialization and generic functions in Swift

I assure you I fully understand /what/ your idea is (or at least, nothing about your example changes my understanding of your idea). What I don't understand is

Fantastic, I think we're getting somewhere :)

You're right, this isn't quite as straight forward as I thought it would be :grin:. And thanks again for talking this through with me. Now let's see if I can answer these questions.

What problem you're solving that balances the complexity cost of having nonuniform rules? You say “makes users less likely to write extensions for all overloads when they don't mean to,” but “writing extensions that apply to all concretizations when they don't mean to” is a problem people can have in Swift today, and we don't feel the need to add any special protections against it.

I want to push back against this a little bit. I don't think the "problem people can have in Swift today" is quite the same. The example you gave with X<Int> and X<String> being "almost completely different types" above is compelling, but still not as common, or concretely different, as in C++.

In C++ X<Int> and X<Void> can essentially be aliased to completely different types. In Swift, it's still the same type, even if very different.

As you bring up, we can't write extension where T != Void, so without this solution, there's not really a way to extend only the non-specialized version of a class. In Swift, this is more OK because users know that fact when they write their generics. In C++, this isn't true, though. People may often write classes thinking that they can select specific specializations. We should have a way to accommodate that.

The balance, in my opinion, is two-fold. First, it seems to align more closely with how C++ operates. Second, if we could get rid of the second type-checking phase, or at least make it trivial, that would be fantastic both from a performance perspective and QoI.

Why you think that a special rule for full specializations that doesn't apply to partial specializations makes sense. I can easily write a partial specialization that effectively only applies to one concretization of the class template.

This was my bad. I shouldn't have brought up partial specializations vs full specializations. Even though I brought them up, let's forget about this distinction for a minute. I don't think it's relevant to this particular problem but there is probably some discussion around them that needs to happen.

constraints like where T != Void are unlikely to ever be allowed in Swift, because they are an anti-pattern /and/ create provable type-checking complexity explosion (with NOT and conjunctions you can create disjunctions) in the implementation.

I don't actually think we should have T != Void, that was mostly for exposition. I just wanted to make clear, this would not apply to the X<Void> overload, but it seems like that was already clear, and saying T != Void just created confusion.

Anyway, that being said, I think we could avoid the problems you bring up by requiring that T != all (and only) types that the class is specialized on. Essentially just providing clarity as to what the extension applies to. It would just be a different syntax for saying extension X where T == T or extension X<T>.

The h's you've written don't actually touch the cases where checking can only happen in phase 2. Try this:

Yes, you're right. These would technically be "phase two," but the type checking wouldn't be "go extend X<Void> and see if it works" it would be, "look up the type X<Void> and see if it has already been extended." The latter is extremely trivial and means we essentially just have to check if the argument types still match whereas the former means we have to do proper type checking of the whole extension/type.