Hello again
I unfortunately ran into a pretty annoying issue; it can probably be solved by rebinding memory but I thought I'd mention it anyway, because it's something unintuitive I noticed.
The context looks something like this:
I'm creating some abstractions for SDL2 (again) because the default api looks quite unidiomatic (and it's just a cool way of testing Swift features). I'm trying to do this with as little overhead as possible, just extending the SDL types rather than wrapping them in some way, especially avoiding classes.
Consider this example usage of an SDL window api:
let window = SDL_CreateWindow(
"Window"
Int32(SDL_WINDOWPOS_CENTERED _MASK),
Int32(SDL_WINDOWPOS_CENTERED_MASK),
800, 600, SDL_WINDOW_SHOWN.rawValue |
SDL_WINDOW_RESIZABLE.rawValue |
SDL_WINDOW_ALLOW_HIGHDPI.rawValue
)
defer { SDL_DestroyWindow(window) }
The somewhat more idiomatic extension:
let window = try! SDL.Window(title: "Window", [.resizable, .hidpi])
defer { window.destroy() }
it takes advantage of Swift features, providing defaults and labels for all the settings but the title, centering the window and allowing hidpi by default, and it also uses an OptionSet as a safer interface for the bitmask. It also makes error handling easier which is usually a separate call to SDL_GetError()
.
Unfortunately, structs have no deinit
so there is an issue of still manually managing memory; window also has reference semantics but I heard that this should be solved in the future with move only types.
Neither of these is why I'm writing this post however.
Something extremely common in C apis is using opaque pointers. This is a problem here, because SDL.Window
is just a typealias for an OpaquePointer, so I don't have to wrap everything in structs, possibly allocating even more unnecessary metadata etc.
The first issue is that at first I didn't even notice this behavior, the code worked.
However, once I got to extending SDL.Renderer
which is also an OpaquePointer I became really confused when I realised extension SDL.Window
was actually extending the underlying type OpaquePointer, creating a conflict between the "types". I'm not sure what the point of allowing typealias extensions is in the first place.
It seems to be doing nothing more than adding confusion to what is actually being extended without checking the definition of the extended type.
I feel like this should either be deprecated and made an error in Swift 6, or implemented in a more intuitive way, because currently it's a pretty big footgun