Swift-DocC treats overloads — which I'm defining as symbols of a particular kind with identical base names and argument labels but different argument types and return types — as distinct symbols, each with its own documentation page. I propose adding an optional feature to DocC that, when enabled for a given build target, collects all the symbols that are overloads of each other onto a new kind of merged-symbol documentation page. The merged-symbol pages replace the individual pages that DocC would otherwise create for each overloaded symbol.
This change improves the navigation experience for readers by reducing repetitive information in both the sidebar and in topic groups of the rendered documentation. It reduces the number of results that turn up in web searches and sidebar filtering by folding overload pages into a single page. And for the same reason, it enables simpler linking to overloaded symbols, both for documentation authors and for others linking to your public content.
Motivation
Today, DocC automatically generates a unique page for every public symbol using the symbol’s full name as the last path component of the symbol’s URL. Every class, structure, and enumeration gets a page, as does every initializer, property, method, and so on within those entities. This ensures that documentation represents every part of the API without depending on a writer to manually identify each symbol. DocC links to all of these pages from the sidebar, as well as from topic groups that appear on other symbol or collection pages.
Separately, Swift supports overloads, which are symbols that have the same full name, differing only in generics or types. Typically, these kinds of symbols also have substantially similar behavior, performing a common operation on different kinds of inputs. For example, the following methods from SwiftUI are overloads because they have the same name, specifically searchable(text:placement:prompt:)
, and differ only in how they acquire the text for a prompt:
func searchable(
text: Binding<String>,
placement: SearchFieldPlacement = .automatic,
prompt: Text? = nil
) -> some View
func searchable(
text: Binding<String>,
placement: SearchFieldPlacement = .automatic,
prompt: LocalizedStringKey
) -> some View
Supporting Swift overloads in the face of a one-page-per-symbol strategy creates challenges for both readers and authors. For example:
-
The docs contain multiple pages about what is conceptually a single, configurable behavior. Being presented with many substantially identical pages (in the sidebar, in a topic group, or in search results) adds to the reader’s cognitive load and reduces discoverability. Which page should I look at? Do I need to visit all of them? How do they differ? Ideally, there would be a single place to read about a particular behavior.
-
Link text is hard to read. To enable readers to distinguish between overloaded methods that appear in a list of symbol links, like in the sidebar or a topic group, DocC includes type and generic information in the link text in those places. This creates long, noisy links that are hard for a reader to scan through. The length also frequently produces truncation in the sidebar, eliminating the advantage that including the extra information was meant to confer. Meanwhile, the type and generic information typically isn’t relevant to a reader at this point in their journey, when they are browsing to learn what kinds of things are broadly possible.
-
An overloaded symbol’s URL is obscure. Because the last path component of a symbol’s URL is the symbol’s name, DocC appends a unique string to the URL of an overload to distinguish it from other overloads with the same name. However, these strings are hard for humans to discover or interpret, and can change in surprising ways as the code evolves, making overload symbol URLs difficult to work with for both readers and authors. For example, you can directly type the URL of a symbol into your browser if you know its name, but that isn’t possible if the symbol is an overload.
Proposed solution
I propose combining the documentation for all the overloads of a particular symbol onto a single page. The combined page provides enough information for a reader to discover all the overloads that the page represents, as well as a means to focus on a particular overload. To avoid overwhelming the reader, the page updates its content to reflect the overload in focus, including automatically-generated content like availability markers, as well as writer-generated content like abstracts and discussions. In most cases, most of the information across overloads is the same, with the primary difference being the types that appear in the declaration. However, updating all the content per selected overload provides flexibility for when there are differences.
Under this proposal, DocC applies overload page unification automatically, without writer intervention. A symbol that DocC identifies as an overload gets collected onto a page with its related overloads. Automaticity ensures uniform treatment across an entire project, and enables improvements to the way content is presented and accessed.
Because there is one page per overload, DocC can:
-
Present all the information about a group of overloaded symbols in one place. There are fewer pages a reader needs to visit to discover all the possible behaviors.
-
Simplify presentation of symbols at the point of curation. In links that appear in the sidebar and in topic groups, DocC can omit type and generic information, just like it does when rendering a symbol as a link inside a discussion. This makes it easier to scan through the list of available symbols.
-
Simplify symbols URLs. In the vast majority of cases, authors and readers won’t need to concern themselves with the unique strings that DocC uses to distinguish between the URLs of overloads.
Detailed design
Definitions
This proposal uses the following terms:
-
A symbol’s full name is the combination of its base name and, if applicable, argument labels (the keywords you use to refer to parameters at the call site) listed in parenthesis, delineated by trailing colons. The full name omits types and generics, as well as parameter names (which you use to refer to parameters inside a method, if different than the argument label). For example, this is the full name of one of the initializers for the
Option
structure inArgumentParser
:init(name:parsing:help:completion:)
In contrast, the initializer's type signature includes type and generic information:
init<T>( name: NameSpecification, parsing: SingleValueParsingStrategy, help: ArgumentHelp?, completion: CompletionKind?)
-
A full-name overload — which I refer to simply as an overload throughout this proposal — is an initializer, method, function, subscript, operator, or property that has the same full name as another of the same kind of entity in the same scope. A symbol can be an overload of any number of other symbols. Two symbols with the same full name but of different kinds or in different scopes are not considered overloads, and remain completely distinct symbols. Similarly, symbols with the same base name but different arguments are not considered overloads.
-
An overload group is a collection of symbols that are overloads of one another.
-
A disambiguating hash — sometimes just referred to as the hash — is the small handful of characters that DocC appends to the URL of an overload that differentiates its URL from all the others in the same overload group. DocC calculates the hash based on additional information about the symbol, including its type signature and full scope.
Importantly, the hash is distinct from the type string that DocC uses to distinguish symbols with the same full name, but of different kinds, which are not considered overloads for the purposes of this proposal. For example, the following two methods are not overloads:
public class Something { public func something() -> Int { 0 } // something()-method public static func something() -> Int { 0 } // something()-type.method }
Presentation
The merged page
All the symbols in an overload group appear on a single page that resembles the symbol pages in use today. Most of the information on the page — including eyebrow, title, abstract, availability markers, deprecation message, parameters, discussion, and return value — comes from the content associated with the overload that is currently in focus. Note that the eyebrow (which reflects the kind of symbol) and title (which is the full name) are the same for all overloads in the group. Otherwise, they wouldn’t be overloads.
The main difference is the declaration section, which now includes a collapsible list of declarations, with one declaration per overload. The page visually highlights the declaration of the overload that’s in focus and that corresponds to all the other content on the page. People browsing the page can use a new UI element below the declarations to alternately collapse and expand the declaration list. They can also click on any of the declarations when the list is expanded to bring a different overload into focus.
The sidebar
Today, the sidebar displays links to symbols using the type signature:
DocC uses this formatting for all symbols, whether part of an overload group or not, and whether an author has manually curated the symbol or DocC has automatically curated it. With the new feature enabled, DocC will instead display links to symbols using only their full name, and will only display one link per overload:
As an exception, an author might choose to link directly to a specific overload in manual curation if the author judges that the symbols in the overload group are different enough to warrant individual listings. While that’s likely to be rare, DocC will in that case revert to displaying the type signature for each explicitly named overload.
Topic groups
Today, DocC presents symbols in topic groups using three elements: the type signature as link text, an abstract, and optional generic information with zero or more statements like “Available when Element
conforms to Equatable
.”
After this change, these elements change as follows:
-
Link text - Like in the sidebar, topic group links will by default use full names, and will only use the type signature in rare cases when the author chooses to link to a specific overload from manual curation. In other words, the link text in the topic group will continue to match the link text in the sidebar.
-
Abstract - DocC continues to display abstracts, as before. However, each overload in a group might have its own abstract (along with other documentation content), so DocC must choose which of these to display in the topic group listing for a merged page. To resolve this, DocC will display the abstract of a deterministically selected overload — for example, sorting the overloads by type signature and then choosing the first of those with a non-empty abstract, if any.
-
Generics - Generic statements will be omitted. That information can be different per overload (indeed, it can be all that is different per overload), and in those cases there isn’t one statement that applies to all the symbols in the overload group. That information was and continues to be available on the symbol’s page, which is where a reader typically needs the information anyway.
Links in discussions
Today, DocC presents links to symbols that appear in discussions using the symbol’s full name.
This proposal doesn’t change the above presentation, but the behavior can vary slightly for overloaded symbols, depending on how the author constructs the link. Specifically, authors can choose a particular overload to bring into focus when someone follows the link. If authors don’t specify a particular overload, DocC chooses a default overload instead.
Authoring
Content
Writers don’t do anything special to author content for an overload. They provide the usual fields in documentation comments in source or in extension files as before, including abstract, discussion, and if applicable, parameters and return value. DocC decides where and how to display this information as described earlier in this proposal. In particular, DocC displays the content on the merged page that’s associated with the overload that’s currently in focus.
DocC chooses one abstract from all of the overload symbols to display in a topic group. As such, writers will typically use the same abstract for all of the overloads, and keep it generic enough to apply to all the overloads in the group. That way, it doesn’t matter which one DocC displays in a topic group.
Links
After the new feature is implemented, writers (and external linkers) can omit the disambiguating hash that overloads require today, and DocC still displays the merged page, but puts the first overload in focus. The “first overload” should be chosen deterministically.
Writers can optionally link to overload symbols using the disambiguating hash, as they did before. Thus, this proposal doesn’t invalidate any existing links that appear in current documentation, or made by external parties to your public documentation. DocC follows the link by displaying the merged overload page and putting the referenced symbol into focus.
Future directions
Group by base name rather than by full name
This proposal considers symbols with the same full name to be overloads of each other. In the future, DocC could add an option to broaden the definition of overloads to include methods with the same base name and different arguments. That would reduce the total number of pages readers need to visit to learn about a particular kind of functionality, but at the expense of some discoverability in the sidebar and in topic groups, plus the need to accommodate more variation on the merged page.
Enable manual definition of overloads
This proposal specifically adds no new syntax for authoring docs, but in the future it might be useful to define some markup that enables authors to indicate a default overload or a sort order. DocC would then use that information to present overloads on the merged page, as well as to pick the abstract to display in the topic group to represent the entire group.
As a further step, DocC could enable authors to manually define overload groups, either in addition to or in place of the overload groups that DocC detects automatically. This would require new syntax to mark methods as overloads of each other, as well as a generalization of the merged page to allow for a wider variety of differences between the overloads.