Beyond fundamental layering problems, there's another concern I have about the compile-time version of this feature, related to the issues that have been discussed around disambiguation, and also somewhat touched on by this comment:
I think what's been bugging me is that in the failure condition, i.e., the case where the symbol in question is not present, it's really difficult to talk about symbol identity.
Suppose someone is writing a program and compiling against platforms X and Y, which have (presently) divergent APIs. Platform X supports doSomething
:
struct Foo {
func doSomething(with bar: Bar)
}
whereas platform X does not:
struct Foo {
// nothing
}
so, the author uses the #if hasSymbol
feature:
#if hasSymbol(Foo.doSomething(with:)
Foo().doSomething(with: .init())
#endif
next year, after hard work on platform Y, the developers release a new version of the library:
struct Foo {
// Note: do *not* use 'doSomething' with a default-initialized 'UnsafeBar'
// This is a serious programming error
func doSomething(with unsafeBar: UnsafeBar)
}
The author of our original program has now inadvertently introduced a use of an unsafe API, and an incorrect use at that!
Ostensibly, when they wrote #if hasSymbol(Foo.doSomething(with:)
, they were in some sense only wanting to take the #if
branch if platform Y introduced the 'same' API as platform X, and not a different one. Perhaps this has a clear meaning in the common cases (like Apple's platforms), and this issue wouldn't really arise in practice.
But in the edge cases, I don't know how to talk about whether two different symbols, on platforms which may have almost entirely divergent API surfaces, are 'really' the same underlying symbol. Should we require type-based disambiguation for all symbols passed as an argument to hasSymbol
, even those that are not today ambiguous? Is type-name-based identity even the right tool for specifying a specific symbol which doesn't currently exist at all on the platform being compiled against?
I know you have mentioned that you want to keep the runtime version of this feature to a separate thread, so I won't go into my thoughts on that part of the feature too extensively, except to say that the problem seems much more tractable when we are able to resolve specific symbol identity at the time that the check is first written.