[Pitch] Simplified API Signature Mode

People often complain online that Swift has too many keywords. Whether or not that's fair, I think some of those keywords get in the way of progressive disclosure in documentation.

Consider Task initializer:

@discardableResult
init(
    priority: TaskPriority? = nil,
    operation: sending @escaping @isolated(any) () async -> Success
)

While each keyword has a meaning and serves its purpose, this kind of highly technical function signature, though accurate, obscures the primary intent.
That’s scary and overwhelming for someone who just started learning SwiftUI and wants to call an async function to make a network request inside a SwiftUI Button action.

What if DocC had a simplified mode (enabled by default and optionally disabled), so that only essential information is displayed?

The simplified version of the above could be:

init(
    priority: TaskPriority? = nil,
    operation: () async -> Success
)

This preserves the core purpose while omitting details that are not essential for most readers.

This simplified mode would offer progressive disclosure in documentation. When—and if—you reach the point where it matters to know that operation is a closure that is sending @escaping @isolated(any), you can refer to the full documentation.

Another example is the map function:

func map<T, E>(_ transform: (Self.Element) throws(E) -> T) throws(E) -> [T] where E : Error

For someone who just wants to map [Person] to [String] , a simplified version would be enough:

func map<T>(_ transform: (Self.Element) -> T)

With this signature, you don’t have to immediately learn about errors or even Self.
With this signature, you don’t have to immediately learn about errors.

As an educator, I try to show students the official documentation as much as possible, but often I have to ask them to abstract away or ignore certain parts. It’s still really hard for them not to get distracted. It’s probably even harder for a self-learner who just reached the documentation on their own.

I believe this kind of simplification could make Swift documentation more approachable and friendly for newcomers.

3 Likes

I agree that two modes, basic and advanced, would be good. I think it would help in both cases, as I would want to see even more details in the advanced view (currently, some annotations are not included) and beginners cannot do much with the various isolation modes and many other annotations.

However, I would not simplify Self.Element to Element. Otherwise, it’s confusing whether there is a type called Element. This is particularly relevant when the type placeholder is named something like Result which is a normal type otherwise.

3 Likes

Yes, I went too far :sweat_smile:

My reflex is to think about how this would be implemented before solidifying an opinion, and i see 3-4 separate changes necessary for this, from bottom to top:

  1. The source data for the "declaration section" at the top of the page comes directly from the Swift compiler, and i think that i would want to start there, to annotate some of the "tokens" as being meant for "advanced mode" display.
  2. Technically swift-docc-symbolkit will need a PR to update its specification and structure definition to add the new annotations, like a new field on a type or something like that.
  3. I don't remember offhand if Swift-DocC itself will need to have a separate PR to ferry the information across to Swift-DocC-Render, but it will likely want to have a PR to update the Render JSON specification regardless.
  4. Swift-DocC-Render will need to accept this new field and surface a new toggle to show/hide the "advanced" tokens.

Taking a step back, i'm not sure i would have the "simplified" declaration be the default presentation; each of those extra keywords and attributes have a special meaning that is important to understand how to use a method. However, i do agree that having a "simplified" mode that you could toggle could aid understanding a lot. Just getting it down to the parameter names and types, discarding any leading attributes, etc, would help to get to the bones of what a symbol needs, before layering on the extra semantics that fill in the extra details.

I do kinda worry about deciding what counts as an "advanced" token, though. That can go down a deep bikeshed if we're not careful... :sweat_smile:

1 Like

I'd have to say no, as even the current hiding of @_ attributes goes too far and hides important information. Unless there's immediately obvious UI that says attributes have been hidden and they can be revealed with a single click or key press, nothing should be hidden by default.

5 Likes

My concern with this approach is that it is, on its own, a valid declaration but crucially not the Task initializer's actual declaration. Which would mean that, on its face, it is incorrect and potentially misleading to users.

Currently, various tools such as Xcode's autocomplete simplify certain aspects of the signature in a way that does not alter meaning but does improve readability: for example, func f<T: P>(_: T) can be spelled out as f(_: some P), which is entirely fine if you're calling it. I think it would be unproblematic if documentation tools similarly took declarations and applied "maximal" sugar in a meaning-preserving way.

Additionally, anything that can be made implicit would be fine to make implicit: for example, perhaps we present a toggle for default @MainActor mode in documentation, just like there is in projects, and in that mode @MainActor annotations could be elided as-though the actual declarations were written in that mode.

However, I am very leery about documentation (even opt-in) which displays a declaration that is plausibly whole but not the actual declaration, in the name of "simplification." That seems counter to our design philosophy: we (deliberately) don't have a "learning" mode that teaches faux-Swift to beginners but rather try to make real Swift behave in a way that's learnable. With this approach to documentation, however, we'd be inventing rules for a faux-Swift that exists only in a documentation preference setting.

My view would be that if there are attributes which make the language unusable for beginners, it is a symptom of a larger problem in the progressive disclosure story for the underlying language and not something we should just hide in documentation.

Additionally, as a procedural matter, if documentation tools were to decide to undertake the work of deciding what's "simplified" Swift, this would inevitably lead to pressure that it be an actual dialect of Swift, and I think the work of undertaking that design (including whether to do so or not) falls properly under language evolution and not tooling.

4 Likes

Yes, that's what I had in mind.

I wouldn't say theses keywords and attribute make language unusable for beginners, Task usage is actually really simple:

Task { await something() }

The problem is that before before using it, beginners are spooked by it's initializer signature.

This sounds like a good argument for the layout of our documentation to surface call-site usage first instead of the declaration signature. But it does not address the concerns above about presenting a declaration signature other than the real one.

3 Likes

This could be a good alternative! How would be a generated call-site usage of Task?

Myabe the simplification could be made explicit, with a clear indication and a button to expand the declaration signature (So it's still there easily accessible, if you want to open the door and see the monster, that's on you :sweat_smile:)

I was thinking it would be manually written out, just as almost all other parts of the documentation for methods are (for example, we don't currently autogenerate documentation about the parameters and return value).

However, it's certainly plausible that we could have tooling which takes the declaration site and generates an example function call, perhaps with variable assignment if there is a return value and without one if it's discardable, defaulting all default arguments, using camel-cased variable names autogenerated from the parameter documentation for non-defaulted arguments, etc.

This would certainly speak directly to your concern about how to present information for someone who, for example, "just" wants to know how to map a [Person] to [String]—an actual, valid use site contains precisely that information.

Inventing new rules to re-create an imaginary declaration site for the reader to then extrapolate what the call site should look like, even if it were not misleading, seems like only an indirect way of accomplishing that goal.

2 Likes

I envision some toggle like Show full form right next to the declaration. While I often want to see it all, including @_… attributes, often I am better served with a compact form that tells me mostly about the basic input/output. So, I foresee myself switching on a regular basis, taking advantage of both perspectives.

1 Like

I did some design prototyping:

3 Likes

I very much share your pain, I teach Swift to children. However I don't think hiding error and concurrency information is the way to go, I'd much rather see improvements to the presentation of information and the written content of documentation.

I do believe there are a few quick wins we could make: the maximal sugar idea is something I'd love to see, it would also help people realize they can probably simplify their own signatures with it.

Something I just thought of but am unsure about: presenting a symbol's "context" (like extension Collection<Element>) which might give you some context to simplify the signature. You could write Element directly.

In general I find Apple's documentation lacking compared to other languages or even their old documentation. Way too many symbols have barely a summary or paragraph, sometimes nothing at all, often omitting to explain behaviour or note invariants, rarely adding examples, inconsistent writing and structure, etc.

Concurrency has many ways to express similar things with completely different notation and in general feels inconsistent but I think this may just be because of how recent it is. With more experience (and the automatic migration command) it may be feasible to unify inconsistent attributes and rename things during a major version.

3 Likes