Why is this cast?

This is from the AudioUnit template code. Note the guard statement:

audioUnit = try HackSynth_ZeroAudioUnit(componentDescription: componentDescription, options: [])
        
        guard let audioUnit = self.audioUnit as? HackSynth_ZeroAudioUnit else {
            log.error("Unable to create HackSynth_ZeroAudioUnit")
            return audioUnit!
        }

Why is that cast there? Can the try expression return any type other than HackSynth_ZeroAudioUnit? The Type itself is an Obj-C "instancetype", so ought to be a non-optional, yes? It seems like it ought to either be a real instance, or the function ought to throw and the guard never be reached.

Technically objective-C initialiser can return some other class, and I was able creating a situation when "Other path" is taken and the subsequent precondition fails:

func foo() {
    let value: AnyObject = try! HackSynth_ZeroAudioUnit(AudioComponentDescription())
    print(type(of: value)) // SomeOtherClass
    if let value = value as? HackSynth_ZeroAudioUnit {
        print("OK")
    } else {
        print("OTHER") // we are here
    }
    precondition(value is HackSynth_ZeroAudioUnit) // fails
}
Using this contrived Obj-C implementation
@interface HackSynth_ZeroAudioUnit: NSObject
- (instancetype)init:(AudioComponentDescription)description error:(NSError**)error;
@end

@interface SomeOtherClass: NSObject
@end

@implementation SomeOtherClass: NSObject
@end

@implementation HackSynth_ZeroAudioUnit
- (nullable instancetype)init:(AudioComponentDescription)description error:(NSError **)error {
    self = [[SomeOtherClass alloc] init];
    return self;
}
@end

But I am unfamiliar with the original HackSynth_ZeroAudioUnit code (is it open source?) so don't know the original intention of that check.

It's from the boilerplate which you get when you start an Audio Unit Extension project.

I see. Unless you do something really strange (like in the contrived example above) – the check will never fail.

Yeah, that’s what I was thinking, but I’ve been fooled before. Thanks for looking at it!

I'm beginning to think this code was written by an intern.

Another thing from the same function, I note that it uses a defer statement to do setup on the View, which assumes the AudioUnit was created, despite the fact that defer runs after throws.

I guess I'm rewriting... well, everything.

What is the declared type of self.audioUnit?

If you rewrite it you may as well get rid of obj-c / obj-c++ in there. Just be careful – it is very easy in swift to do something that allocates memory / blocks on a mutex implicitly – this is no go in realtime context.

1 Like

Yeah, I'm shaky in this area, so I might be asking for folks to look at what I'm doing as I'm going along. Based on the discussion about real time swift where you pointed out that Apple seemed to be okay with pure swift real time, I'm going to try and make the template all swift, and figure out the buffering and stuff so the DSP kernel can properly be memory move and math.

It's declared as var audioUnit: AUAudioUnit?

So, yep, the cast makes sense, but the surrounding bits are dubious.

And really, given that this is a subclass of AUViewController, and AUAudioUnitFactory, it's not clear to be it needs to be declared that way. I can't immediately think of why it shouldn't be declared as HackSynth_ZeroAudioUnit? right off the bat.