Why can't I have a private @usableFromInline declaration?

The @usableFromInline annotation can only be attached to internal declarations. Why can't I attach it to private ones too? Whether it's usable from inline should be completely orthogonal to access control (except in that public implies usable from inline already).

For context, I've got a property that I want to make private(set), because I need to preserve certain invariants when modifying it, but I also want to make a public function that modifies it @inlinable.

1 Like

I believe the reason is the exported name. The symbol for the exported function is exposed in the library's ABI, which means it needs a name, and that name must be unique. Private functions on the other hand can have multiple definitions with the same name living in different files. So @usableFromInline would have to change the semantics of private to make it an error to have two private symbols that are @usableFromInline with the same name in the same library that are both @usableFromInline.

I think it's achievable, but the resulting semantics are a bit weird and unexpected in other ways.

5 Likes

That's a good point. But it's a very frustrating limitation, and I'd much rather have the limitation of "you can't have 2 @usableFromInline private symbols with the same name.

Also, in my case I don't even care about ABI stability, as the symbol is declared in a framework that I bundle in my app. So this limitation serves no benefit to me.

In any case, if we changed private symbols to ditch the UUID if they're declared within the original type declaration instead of an extension, then we could at least relax it to "@usableFromInline cannot be used on a private symbol inside of an extension", which is pretty similar to "you can't declare stored proprties in an extension". I'd definitely prefer the restriction to be "you can't have two @usableFromInline private symbols with the same name", but the "it can't be in an extension" rule might be conceptually simpler.

@michelf pretty much got it. Allowing @usableFromInline on private declarations would mean doing redeclaration checking across files of declarations nominally marked private, perhaps nested in extensions. I don't think it's impossible but it would definitely break assumptions in the compiler.

(Alternately, the compiler could just believe you, and then you'd get a linker or SIL error if you were wrong. That might be easiest in the long run.)

4 Likes

Just to clarify, you can't export duplicate symbol names in a library; whether its ABI is stable or not doesn't change this.

I think Lily's point was that the mangled names could continue to have discriminators in them if they didn't have to be stable. LLDB can find them just fine, for example. But it'd be tricky if we ever wanted to support module interface files with non-library-evolution-enabled frameworks, though I'm not sure we will.

1 Like