Noah Wilder
Noah Wilder

Reputation: 1574

Widespread Swift Protocol for Extensions

Widespread Protocol for Extensions

Swift 4.1, Xcode 9.3

I was wondering, what are some of the most overarching protocols in Swift. I want to make an extension that applies to values that can be set. The purpose of this was to make it easier to write more one-lined code.


My Extension:

Note: for the time being, the "overarching" protocol that I am extending is Equatable.

extension Equatable {
    @discardableResult public func set(to variable: inout Self) -> Self {
        variable = self
        return self
    }
}

Caveat: I would like to be able to use .set(to: ) for values that don't conform to Equatable as well.


Usage:

let ten = 10
var twenty = 0

(ten + 10).set(to: &twenty)

print(twenty)
// Prints "20"

This can be helpful when you need to set and return a value, now only one line of code is required to do so.

return value.set(to: &variable)

Final Question

How do I make .set(to: ) more far reaching, without needing multiple instances of it?


Bonus Question: is there a way in an extension to do something not dissimilar to extension Equatable where !(Element: CustomStringConvertible) or extension Equatable where !(Element == Int) (use the where predicate for exclusion purposes)?


Upvotes: 1

Views: 187

Answers (1)

Rob Napier
Rob Napier

Reputation: 299345

In most cases, I strong discourage this kind of code. "One-line" code is not generally a goal of Swift. Clear and concise is a goal, with clear winning when they're in conflict. Extending Any this way (even if it were legal) is generally a very bad idea since set(to:) could easily collide.

But in limited circumstances this may be useful within a single file or for a special use. In that case, it's easily implemented with operators.

infix operator -->
private func --> <T>(lhs: T, rhs: inout T) -> T {
    rhs = lhs
    return lhs
}

let ten = 10
var twenty = 0

(ten + 10) --> twenty

print(twenty)
// Prints "20"

The more natural way to do what you're describing is with protocols that you explicitly conform. For example:

protocol Settable {}

extension Settable {
    @discardableResult public func set(to variable: inout Self) -> Self {
        variable = self
        return self
    }
}

extension Int: Settable {}
extension String: Settable {}
extension Array: Settable {}
extension Optional: Settable {}

You can attach Settable to any types that are useful for this purpose, and these extensions can be provided anywhere in the project (even in other modules). There is no way to attach a method to every possible type in Swift.

Upvotes: 3

Related Questions