@_silgen_name
is the elephant in the room. Part of that is right there in the name of the attribute: "SILGen name". @_silgen_name
doesn't just change the symbol name of a function; it changes how the compiler itself sees the function, well before it's emitted.* It also does not change the calling convention, but the Swift calling convention is mostly compatible with C's on most platforms and those "mosts" should freak you out.
The other thing @_silgen_name
does is let you declare functions that exist without importing a module or header file. That's inherently unsafe, but it's also how Rust calls C functions**, so I don't want to say it's forever off the table. For now, though, it'd be a big shift in how what Swift allows, so I want to set this aside. I really want to set this aside.
I don't think this was ever a thing; please go see if you can remove @_silgen_name
!
* For what it's worth, I believe @_cdecl
is currently implemented the same way, and I'm not sure we should keep that. I'd rather preserve the Swift name until we get down to LLVM, which is where we've resolved all names and no longer need to look in imported modules.
** Though often these extern
blocks are generated by a tool like bindgen
rather than written by hand, precisely because it's easy to get it wrong.
Okay, so what about the other aspect: the separation of name control from calling convention? The main thing I'm thinking about here is the goal: call a Swift-defined function from C.
Jens's stub here is clever, and mostly works because we've kept our mangling scheme based on the C identifier character set. I had originally dismissed the idea because I didn't think of a way to do it without language extensions. I would still like a way to control the symbol name too, but maybe that really is separable.
Anyway, the conclusion I'm coming to is that we should have an attribute like @available
where there's one required parameter—the language—and then several keyword arguments. That leaves room for expansion in the future.
@extern(c)
@extern(c, name: fookit_setup)
@extern(c++, abi: itanium)
If we follow the convention of @objc
, then @extern(c)
would generate a C function but use the Swift symbol name, and @extern(c, name: fookit_setup)
would actually change the symbol name. That's fairly subtle, though, so maybe we'd want to do something else? (As has been pointed out above, you can always write a wrapper function that has the right C name if you also care about the name in Swift.)
Does the name really need a parameter label, since it's the most common thing? It does if we want to support Objective-C selectors without quotes, and I think quotes are bad here because the compiler does need to validate it a little. Okay, technically you can distinguish them because selectors with arguments always end in a colon, but still.
I'm not the first in the thread to come up with the argument-based attribute, of course; I'm just throwing my weight behind it. Y'all have convinced me. :-)
One thing that's missing here is the @objc @cdecl
thing. How do you distinguish between a C function that allows ObjC types from a C function that doesn't? Maybe something like @extern(c, allow: objc)
? That does scale to @extern(c, allow: c++)
, which is a thing that happens sometimes… But if anyone has better suggestions, I'm all ears.
*** You can't do this with Objective-C methods because you need to be able to implement a protocol method in both Objective-C and Swift and have it work from the other language. And it wouldn't work at all with classes.
Finally, the name. I don't love the name extern
because I feel like it's more strongly associated with it's "declare but not define" meaning than its "share with other files/libraries/languages" meaning, but it does have massive precedent. My thoughts on the other suggestions in the thread:
-
@linkage
isn't a term most people would know, I think. (It means more than just C vs. C++ in C-land, too.) -
@decl
feels very generic (though I appreciate that Swift is just another choice there) -
@callableBy
feels wordy and doesn't work on things other than functions. -
@convention(c)
doesn't feel like it'll scale to all our uses, and@extern @convention(c)
seems needlessly verbose even if@extern
also supports a symbol name.
I was hoping I'd come to conclusions at the end of these update posts, but there aren't too many to be had. I'm glad we're having the discussion, though!
P.S. I don't like anyone's names for the alternate -emit-objc-header
either. Bleah!