i don’t think “does not expose source code” needs to be the only criteria for a workable generics model, generics are useful even when they are totally inlinable. so i don’t think there ever was a perception that generics are about resilience, resilience is just something generics can also do alongside templating.
what @stuchlej was asking about with the overload resolution has to do with swift choosing a particular set of overload resolution rules that makes sense for resilient generics, and that set of rules is different from the one that makes sense for inlinable generics, like C++ has. so for consistency, swift just made the resilient overload resolution rules apply to the inlinable case as well. that’s why you can’t override the default overload resolution rules with @inlinable
and get C++ style dispatch.
it is confusing to people coming from a C++ background, but it’s mostly unrelated to the performance aspects of generics.
to me, the difficulties ive had working with generics is because we don’t have any compile time checking for inlinable generics to make sure they are always specialized when you expect them to. so the monomorphization often fails for interesting reasons that are hard to understand or anticipate. and the compiler doesn’t tell you if it failed because you have to read assembly for every usage site to see what the compiler did.
i think many of these issues with swift generics could be resolved if we just had some kind of attribute like @specialized
that attaches to type parameters and tell the compiler that the type parameter it’s attached expects to be used only in declarations emitted into the client. (this would be different from the current behavior of the underscored @_specialized
attribute.)
@specialized(T)
struct RGBA<T>
public
and @usableFromInline internal
things that use the type parameter would have to be @inlinable public
, or the compiler would emit a warning.
extension RGBA
{
public
var premultiplied:Self
// ^~~~~~
// warning: computed property 'premultiplied' must be marked @inlinable,
// because it uses a specialized type parameter 'T'
but things that don’t use the type parameter wouldn’t need to be inlinable.