Hello,
The upcoming 6.0 release of Swift-DocC has a handful of enhancements for documenting API with representations in multiple source languages. In this post I'd like to talk about one such enhancement: validation and processing of documentation for parameters and return values. This is currently opt-in, controlled by a --enable-experimental-parameters-and-returns-validation
flag.
There are two parts to this enhance that each solve a different problem:
- Different language representations of an API can have different parameters and return values.
- Sometimes when we update an API we forget to document new parameters or return values.
Different parameters in different language representations
One primary example of API with different parameters and return values is throwing functions in Swift that correspond to Objective-C methods with error parameters.
For example: @objc func doSomething(with someValue: Int) throws
with one parameter and no return values corresponds to -(BOOL)doSomethingWith:(NSInteger)someValue error:(NSError **)error
with two parameters and one return value.
It's common to document parameters and return values alongside the API declaration which means that depending on what source language the API is defined in, the other language representation may have too many or too few parameters documented.
By default, DocC will display all documented parameters and return values for all language representations of that API. However, when DocC is passed the --enable-experimental-parameters-and-returns-validation
flag it will check the documented parameters and return values against each language representation's signature (information emitted by the compilers into their respective symbol graph file). If a parameter or return value doesn't exist in one language representation then it won't be displayed in that language's version of the documentation page.
For example, this Objective-C method will display both its parameters and the return value on the Objective-C version of its documentation page but only the first parameter on the Swift version of its documentation page
/// A method that does something.
/// - Parameters:
/// - someValue: A description of this number.
/// - error: On input, a pointer to an error object. If an error occurs, this pointer is set to an object containing information about the error.
/// - Returns: `YES` if doing something was successful, or `NO` if an error occurred.
- (BOOL)doSomethingWith:(NSInteger)someValue
error:(NSError **)error;
This works well for API defined in Objective-C—where there are "extra" parameters or return values—but it doesn't help with the missing parameter or return value documentation if the API is defined in Swift.
To address this—specifically for throwing Swift API that correspond to an Objective-C method with an error parameter—DocC will add a generic description for the error parameter and extend the return value documentation to describe the Objective-C specific behavior. For example, consider this method in Swift that corresponds to the Objective-C method above:
/// A method that does something.
/// - Parameter someValue: A description of this number.
@objc func doSomething(with someValue: Int) throws { }
Since the Objective-C API has an extra "error" parameter and a BOOL
return value, DocC will display an extra parameter and return value description on the Objective-C version of this page.
error
On input, a pointer to an error object. If an error occurs, this pointer is set to an actual error object containing the error information.
and a synthesized return value documentation with the generic description:
Return Value
YES
if successful, orNO
if an error occurred.
If the Swift API has a non-optional return value that corresponds to an optional return value in Objective-C, for example:
/// A method that returns something.
/// - Returns: Description of the return value.
@objc func returnSomething() throws -> String { "" }
then DocC will add a new paragraph to the authored return value documentation to describe that the return value may be nil
if an error occurs.
If an error occurs, this method returns
nil
and assigns an appropriate error object to theerror
parameter.
Both these behaviors are controlled by the --enable-experimental-parameters-and-returns-validation
flag.
Documenting new parameters when API is updated.
By default, DocC lets you document any parameter or return value for any symbol, in any order, potentially more than once. However, when DocC is passed the --enable-experimental-parameters-and-returns-validation
flag it will check the documented parameters and return values against each language representation's signature.
Note:
If none of the symbol's parameters have documentation DocC will not warn about adding parameter documentation. However, if some of the parameters have documentation, DocC will warn about documenting the other parameters as well. We believe that this strikes a good balance in highlighting parameters that the developer intended to document without overwhelming the project with warnings.
API without function signature data
Both these behaviors rely on the compiler emitted "function signatures" for each symbol. If a symbol doesn't have a function signature—either because the symbol graph is from a tool that doesn't emit function signatures or because the specific symbol isn't a function-like symbol kind—DocC will behave as before and use the authored parameter and return value documentation without any processing or validation. This allows symbols in custom symbol graphs to have parameters and return value documentation.
One open question is what the right behavior is when a symbol has signature information in one language representation but not in another. For example, this C function is refined as a property in Swift, which isn't function-like and doesn't have a "function signature".
/// Returns whether a circle has zero radius.
/// - Parameter circle: The circle to examine.
/// - Returns: `YES` if the specified circle is empty; otherwise, `NO`.
BOOL TLACircleIsEmpty(TLACircle circle) NS_SWIFT_NAME(getter:Circle.isEmpty(self:));
Hiding the parameter and return value documentation for the Swift property (which is correct) would have the tradeoff that other tools that create symbol graph files need to emit function signatures going forward if the API they represent is also available in other languages.
How to try it
- Use a toolchain from either the
main
orrelease/6.0
branches, created after February 14th. You can download such a toolchain from the downloads page. - Pass the
--enable-experimental-parameters-and-returns-validation
flag to DocC, either by adding it to the end of yourswift package generate-documentation
call or by adding it to the Other DocC Flags build setting (OTHER_DOCC_FLAGS
) in your Xcode project.
If you have symbols with different parameters in different language representations, you should now see only the applicable parameters and return values documented in each language's version of that symbol's documentation page.
If you have symbols with extra parameter or return value documentation (even in Swift-only projects), you should now see warnings with suggestions. For example:
warning: Parameter 'smoeValue' not found in function declaration
--> ../SomeFile.swift:12:7-12:60
9 |
10 | /// - Parameters:
11 + /// - smoeValue: Some description of this parameter.
| ╰─suggestion: Replace 'smoeValue' with 'someValue'
12 | public func doSomething(with someValue: Int) { /* ... */ }
Going forward
We believe that both of these behaviors are useful with very little tradeoffs and hope to enable this by default—with a --disable-parameters-and-returns-validation
flag to go back to the previous behavior—sometime in the 6.0 release and refine these behaviors throughout the 6.0 release.
We look forward to hearing how this works in your projects and to talk about refinements to both the processing of language specific parameter and return value documentation as well as warnings about parameter and return value documentation.