Extending multiple types at once with `extension`

The ability to provide a default implementation for a protocol surely is a great tool to avoid repetition.

Take for example a protocol Foo with only one method bar that provides a default implementation:

protocol Foo {
    func bar()
}

extension Foo {
    func bar() { ... }
}

Conforming to the protocol and receiving the default implementation for free is effortless:

extension TypeA: Foo { }

But this task can sometimes be repetitive when there are multiple types that need to conform to the protocol and receive the default implementation:

extension TypeA: Foo { }
extension TypeB: Foo { }
extension TypeC: Foo { }
extension TypeD: Foo { }

I personally think it would be more concise if Swift had a syntax like this:

extension TypeA, TypeB, TypeC, TypeD: Foo { }

As a side thought there may be merit in permitting writing extensions like this:


extension TypeA, TypeB, TypeC, TypeD {
    func baz() { ... }
}

This would allow extending multiple Types at once without using a protocol with a default implementation.

1 Like

It would definitely be more concise, but it's quite a complicated feature unless it's limited to just conforming to a protocol, which would create a weird inconsistency for extension. In your last example, determining what you can usefully do from inside baz() would either require intersecting all the capabilities of TypeA-TypeD or not allow you to use any properties or methods from those types, which really limits how useful this would be.

3 Likes

Sounds like an interesting concept, but I wouldn't know what to do with it.
Do you have some real-world examples?

There have been some threads about partial classes ("extensions with stored properties") in the past - if support for those is added, your concept would be much more powerful, and could act as replacement for inheritance for structs.
But I guess partial classes won't happen until Swift 8 ;-) (if at all)

@jawbroken Thanks for the feedback!
Yeah the thing I mentioned as a side note really isnt too useful after all, after giving it more thought.

I think it would make more sense to just focus on deriving multiple types to a protocol at once.

@Tino Yeah the idea is a little off-center but I got the idea for this from writing extensions in the style that RxSwift does where there is a psuedo namespace trick where extensions are not written directly but in the style of foo.rx.someRxOperator instead of foo.someRxOperator.

I use that same style in my library here:

If you look at the bottom of that you will see:

extension String: AttributedCompatible { }
extension NSString: AttributedCompatible { }
extension NSAttributedString: AttributedCompatible { }

Basically I want those three types to inherit AttributedCompatible default implementation but I have to write it out as it is written above.

It would be more concise if I could just write:

extension String, NSString, NSAttributedString: AttributedCompatible { }
1 Like

This thread came up in a search for something similar. An example that I can think of is what if you have a mixture of SwiftUI and UIKit. Right now I have an extension on Color with a bunch of static properties for all the colors used with the app. When it comes to UIKit they have a UIColor initializer that can take in a Color, but you only get that with iOS 14. It would be nice to make an extension for UIColor and Color with static properties so I don't have to write them twice. I could just use an enum I guess. But that's an example, I guess, where it might be nice to have that option to be able to do extension Color, UIColor { }

1 Like

Yeah I think being able to extend multiple things in one line would be cleaner in some cases. Currently the best you can do if you need to conform multiple types to a protocol that has a default implementation that is good enough to use as is, is something like this:

extension TypeA: MyProtocol { }

extension TypeB: MyProtocol { }

extension TypeC: MyProtocol { }

But wouldn't it be easier to read if you could do something like this?

extension TypeA, TypeB, TypeC: MyProtocol { }
1 Like