electromaggot electromaggot - 1 month ago 18
Swift Question

Swift compiler bug? Can't use "direct" as method name

Can someone please sanity-check me on this? I made a Swift3/Obj-C project* with three tiny files:

ChannelSpy.swift :

import Foundation
class ChannelSpy: RMQChannel {
func direct(_ name: String!) {}
}


RMQChannel.h :

#import <Foundation/Foundation.h>
@protocol RMQChannel
- (void) direct:(NSString *)name;
@end


Bridging-Header.h :

#import "RMQChannel.h"


But this won't compile! Here's the error I'm getting:

  Type 'ChannelSpy' does not conform to protocol 'RMQChannel'

    Protocol requires function 'dirent' with type '(String!) -> Void'; do you want to add a stub?

/Proj/. . ./ChannelSpy.swift:2:7: error: type 'ChannelSpy' does not conform to protocol 'RMQChannel'  
class ChannelSpy: RMQChannel {
^
__ObjC.RMQChannel:2:17: note: protocol requires function 'dirent' with type '(String!) -> Void'; do you want to add a stub?
public func dirent(_ name: String!)
^


What's this "dirent" stuff? Am I (or the Rabbit* project) not allowed to use the name "direct"? I googled this (extensively, of course) and I see vestiges of
#define direct dirent
in ancient BSD code remnants, but I'm sure that has nothing to do with anything.

* - Actually I'm trying to build the RabbitMQ Client, while porting it to Swift 3 and OS X (which it doesn't officially support). That is, the tests are written in Swift while the Rabbit library itself remains Objective-C. I'm checking my fork into GitHub for the benefit of others needing RabbitMQ on OS X.

Answer

The system include file <sys/dir.h> defines:

/*
 * Backwards compatibility.
 */
#define direct dirent

I have no idea what that definition is needed for, but apparently <sys/dir.h> is included (indirectly) from Foundation.h, so that direct is substituted by dirent in all (Objective-)C code.

Therefore the protocol is exposed to Swift as

public protocol RMQChannel {
    public func dirent(_ name: String!)
}

If renaming the property is not possible then undefing the macro (after including the system headers) should be a viable workaround:

#undef direct
@protocol RMQChannel  
- (void) direct:(NSString *)name;  
@end