Monthly Archives: May 2018

Internal Typealias Promotion

In some scenarios it might be useful to declare a typealias internally to a module, to make it easier to implement the functionality of the module itself, but less useful to export that typealias to clients of the module. For example, consider an image manipulation framework that can work with NSImage or UIImage instances, depending on the platform. Internally to the module, I might define:

#if os(macOS)
	typealias RSPlatformNativeImage = NSImage
	typealias RSPlatformNativeImage = UIImage

Then I can implement methods, including public facing methods like:

public func monochromeImage(fromImage image: RSPlatformNativeImage) -> RSPlatformNativeImage { ... }

Since I haven’t marked my typealiases as ‘public’, they won’t be exported to clients, but the above will also fail to compile. Swift requires that public methods work only with public types. This makes sense, because if the types aren’t public, how are clients expected to be able to work with them?

But if I mark the typealiases public, I impose a new type “RSPlatformNativeImage” on clients, when as far as they are concerned, this method operates on either an NSImage or UIImage. They might quickly get the idea that RSPlatformNativeImage is just a typealias, but it’s a bit of unwanted clutter on the public-facing API.

Obviously I can solve this by adding more platform-specific directives to the module so that whole functions are declared as working with either NSImage or UIImage, but it would be nice if Swift would help me out here. Instead of giving a compiler error, Swift could simply export the method using the public type that the typealias resolves to. In which case a client of the module for iOS would see the method as:

public func monochromeImage(fromImage image: UIImage) -> UIImage { ... }

And for Mac:

public func monochromeImage(fromImage image: NSImage) -> NSImage { ... }

Handling internal typealiases like this would cause the behavior for Swift clients to match what is already being done for Objective-C clients. The generated Module-Swift.h for this method in a Mac project is:

- (NSImage * _Nonnull) monochromeImageFromImage:(NSImage * _Nonnull)image SWIFT_WARN_UNUSED_RESULT;

Thus for Objective-C clients the clutter of the typelias definition is tidied away, but for Swift clients, it must still be dealt with. I filed a bug requesting this behavior in the Swift bug tracking system.

Getting a CFNumber’s Value in Swift

Recently, as a consequence of working with the CGImageSource API, I found myself in a situation where I had hold of a CFNumber and wanted to get its value, as a CGFloat, in Swift.

CFNumber wraps numeric values in such a way that, to get the value out, you have to specify both the desired type, and provide a pointer to the memory of the variable that will hold the value. This kind of direct memory manipulation is not particularly suited to Swift’s priorities for type safety and memory protection. Here’s the API I’d need to use in Swift:

func CFNumberGetValue(_ number: CFNumber!, 
                    _ theType: CFNumberType, 
                    _ valuePtr: UnsafeMutableRawPointer!) -> Bool

The first two parameters are straightforward, but whenever I see types like “UnsafeMutableRawPointer” in Swift, my brain melts down a little. I have never really sat down to truly understand the nuanced differences between these types, so I usually just try something and hope it works. Here I am hoping for a gift from Swift’s implicit bridging:

// myCFNumber is 30.5
var myFloat: CGFloat = 0
CFNumberGetValue(myCFNumber, .floatType, &myFloat)
print(myFloat) // "5.46688490824244e-315\n"

Welp. That didn’t work. Let’s see if we can refresh our memory about UnsafeMutableRawPointer. In the section titled “Raw, Unitialized Memory” or I read:

You can use methods like initializeMemory(as:from:) and moveInitializeMemory(as:from:count:) to bind raw memory to a type and initialize it with a value or series of values.

Oh jeez, am I really going to have to manually create an UnsafeMutableRawPointer? I’ll try anything:

var myFloat: CGFloat = 0
var myFloatPointer = UnsafeMutableRawPointer(mutating: &myFloat)
CFNumberGetValue(myCFNumber, .floatType, myFloatPointer)
print(myFloat) // "5.46688490824244e-315\n"

Alas, same problem. Surely somebody has figured this out? I try Googling for “CFNumberGetValue Swift GitHub” and find a promising result from an authoritative source. The Swift standard library itself!

var value: Float = 0
CFNumberGetValue(_cfObject, kCFNumberFloatType, &value)

Aha! Practically the same thing I was doing, except for one nuanced detail: the var value is declared as a Float instead of a CGFloat. But wait a minute, what file is this implementation in? NSNumber.swift? Oh, right. NSNumber and CFNumber are toll-free bridged, and Swift’s standard library fulfills that promise too:

let myFloat = (myCFNumber as NSNumber).floatValue
print(myFloat) // 30.5

In fact, Swift’s Float type is even cozier with CFNumber than I expected. What started as a confused mission to make use of CFNumberGetValue and its unsafe pointer argument culminated in a bit of sample code from GitHub that ultimately led me to the understanding that the way to get a CFNumber’s value in Swift is … simply to ask for it:

let myFloat = Float(myCFNumber)
print(myFloat) // 30.5