Deduplicating documentation comments through protocols or inheritance

I consider two of Swift’s biggest strengths to be composition and documentation. That means using internal protocols to formalize implementation requirements and using Markdown to explain exactly what each declaration is, does, or is meant for.

Unfortunately, these two features often feel at odds with each other. It is impossible to document inherited declarations without overwriting all existing documentation, and that has extremely serious consequences for long-term maintenance.

Consider Decodable, a true gem of Swift’s standard library. One of the protocols it uses, Decoder, has a userInfo property designed for passing information that helps with decoding. It’s very flexible, but it has an obvious weakness: it is more or less impossible to tell what a type is expecting users to put in there.

This is best solved through careful documentation, of course. But if you try to add any, this:

/// Creates a new instance by decoding from the given decoder.
///
/// This initializer throws an error if reading from the decoder fails, or
/// if the data read is corrupted or otherwise invalid.
///
/// - Parameter decoder: The decoder to read data from.
init(from decoder: Decoder) throws

becomes something like this:

/// - Important: Before decoding from a server response, add the `Date`
/// that the response was generated (if available) to the decoder’s `userInfo`
/// dictionary with a key of `responseDate`. This is used to correct for the
/// server’s inaccurate clock.
init(from decoder: Decoder) throws

Clearly, this is not the desired outcome. Copying the original documentation works (you can see that all over the standard library), but what happens if that original changes? Adding documentation to a different declaration (like the type itself) avoids clobbering the original, but that’s easily missed at the point of use. A lot of people just forgo documenting implementation specifics entirely: how often do you see decoding initializers describe the errors they might throw?

I’m not sure what the best solution to this is, but I am sure that one is called for.

2 Likes