Byte-sized Swift: Building Tiny Games for the Playdate

Hey folks,

As of last night's (the 19th) nightly toolchain, the standard library now has support for noncopyable generics on its pointer types and on Optional (gated under the -enable-experimental-feature NoncopyableGenerics.

Here is a PR I put up on the Swift Playdate sample, applying this feature to the SwiftBreak game. This adds a very basic non-copyable array type, and then uses that to store the brick sprites.

This feature is very relevant to the embedded world, as it can dramatically reduce overhead otherwise needed from Swift's reference-counting approach to memory ownership.

Previously the Sprite had to be represented as an enum (indicating ownership) plus a class (to handle deallocation). The noncopyable version of that pattern is significantly simpler: it just holds the underlying opaque pointer (the playdate SDK's sprite handle) plus a bool to track ownership, then uses a struct with a deinit to free it if necessary.

This PR also adds a very basic fixed-size array type to hold the bricks. This was done for two reasons. The first is that Swift.Array does not yet support non-copyable types. But more importantly, the standard array type has more overhead than is necessary for all uses, including in this game. Tracking the buffer with reference counting, accounting for CoW uses, and automatically growing the array when needed, adds to binary size. For most uses cases, these costs are negligible so not a problem. But in an embedded context, they can make a significant difference.

The net effect of these changes is that binary size for the SwiftBreak game drops about 14%. Around half of this is from the simpler array type, and about half from the simpler sprite type.

If you're interested in the evolution of this feature, check out the ongoing review thread.

17 Likes