Search code examples
swiftswift-extensionsanyobject

How can you create an infix operator that applies to every class and struct?


I've created a 'configure' infix operator '=>' which lets me configure objects inline, allowing me to both define and initialize properties and/or call methods/functions at the assignment level.

For instance, instead of this, which requires an initializer...

let redSquare = SquareView()

init(){ // Some init somewhere

    redSquare.backgroundColor = .red

}

I can simply do this...

let redSquare = SquareView() => { $0.backgroundColor = .red }

The 'configure' operator is implemented like this...

infix operator =>

public protocol Configurable {}

extension Configurable {

    public typealias ConfigureDelegate = (Self) -> Void

    @discardableResult
    public static func => (this:Self, _ delegate:ConfigureDelegate) -> Self {
        delegate(this)
        return this
    }
}

extension NSObject : Configurable {}

Note: You could also implement this as a member function like below, but I prefer the infix operator as it doesn't clutter the . (dot) completion.

public protocol Configurable {}

extension Configurable {

    public typealias ConfigureDelegate = (Self) -> Void

    @discardableResult
    public func configure(delegate:ConfigureDelegate) -> Self {
        delegate(self)
        return self
    }
}

extension NSObject : Configurable {}

As you can see, I already make NSObject conform to this protocol, but realistically, this should be able to be utilized by anything that needs to set properties not passed through an initializer, or anything that requires a method/function to be called as part of its initialization.

Currently, this means I just have to keep adding this everywhere (for non-NSObject-based items)...

extension MyStruct     : Configurable {}
extension MyClass      : Configurable {}
extension MyOtherClass : Configurable {}

This one's not allowed (which really annoys me!)

extension AnyObject : Configurable {}

In C# for instance, you can extend everything by simply extending 'object' since that is the base for everything (ironically including value types), but it doesn't look like there's anything similar in Swift.

Is there, or do I just have to keep manually adding those conformances?


Solution

  • If all you want is an operator that applies a closure to whatever type you throw at it, than a protocol isn't really the right approach here. A plain generic operator (function) will do the trick:

    infix operator =>
    
    @discardableResult func => <T>(this: T, _ delegate: (T) -> ()) -> T {
        delegate(this)
        return this
    }
    

    This can be used in exactly the way you outline, without needing to extend anything.