[swift-evolution] Pitch: @objc attribute for top-level functions

Joe Groff jgroff at apple.com
Fri Mar 31 17:53:07 CDT 2017


> On Mar 31, 2017, at 8:00 AM, Charles Srstka via swift-evolution <swift-evolution at swift.org> wrote:
> 
> MOTIVATION:
> 
> Sometimes, it’s necessary to write a top-level C function in order to interact with some C-based code. This can come up, for example, when making a new port for a cross-platform app that implements OS-dependent functionality via C functions. More urgently, though, it also pops up in certain Apple APIs, such as the standard QuickLook plug-in template. In order to write a QuickLook plug-in, developers are required to write implementations for certain predefined C functions, such as GeneratePreviewForURL(), GenerateThumbnailForURL(), CancelPreviewGeneration(), and CancelThumbnailGeneration(). Unfortunately, this API contract cannot be met in Swift. Currently, Swift can only expose class members to C/Objective-C, which means that implementing a QuickLook plug-in involves a rather awkward series of hoops to jump through:
> 
> GeneratePreview.swift:
> 
> class QLGlue: NSObject {
> 	@objc static func generatePreview(_: UnsafeMutableRawPointer, request preview: QLPreviewRequest, url: URL, contentTypeUTI: String, options: [String : Any]) -> OSStatus {
> 		// generate the preview
> 	}
> }
> 
> GeneratePreview.m:
> 
> #import “MyProject-Swift.h"
> 
> OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef request, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options) {
>    return [QLGlue generatePreview:thisInterface request:request url:(__bridge NSURL *)url contentTypeUTI:(__bridge NSString *)contentTypeUTI options:(__bridge NSDictionary *)options];
> }
> 
> PROPOSED SOLUTION:
> 
> Allow the @objc on top-level functions. This will cause the functions to be exposed as C functions, satisfying contracts such as Apple’s QuickLook plug-in contract, and allowing developers to just write:
> 
> @objc func generatePreview(_: UnsafeMutableRawPointer, _ preview: QLPreviewRequest, _ url: CFURL, _ contentTypeUTI: CFString, _ options: CFDictionary) -> OSStatus {
> 	// generate the preview
> }
> 
> This would eliminate an entire source file of glue code.
> 
> IMPACT ON EXISTING CODE:
> 
> None, since @objc is not currently allowed on top-level functions. This is purely additive.

This would definitely be useful, even beyond ObjC interop. There is in fact an unfinished implementation of a `@_cdecl("symbolName")` attribute that you can use to export a global function as a C-compatible symbol. What's missing (IIRC) is bridging header support to expose the declaration back to C, compiler checking for symbol name collisions, and decoupling the validation from ObjC interop for non-Apple platforms—and, of course, a formal evolution proposal to make it an official part of the language. I don't think we want to call this @objc, since it isn't inherently tied to ObjC, and IMO it makes sense to require the exported symbol name to be required, since top-level unmangled symbols are a crowded namespace, and it would be good to ensure people think about the C symbol name they export.

-Joe


More information about the swift-evolution mailing list