I am quite sure that the question covers that aspect too.
That was meant rhetorically. So let’s expand on it. Supposing a reasonably modern 64-bit platform, the ABI of Int is a single 64-bit word of storage. All existing code making use of that ABI assumes word-sized loads and word sized stores. If an extension were to add storage for, say, an extra Bool field, where among the bitpatterns for an Int could we possibly attach this bit? We certainly cannot stick it among the 64 bits in use by Int’s ABI since all 64 are needed for the full space of representable integer bitpatterns. We also cannot simply add more storage to accommodate the new bit, or we would break the layout expected by every existing client of Int that was built against the word-sized ABI.
Okay, but maybe that’s not convincing enough. After all, we could totally alter the ABI of Int to add our new bit, but say only change the ABI in the module we’re building. Now we export a public API:
extension Int {
public var isSpecial: Bool = true
}
Alright, so now every client of our module needs to know about our special Int too to use it properly, so let’s use our compiler to propagate the new ABI up and out to dependent modules that import us. Let’s repeat the extension process in another module for good measure
extension Int {
public var isFancy: Bool = true
}
Again, we’ll ignore the ABI propagation problem here. Suppose both extensions were imported together. Now we have to have a stable way to sort extensions adding storage so clients see the proper ABI at each level. It’s not infeasible, but it’s certainly difficult to juggle all of these disparate ABIs dependent entirely upon the set of modules imported into any one Swift file. We’d also need to make sure that we emit thunks between ABIs so code in our module can, say, call standard library APIs that assume the original 64-bit ABI. Imagine that, the act of importing a module automatically incurs a code size and runtime performance impact!
This system is... a mess. Its consequences would be disastrous both from an implementation perspective and from a user perspective. It’s not impossible to imagine a world where we allowed this through some kind of side channel akin to associated objects, but every choice has consequences. And associated objects, for example, come with a steep runtime cost.
But why can you add functions then? Well, they’re not subject to the same ABI-altering concerns from before. A new member function in isolation adds a symbol (modulo thunks) to the module it is defined in, but that symbol is not a part of the ABI of the original type - its presence or absence does not change the fact that an Int is 64 bits.