As I'm working on creating a Swift library for SDL, I’m running into a new issue. The C header file declares
typedef struct SDL_Window SDL_Window;
with no further definition; SDL_Window is meant to be opaque, and is referred to throughout the API as a pointer SDL_Window*.
My modulemap file imports the SDL.h umbrella header. SDL.h includes SDL_video.h, which declares SDL_Window above, as well as (for example) SDL_CreateWindow(). My library code can see SDL_CreateWindow(), but not SDL_Window.
If I include a line like struct SDL_Window {}; in the C API module header file, then Swift is able to make the struct typedef visible.
Am I doing something wrong, or is this a limitation of the C importer? Is there a better way to address it?
Since the type's opaque, Swift imports it as an OpaquePointer. The best you can do is typealias SDLWindow = OpaquePointer, or wrap it in a custom struct for your wrapper APIs.
You don't want to provide an incorrect definition in the C code, since then you have problems if you ever dereference the pointer.
Huh. That seems to drop a lot of helpful type information. Couldn't it have defined a Swift type SDL_Window that behaves like an OpaquePointer, but could only be passed to parameters that take SDL_Window* in the C API? That way I don't pass it accidentally to the wrong API.
Yet another use case for something like Haskell's newtype. Like a type alias, but defines a (wait for it) new distinct type that's incompatible with the original type, but coercible when necessary.
Aggressive changes to the default importing rules are unlikely because of Swift's source-compatibility needs, but it might be reasonable to teach the importer to honor some sort of source annotation, perhaps via the apinotes mechanism (or something similar).