Skip to content

Conversation

heckj
Copy link
Member

@heckj heckj commented Aug 19, 2025

Adds documentation for the Swift 6.1 traits feature

Motivation:

  • Show how to consume packages that provide traits
  • Show how to present traits from your package(s)
  • Updating PackageDescription API to use slightly more readable content related to traits.

Modifications:

  • updated PackageDescription API around traits
  • added curation (organization) for Traits and Package/Dependency/Traits
  • extended Using Dependencies article to touch on traits and how to consume packages that provide them
  • added an article to share patterns to use when providing a traits from your own package

Result:

Updated content and one additional article in the central documentation for Swift Package Manager that illustrates how to consume and provide packages with traits.

@heckj heckj self-assigned this Aug 20, 2025
@heckj
Copy link
Member Author

heckj commented Aug 20, 2025

@swift-ci please test

@heckj
Copy link
Member Author

heckj commented Aug 27, 2025

@swift-ci please test

Copy link
Contributor

@bripeticca bripeticca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking wonderful! Just a few comments for you to check out :)


Traits, introduced with Swift 6.1, allow packages to offer additional API that may include optional dependencies.
Packages should offer traits to provide API beyond the core of a package.
For example, a package may provide an experimental API, optional API that requires additional dependencies, or functionality that a developer may want to disable in specific circumstances.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
For example, a package may provide an experimental API, optional API that requires additional dependencies, or functionality that a developer may want to disable in specific circumstances.
For example, a package may provide an experimental API, an optional API that requires additional dependencies, or functionality that a developer may want to disable in specific circumstances.

Packages should offer traits to provide API beyond the core of a package.
For example, a package may provide an experimental API, optional API that requires additional dependencies, or functionality that a developer may want to disable in specific circumstances.
If a package offers traits, using that package as a dependency without any declared traits uses the default traits that the package defines.
In the following example dependency declaration, the package uses the default set of traits from the dependency, if any are defined:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Perhaps for clarity here, we should specify that the dependency package (example-package-playingcard) will use its own default traits when being imported into the package that defines it as a dependency if it is declared in this way. I'm not sure how to make that less of a mouthful however :)

]
```

To determine what traits a package offers, including its defaults, inspect its `Package.swift` manifest.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: once your other PR #9034 is merged, it would be sweet to also add that you could also invoke swift package show-dependencies to view the available traits as well! :)


Define one or more traits to offer default and configurable features for a package.

Prior to Swift packages prior to Swift 6.1 offered a non-configurable API surface for each version.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo:

Suggested change
Prior to Swift packages prior to Swift 6.1 offered a non-configurable API surface for each version.
Swift packages prior to Swift 6.1 offered a non-configurable API surface for each version.

Constrain the version of a remote dependency when you when you declare the dependency.
The package manager uses git tags interpretted as semantic versions to identify eligible versions of packages.
Constrain the version of a remote dependency when you declare the dependency.
The package manager uses git tags, interpreted as a semantic versions, to identify eligible versions of packages.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo:

Suggested change
The package manager uses git tags, interpreted as a semantic versions, to identify eligible versions of packages.
The package manager uses git tags, interpreted as a semantic version, to identify eligible versions of packages.

///
/// - Important: Traits must be strictly additive. Enabling a trait **must not** remove API.
///
/// If your conditional code requires an dependency that you want to enable only when the trait is enabled,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo:

Suggested change
/// If your conditional code requires an dependency that you want to enable only when the trait is enabled,
/// If your conditional code requires a dependency that you want to enable only when the trait is enabled,

Copy link
Member

@FranzBusch FranzBusch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great. Thanks for working on this @heckj !

Comment on lines +23 to +25
/// #if Trait1
/// // additional imports or APIs that Trait1 enables
/// #endif // Trait1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// #if Trait1
/// // additional imports or APIs that Trait1 enables
/// #endif // Trait1
/// #if MyTrait
/// // additional imports or APIs that MyTrait enables
/// #endif // MyTrait


Traits, introduced with Swift 6.1, allow packages to offer additional API that may include optional dependencies.
Packages should offer traits to provide API beyond the core of a package.
For example, a package may provide an experimental API, optional API that requires additional dependencies, or functionality that a developer may want to disable in specific circumstances.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the word disable is too strong here. There is no way to disable a trait really since across a package graph multiple different packages might enable different traits and we always take the union of all traits.

With Swift 6.1, packages may offer traits, which express a configurable API surface for a package.

Use traits to enable additional API beyond the core API of the package.
For example, a trait may enable an experimental API, optional extended functionality that requires additional dependencies, or functionality that isn't critical that a developer may want to disable in specific circumstances.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. Maybe we can say

or functionality that isn't critical that a developer may want to enable only in specific circumstances.

Use traits to enable additional API beyond the core API of the package.
For example, a trait may enable an experimental API, optional extended functionality that requires additional dependencies, or functionality that isn't critical that a developer may want to disable in specific circumstances.

> Note: Traits should always *enable* additional code, never "remove" or disable API when a trait is enabled.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think "enable additional code" is weird here. Developers are generally free to do whatever they want with traits except remove public API.

Within the package, traits express conditional compilation, and may be used to declare additional dependencies that are enabled when that trait is active.

Traits are identified by their names, which are name-spaced within the package that hosts them.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC the latest is that traits use be valid Swift identifiers. We can link to the Swift book's grammar section on this.


The traits enabled by default for the example above is `FeatureA`.

> Note: Changing the default set of traits for your package should be considered a major semantic version change, as it can potentially remove API surface.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not fully true. It is okay to add more to the default traits just not remove traits from the default.

#### Mutually Exclusive Traits

The package manifest format doesn't support declaring mutually exclusive traits.
In the rare case that you need to offer mutually exclusive traits, protect that scenario in code:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add an additional line of caution here that this can result in compilation errors when users of the package enable mutually exclusive traits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants