|
1 | 1 | # Name Translation from C to Swift
|
2 | 2 |
|
3 |
| -This document gives a high-level description of how C and Objective-C declarations are translated to Swift, with particular focus on how names are adjusted. It is not attempting to be a *complete* description of everything the compiler does except with regards to how *names* are transformed; even there, some special cases that only apply to Apple's SDKs have been omitted. |
| 3 | +This document gives a high-level description of how C and Objective-C declarations are translated to Swift, with particular focus on how names are adjusted. It is not attempting to be a *complete* description of everything the compiler does except with regards to how *names* are transformed; even there, some special cases that only apply to Apple's SDKs have been omitted. The example code shown is for illustrative purposes and does not always include all parts of an imported API's interface. |
4 | 4 |
|
5 | 5 | ## Word boundaries
|
6 | 6 |
|
@@ -239,4 +239,208 @@ _The original intent of the `swift_private` attribute was additionally to limit
|
239 | 239 | _For "historical reasons", the `swift_private` attribute is ignored on factory methods with no arguments imported as initializers. This is essentially matching the behavior of older Swift compilers for source compatibility in case someone has marked such a factory method as `swift_private`._
|
240 | 240 |
|
241 | 241 |
|
| 242 | +## Custom names |
| 243 | + |
| 244 | +The `swift_name` Clang attribute can be used to control how a declaration imports into Swift. If it's valid, the value of the `swift_name` attribute always overrides any other name transformation rules (prefix-stripping, underscore-prepending, etc.) |
| 245 | + |
| 246 | +### Types and globals |
| 247 | + |
| 248 | +The `swift_name` attribute can be used to give a type or a global a custom name. In the simplest form, the value of the attribute must be a valid Swift identifier. |
| 249 | + |
| 250 | +```objc |
| 251 | +__attribute__((swift_name("SpacecraftCoordinates"))) |
| 252 | +struct SPKSpacecraftCoordinates { |
| 253 | + double x, y, z, t; // space and time, of course |
| 254 | +}; |
| 255 | +``` |
| 256 | +
|
| 257 | +```swift |
| 258 | +struct SpacecraftCoordinates { |
| 259 | + var x, y, z, t: Double |
| 260 | +} |
| 261 | +``` |
| 262 | + |
| 263 | +### Import-as-member |
| 264 | + |
| 265 | +A custom name that starts with an identifier followed by a period is taken to be a member name. The identifier should be the imported Swift name of a C/Objective-C type in the same module. In this case, the type or global will be imported as a static member of the named type. |
| 266 | + |
| 267 | +```objc |
| 268 | +__attribute__((swift_name("SpacecraftCoordinates.earth"))) |
| 269 | +extern const struct SPKSpacecraftCoordinates SPKSpacecraftCoordinatesEarth; |
| 270 | +``` |
| 271 | +
|
| 272 | +```swift |
| 273 | +extension SpacecraftCoordinates { |
| 274 | + static var earth: SpacecraftCoordinates { get } |
| 275 | +} |
| 276 | +``` |
| 277 | + |
| 278 | +Note that types cannot be imported as members of protocols. |
| 279 | + |
| 280 | +_The "in the same module" restriction is considered a technical limitation; a forward declaration of the base type will work around it._ |
| 281 | + |
| 282 | + |
| 283 | +### C functions with custom names |
| 284 | + |
| 285 | +The `swift_name` attribute can be used to give a C function a custom name. The value of the attribute must be a full Swift function name, including parameter labels. |
| 286 | + |
| 287 | +```objc |
| 288 | +__attribute__((swift_name("doSomething(to:bar:)"))) |
| 289 | +void doSomethingToFoo(Foo *foo, int bar); |
| 290 | + |
| 291 | +// Usually seen as NS_SWIFT_NAME. |
| 292 | +``` |
| 293 | +
|
| 294 | +```swift |
| 295 | +func doSomething(foo: UnsafeMutablePointer<Foo>, bar: Int32) |
| 296 | +``` |
| 297 | + |
| 298 | +An underscore can be used in place of an empty parameter label, as in Swift. |
| 299 | + |
| 300 | +A C function with zero arguments and a non-`void` return type can also be imported as a computed variable by using the `getter:` prefix on the name. A function with one argument and a `void` return type can optionally serve as the setter for that variable using `setter:`. |
| 301 | + |
| 302 | +```objc |
| 303 | +__attribute__((swift_name("getter:globalCounter()"))) |
| 304 | +int getGlobalCounter(void); |
| 305 | +__attribute__((swift_name("setter:globalCounter(_:)"))) |
| 306 | +void setGlobalCounter(int newValue); |
| 307 | +``` |
| 308 | +
|
| 309 | +```swift |
| 310 | +var globalCounter: Int32 { get set } |
| 311 | +``` |
| 312 | + |
| 313 | +Note that the argument lists must still be present even though the name used is the name of the variable. (Also note the `void` parameter list to specify a C function with zero arguments. This is required!) |
| 314 | + |
| 315 | +Variables with setters and no getters are not supported. |
| 316 | + |
| 317 | + |
| 318 | +#### Import-as-member |
| 319 | + |
| 320 | +Like types and globals, functions can be imported as static members of types. |
| 321 | + |
| 322 | +```objc |
| 323 | +__attribute__((swift_name("NSSound.beep()"))) |
| 324 | +void NSBeep(void); |
| 325 | +``` |
| 326 | +
|
| 327 | +```swift |
| 328 | +extension NSSound { |
| 329 | + static func beep() |
| 330 | +} |
| 331 | +``` |
| 332 | + |
| 333 | +However, by giving a parameter the label `self`, a function can also be imported as an instance member of a type __T__. In this case, the parameter labeled `self` must either have the type __T__ itself, or be a pointer to __T__. The latter is only valid if __T__ is imported as a value type; if the pointer is non-`const`, the resulting method will be `mutating`. If __T__ is a class, the function will be `final`. |
| 334 | + |
| 335 | +```objc |
| 336 | +typedef struct { |
| 337 | + int value; |
| 338 | +} Counter; |
| 339 | + |
| 340 | +__attribute__((swift_name("Counter.printValue(self:)"))) |
| 341 | +void CounterPrintValue(Counter c); |
| 342 | +__attribute__((swift_name("Counter.printValue2(self:)"))) |
| 343 | +void CounterPrintValue2(const Counter *c); |
| 344 | +__attribute__((swift_name("Counter.resetValue(self:)"))) |
| 345 | +void CounterResetValue(Counter *c); |
| 346 | +``` |
| 347 | +
|
| 348 | +```swift |
| 349 | +struct Counter { |
| 350 | + var value: Int32 { get set } |
| 351 | +} |
| 352 | +
|
| 353 | +extension Counter { |
| 354 | + func printValue() |
| 355 | + func printValue2() |
| 356 | + mutating func resetValue() |
| 357 | +} |
| 358 | +``` |
| 359 | + |
| 360 | +This also applies to getters and setters, to be imported as instance properties. |
| 361 | + |
| 362 | +```objc |
| 363 | +__attribute__((swift_name("getter:Counter.absoluteValue(self:)"))) |
| 364 | +int CounterGetAbsoluteValue(Counter c); |
| 365 | +``` |
| 366 | +
|
| 367 | +```swift |
| 368 | +extension Counter { |
| 369 | + var absoluteValue: Int32 { get } |
| 370 | +} |
| 371 | +``` |
| 372 | + |
| 373 | +The getter/setter syntax also allows for subscripts by using the base name `subscript`. |
| 374 | + |
| 375 | +```objc |
| 376 | +__attribute__((swift_name("getter:LinkedListOfInts.subscript(self:_:)"))) |
| 377 | +int LinkedListGetAtIndex(const LinkedListOfInts *head, int index); |
| 378 | +``` |
| 379 | +
|
| 380 | +```swift |
| 381 | +extension LinkedListOfInts { |
| 382 | + subscript(_ index: Int32) -> Int32 { get } |
| 383 | +} |
| 384 | +``` |
| 385 | + |
| 386 | +Finally, functions can be imported as initializers as well by using the base name `init`. These are considered "factory" initializers and are never inherited or overridable. They must not have a `self` parameter. |
| 387 | + |
| 388 | +```objc |
| 389 | +__attribute__((swift_name("Counter.init(initialValue:)"))) |
| 390 | +Counter CounterCreateWithInitialValue(int value); |
| 391 | +``` |
| 392 | +
|
| 393 | +```swift |
| 394 | +extension Counter { |
| 395 | + /* non-inherited */ init(initialValue value: Int32) |
| 396 | +} |
| 397 | +``` |
| 398 | + |
| 399 | + |
| 400 | +### Enumerators (enum cases) |
| 401 | + |
| 402 | +The `swift_name` attribute can be used to rename enumerators. As mentioned above, not only does no further prefix-stripping occur on the resulting name, but the presence of a custom name removes the enum case from the computation of a prefix for the other cases. |
| 403 | + |
| 404 | +``` |
| 405 | +// Actual example from Apple's SDKs; in fact, the first shipping example of |
| 406 | +// swift_name on an enumerator at all! |
| 407 | +typedef NS_ENUM(NSUInteger, NSXMLNodeKind) { |
| 408 | + NSXMLInvalidKind = 0, |
| 409 | + NSXMLDocumentKind, |
| 410 | + NSXMLElementKind, |
| 411 | + NSXMLAttributeKind, |
| 412 | + NSXMLNamespaceKind, |
| 413 | + NSXMLProcessingInstructionKind, |
| 414 | + NSXMLCommentKind, |
| 415 | + NSXMLTextKind, |
| 416 | + NSXMLDTDKind NS_SWIFT_NAME(DTDKind), |
| 417 | + NSXMLEntityDeclarationKind, |
| 418 | + NSXMLAttributeDeclarationKind, |
| 419 | + NSXMLElementDeclarationKind, |
| 420 | + NSXMLNotationDeclarationKind |
| 421 | +}; |
| 422 | +``` |
| 423 | + |
| 424 | +``` |
| 425 | +public enum Kind : UInt { |
| 426 | + case invalid |
| 427 | + case document |
| 428 | + case element |
| 429 | + case attribute |
| 430 | + case namespace |
| 431 | + case processingInstruction |
| 432 | + case comment |
| 433 | + case text |
| 434 | + case DTDKind |
| 435 | + case entityDeclaration |
| 436 | + case attributeDeclaration |
| 437 | + case elementDeclaration |
| 438 | + case notationDeclaration |
| 439 | +} |
| 440 | +``` |
| 441 | + |
| 442 | +Although enumerators always have global scope in C, they are often imported as members in Swift, and thus the `swift_name` attribute cannot be used to import them as members of another type unless the enum type is anonymous. |
| 443 | + |
| 444 | +_Currently, `swift_name` does not even allow importing an enum case as a member of the enum type itself, even if the enum is not recognized as an `@objc` enum, error code enum, or option set (i.e. the situation where a case is imported as a global constant)._ |
| 445 | + |
242 | 446 | ## More to come...
|
0 commit comments