Un-requiring required initializers

This came up before in the context of Decodable: Why you can't make someone else's class Decodable: a long-winded explanation of 'required' initializers. Specifically, I had these two solutions in mind:

Future Direction: 'required' + 'final'

One language feature we could add to make this work is a required initializer that is also final. Because it's final, it wouldn't have to go into the dynamic dispatch table. But because it's final, we have to make sure its implementation works on all subclasses. For that to work, it would only be allowed to call other required initializers…which means you're still stuck if the original author didn't mark anything required. Still, it's a safe, reasonable, and contained extension to our initializer model.

Future Direction: runtime-checked convenience initializers

In most cases you don't care about hypothetical subclasses or invoking init(from:) on some dynamic Point type. If there was a way to mark init(from:) as something that was always available on subclasses, but dynamically checked to see if it was okay, we'd be good. That could take one of two forms:

  • If 'self' is not Point itself, trap.
  • If 'self' did not inherit or override all of Point's designated initializers, trap.

The former is pretty easy to implement but not very extensible. The latter seems more expensive: it's information we already check in the compiler, but we don't put it into the runtime metadata for a class, and checking it at run time requires walking up the class hierarchy until we get to the class we want. This is all predicated on the idea that this is rare, though.

That second one is pretty close to what you're describing.

However, that post ends with

The Dangers of Retroactive Modeling

Even if we magically make this all work, however, there's still one last problem: what if two frameworks do this? Point can't conform to Decodable in two different ways, but neither can it just pick one. (Maybe one of the encoded formats uses "dx" and "dy" for the key names, or maybe it's encoded with polar coordinates.)

So I'm not convinced yet that this is a good idea. The two examples you've shown are an imported Objective-C class, which can't take advantage of this unless we change the compiler, and conforming a type you don't own to a protocol you don't own, which is *cough* something I'm supposed to be leading discussions on, Retroactive Conformances vs. Swift-in-the-OS. Neither of them are sufficient to motivate this feature in my opinion.

7 Likes