@_exported and fixing import visibility


(Joe Groff) #41

If that's the case, then why does this matter at all to Swift's own language design? When people use C, they know C's limitations, and I think they can accept Swift isn't going to magically lift them. If a C module transitively imports a Swift or mixed-source module, I would expect it to leak the C interface of that module through the C module, but it doesn't seem fundamental to me that it'd affect the Swift side of things; we could still conceivably say that to get the Swift part of the interface, the Swift code has to explicitly import it.


(Matthew Johnson) #42

Unless I misunderstand, what it gives us is the ability to use C without having to re-export everything. As @Joe_Groff mentioned upthread, sometimes there are reasons to use C right now where people might prefer to stay in Swift-only land. If they had the option to do that without the downside of having to re-export it might be very useful.

I understand that it's not a regression but it is something I think we should fix if we can (and it sounds like we can, the only question is whether we should given source compatibility, etc). The behavior of (2) and (3) is extremely undesirable IMO even if it is what we have today.

Isn't there a path forward that might break source compatibility but allows for automatic migration (at least via a temporary / deprecated @leaky import I mentioned earlier).


(Jordan Rose) #43

The compiler can't import "just the C part" of a Swift module because it doesn't know how the types match up with the Swift types. (The way this works in the importer is by basically throwing away the C declarations once they've been mapped back to Swift declarations.) I guess we could treat that as "loaded but not visible", though?

It's the kind of thing that's technically feasible but definitely non-trivial, and I haven't thought too much about the tricky bits. I was hoping we could define the problem away with the work on "implementation-only imports" and "re-exported imports", but that doesn't seem to be the case, and that means it's just a separate issue. Which means I won't be working on it right now.


(Matthew Johnson) #44

Would this mean it's available to the library but not the client? I think this is pretty much the direction I'm suggesting, isn't it?

I see. We've lived with it this long so I suppose that's ok. :slight_smile: I'll be happy as long as it eventually gets some attention...


(Jordan Rose) #45

Yeah, "loaded but not visible" is my attempt to describe what the current Swift import does.

Okay, hm. I'll have to think about how to do this C thing.


(Matthew Johnson) #46

FWIW, I would interpret "not visible" to include operators and extensions (which current Swift import does include)...


(Jordan Rose) #47

:-) I'm describing where we want to be rather than where we are, but since I did just say that probably won't get fixed as part of this work, maybe I should stop.


(Jens Ayton) #48

I’d like to note that this is not my expectation as an Objective-C developer. Clang modules have explicit export lists, and while export * is commonplace, it isn’t the only way to do things.

It is in fact exactly how the Clang modules dialect of C works. @import UIKit only exposes NSObject because UIKit’s module map says so.

On top of that (regardless of modules), C and Objective-C libraries can distinguish between public imports (ones that are in their public headers) and private ones (ones in private headers or implementation files only). They can also reduce the number of public imports required by using forward declarations. Swift doesn’t have either of these things.

It seems to me that C and Objective-C compatibility is being used to argue for a semantics that’s leakier than C or Objective-C require.


(Matthew Johnson) #49

I don’t have the expertise that @jrose does in this area so I have been accepting his statement of the problem. If we can get away with more controlled semantics when dealing with C and Objective-C interop I would of course be very happy with that!


(Jordan Rose) #50

Ooh, I was hoping no one would bring up export *. Swift is currently pretty broken when people don't do export *, and I'm not sure Clang works well with it either. But on top of that, the module map for an Xcode-built framework containing Swift code currently always includes export * for the Swift part of the module, with no way to configure it. Part of the reason for this is because it's never a good thing when C code behaves differently with and without modules enabled, and while Swift generated headers currently don't support modules-off very well, they should be able to (SR-805).

We may not get forward declarations in Swift (for probably dozens of reasons), but this thread definitely covers adding the implementation-only imports. The tricky bits are around the things you want to expose as API, and then around the things you want to expose as ABI but not API. (The latter is where forward declarations are "usually good enough" in C.)


(Vladislav Alekseev) #51

My bit to the discussion from user of the Swift and SPM.

I use SPM and I have plenty of targets. SPM requires you to explicitly specify the dependencies for each target inside Package.swift, but on the other side, Swift allows me to use transitive dependencies in my source code without updating Package.swift. Sometimes this breaks the build phase, because, as I think, the compiler meets some import-s of not yet built modules/targets. Then I have to dig into the problem, find the missing dependency and update my module inside Package.swift so build system would build the libraries in the right order. Usually this is a pain, because swift build will just print some not very helpful error about libc module. :slight_smile:

I agree that NSObject should be usable if you import AppKit or UIKit, but for non-Apple modules, I think, it will be beneficial to have the ability to disable the use of the transitive deps.