Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift protocol similar to Equatable

I’m trying to create a protocol for types that are Lerp-able (linear-interpolatable). I’m declaring it similarly to how Equatable is defined:

protocol Lerpable {
    func lerp(from: Self, to: Self, alpha: Double) -> Self
}

Unfortunately, when I try to implement Lerpable for Double:

func lerp(from: Double, to: Double, alpha: Double) -> Double {
    return from + alpha * (to - from)
}
extension Double: Lerpable {}

I get an error: Type 'Double' does not conform to protocol 'Lerpable'.

I assumed this would be pretty straightforward, but maybe I just don’t understand how Equatable works. Or is it a special case in Swift? Any thoughts?


UPDATE: The correct answer is below, and here’s the final version of the code, for others’ reference:

protocol Lerpable {
    func lerp(to: Self, alpha: Double) -> Self
}

extension Double: Lerpable {
    func lerp(to: Double, alpha: Double) -> Double {
        return self + alpha * (to - self)
    }
}

func lerp<T: Lerpable>(from: T, to: T, alpha: Double) -> T {
    return from.lerp(to, alpha: alpha)
}

I added the global lerp function so I could still refer to it as
lerp(foo, bar, alpha: 0.5)
rather than
foo.lerp(bar, alpha: 0.5)

like image 865
David Cairns Avatar asked Oct 19 '25 02:10

David Cairns


1 Answers

To fix your problem you need to put the lerp function inside your extension, like so:

extension Double: Lerpable {
    func lerp(from: Double, to: Double, alpha: Double) -> Double {
        return from + alpha * (to - from)
    }
}

If you have a look at the Equatable protocol:

protocol Equatable {
    func == (lhs: Self, rhs: Self) -> Bool
}

The reason you declare its method (== specifically) outside your type extension is because Equatable wants you to overload an operator and operators must be declared at global scope. Here's an example to clarify:

protocol MyProtocol {
    func *** (lhs: Self, rhs: Self) -> Self
}

Now to make Int adopt the protocol:

extension Int : MyProtocol {}

infix operator *** {}
func *** (lhs: Int, rhs: Int) -> Int {
    return lhs * rhs
}
like image 199
ABakerSmith Avatar answered Oct 21 '25 15:10

ABakerSmith



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!