By Casey Liss
WWDC 2021 Wishes

Last week, Paul Hudson wrote a far more actionable and, well, kind version of my prior post on the… undesirable state of Apple’s documentation. Paul’s post — Reimagining Apple’s Documentation — was largely framed around a WWDC wish list.

I’m taking this chance to make my own WWDC wish list. There are many others like it, but this one is mine. And really, it’s only two items.

1. Improved & Prioritized Documentation

Given my constant kvetching about this, it should be of no surprise that the #1 thing I want from Apple is improved documentation. I can’t stress enough: reading Paul’s post is a great way to see what kinds of actual changes Apple can make to improve finding and using their documentation.

But, as Paul said in his post, it’s more than just that. Apple doesn’t seem to prioritize documentation in the way I think they should. I could quote the entirety of Paul’s post, but this in particular stuck out to me:

No APIs mentioned in the WWDC Platforms State of the Union talk should be allowed to ship with “No Overview Available” as their documentation – either can the feature or prioritize documentation.

For my money, I think this should be true of all new APIs, but that’s not a particularly realistic expectation. Nevertheless, anything that makes it into the Platforms State of the Union — the keynote that’s aimed squarely at developers — should absolutely have fully cooked documentation to go with it.

I also loved this idea of Paul’s:

The top 100 most popular APIs should get either a screenshot or a video showing exactly how it works and what the result is.

Hear hear.

2. More Breadth to Combine

Easily my favorite new API to come out of Apple from the last couple years is Combine. It is a first-party take on ReactiveX, in many ways aping RxSwift in the best possible way.

Combine was introduced at WWDC 2019, and I immediately fell in love. Though it makes many choices I’m not sure I would, I immediately dove in, writing a series of blog posts comparing and constrasting it with RxSwift.

Combine also powers a lot of both Peek‑a‑View and a new thing I’m working on.

Politics Killed the Framework Star?

Last year, at WWDC 2020, I was super amped to see the improvements made to Combine. I was hoping more than anything else to see a Combine knock-off of RxCocoa. This hypothetical set of extensions would allow developers to use Publishers that are exposed by UIKit controls such as UIButton, UITextField, etc.

Unfortunately, that never landed. In fact, there were almost no updates to Combine in 2020. I was, and remain, really saddened by this.

I can only speculate why Combine didn’t get any more love in 2020, but if I were a betting man, I’d guess it’s politics. SwiftUI is the new hotness. Though some of SwiftUI is powered by Combine, a lot of what makes SwiftUI great could be similarly accomplished using Combine and “CombineCocoa”.

If I were the captain of the good ship SwiftUI, I would not be keen to see “CombineCocoa” off the port bow. If there’s an alternative to SwiftUI that leverages all of UIKit, but with some new affordances for faster and easier development, that’s a threat. I’d fire all my cannons, as quickly as possible.

To do so would be immature, and it would be against Apple’s best wishes. The best thing Apple can do is provide as many options for developers as they can. Why should I have to throw away my years-deep knowledge of UIKit just to use SwiftUI?

One of the things that made Swift great — from day one — was its ability to coexist [mostly] gracefully with Objective-C. The same is true of SwiftUI: UIKit and SwiftUI can [mostly] coexist without too many compromises. As a developer, this affords me the ability to use the right/best tool for the job: SwiftUI for things that are less interactive; UIKit for when I have intense/complex interactions, or need to have deeper control.

My money is on Combine being neutered — if not straight-up scuttled — by an over-zealous SwiftUI champion, politicking within Apple. I surely hope that isn’t the case, because a rising tide raises all boats. Giving developers like me the option to use whichever tool is the best fit for the job makes for better apps, and a better user experience on Apple devices. Dare I say, Tim, that it also increases customer sat?

What Does Combine Need?

To my eyes, there’s a couple of ways that Combine could be improved. In summary, it could mostly be summarized as “more breadth”.

Combine could most directly be improved by increasing its coverage of legacy APIs. When Combine originally shipped, it included some very simple but very useful bindings for URLSessiondataTaskPublisher(for:) — and for NotificationCenterpublisher(for:object:). I’d love to see many other Apple APIs get this kind of basic Publisher coverage:

That’s just a few that jump to mind off-hand. There are so many others that could stand to get the same treatment.

Another thing that I really wish Combine had — and which existed in some early betas! — is a way to programmatically create a Publisher with a closure. Effectively, I’d love to have the equivalent of Future.init(:) that worked for Publishers that signal more than once.

I know that this is one of the many neat things that is added in CombineExt, but it’d be great if I could create Publishers via closure without having to bring in an entire open-source project.

(See also some other neat CombineExt tricks like materialize.)

Why Bother with Combine?

A keen-eyed observer may note that there are several technologies that are very close to landing in Swift that may obviate Combine entirely. Some obvious examples:

Both of these tools do a great job covering some of the Combine surface area. However, they leave out most of what makes Combine so great.

The Components of Combine

To my eyes, Combine is a combination of a few different things:

  • A consistent way to do multi-threaded/asynchronous programming
    • …including a consistent and understandable way of hopping between threads
  • A consistent way to deal with asynchronous messaging:
  • A consistent way to manipulate streams of data

To most, the first two items — asynchronicity and messaging — may seem like the stars of the show. Au contraire, mon ami. For my money, manipulation is the real winner. Take a gander at the sidebar on RxMarbles. There are so many classes of things one can do with an Observable/Publisher:

  • Conditionals
  • Combinations
  • Filtering
  • Mathematics
  • Transformation
  • Timing

Note that each of those groups above has many operations that can be performed. It’s quite a bit more than just .map(), .compactMap(), and .flatMap().

It’s this incredibly broad and deep collection of operations that allows the canonical example of how powerful Combine/functional reactive programming can be:

let searchTerms: AnyPublisher<String, Never> = /* ... */
let searchRequestPublisher = searchTerms
    // Don't send values until they've been 
    // static for at least 0.3 seconds
    .debounce(for: .seconds(0.3), scheduler: RunLoop.main)
    // Don't send values until they're 
    // more than 3 characters
    .filter { query in  query.characters.count > 3 }

With this combination of a timing operator (.debounce(for:scheduler:)) and a filtering operator (.filter(_:)) makes it possible, with two lines of code, to ensure that searchRequestPublisher only gets new values when the text the user input has been still for 0.3 seconds, and is more than 3 characters.

Actors and async/await Aren’t Enough

All of these things are absolutely possible with Actors, and with async/await, but there is so much more code required.

async/await — or, at least, my understanding of it today — makes asynchronous programming easier to both write and reason about. Asynchronous code written using async/await looks, at a glance, almost identical to the synchronous code we are all used to.

Actors build on the vast improvements of async/await and, via convention as well as compiler rules, prevent race conditions, and generally ensures improved safety, particularly around threading and data access.

All of these protections and affordances are important. In some cases, even as a devout Combine fan, I can absolutely see myself turning to async/await or Actors in order to accomplish a task. Here again, that’s what makes all these technologies so great: they permit me to use the best tool for the task at hand.

So, Apple, my wish is for you to re-discover Combine, refine it, and build it out. However, reading the tea leaves, right now I’ll happily settle for you not sending Combine out to pasture. 🥺

One More Thing

The iPad hardware is ridiculously powerful. Please, please, can we have some software improvements to match? Some things that I prefer to do on my Macs that I can’t do nearly as effectively on my iPad:

  • Managing more than two concurrent applications
  • Any sort of proper software development
  • Culling and ingestion of photos, particularly from my big camera
  • Podcasting

Granted, not all of these things I necessarily want to do on my iPad, but it really chaps my behind that I can’t. Or if I can, without having so many gotchas and caveats that it makes it a waste of time.

You’ve given yourselves such powerful hardware. Let’s combine forces and make use of it, together.