Portrait

I2H3

Notes from work as an app developer for iPhones, iPads and Macs.

RSS Icon GitHub Mastodon

Signposting Macro

I was very excited about macros because they allow the reduction of boilerplate code like handling signposts. This macro reduces signposting in a method to a single word expression.

Have a look at this usage example:

@Logging
@Signposting
class Example {
    func sayHello() {
        #signpost
        logger.notice("Hello!")
    }
}

let example = Example()
example.sayHello()

The @Logging and @Signposting attributes are custom macros which expand to property declarations on Example. They add the preconfigured logger: Logger and signposter: OSSignposter properties. That as an explanation why I can access a logger which does not appear to be declared here. I wrote about that @Logging macro earlier already. On the other hand: the signposter is not visibly used here, only by the expanded #signpost macro. The #signpost macro expands to this:

let signpostID = signposter.makeSignpostID()
let signpostIntervalState = signposter.beginInterval(#function, id: signpostID)

defer {
    signposter.endInterval(#function, signpostIntervalState)
}

The predefined #function macro provides the current function name as a signpost name. With a single word macro the complete signposting interval is taken care of. This is very great to reduce a lot of redundant code.

a memoji

Caveat: This macro can be used only in functions which do not dispatch asynchronous tasks. As soon as the work includes execution of an asynchronous task, the interval end must be moved into the asynchronous task for correct measurement, leaving the automatically generated defer block in the wrong scope. In such case the manual endInterval(_:_:) must be used.

Update on 11th March 2024

To my dismay, the release of Swift 5.10 broke my neat little macro. The compiler now reports an error in the expansion, specifically the defer block. A declaration is expected and the defer block no longer is considered one.

Well… dang. I fear this now means search and replace everywhere and insert that redundant code snippet everywhere. Or hopefully I find another idea for this on the short term.

a memoji