2

As an exercise, I'm trying to extend Array in Swift to add a sum() member function. This should be type safe in a way that I want a call to sum() to compile only if the array holds elements that can be added up.

I tried a few variants of something like this:

extension Array {

    func sum<U : _IntegerArithmeticType where U == T>() -> Int {
        var acc = 0
        for elem in self {
            acc += elem as Int
        }
        return acc
    }

}

The idea was to say, “OK, this is a generic function, the generic type must be something like an Int, and must also be the same as T, the type of the elements of the array”. But the compiler complains: “Same-type requirement make generic parameters U and T equivalent”. That's right, and they should be, with the additional contraint T : _IntegerArithmeticType.

Why isn't the compiler letting me do this? How can I do it?

(I know that I should later fix how things are added up and what the return type exactly is, but I'm stuck at the type constraint for now.)

Jean-Philippe Pellet
  • 59,296
  • 21
  • 173
  • 234
  • It is (currently) not possible to extend Array with methods that require the elements to be of a restricted type. Compare http://stackoverflow.com/questions/24938948/array-extension-to-remove-object-by-value or http://stackoverflow.com/questions/25630476/swift-array-insert-generics (both of them might qualify as a duplicate). – Martin R Jan 28 '15 at 11:06
  • You wrote “(currently)”. Has anyone heard whispers it may change soon? – Jean-Philippe Pellet Jan 28 '15 at 11:08
  • I *think* that I read in devforums.apple.com that this is a known issue and might change in the future, but I am not 100% sure. I will give you the link if I find it again. – Martin R Jan 28 '15 at 11:10
  • Thanks. I'll post the least bad workaround I found as an answer. – Jean-Philippe Pellet Jan 28 '15 at 11:11

1 Answers1

3

As per Martin R's comment, this is not currently possible. The thing I'm tempted to use in this particular situation would be an explicit passing of a T -> Int conversion function:

extension Array {

    func sum(toInt: T -> Int?) -> Int {
        var acc = 0
        for elem in self {
            if let i = toInt(elem) {
                acc += i
            }
        }
        return acc
    }

}

Then I can write stuff like this:

func itself<T>(t: T) -> T {
    return t
}

let ss = ["1", "2", "3", "4", "five"].sum { $0.toInt() }
let si = [1, 2, 3, 4].sum(itself)

An explicit function has to be passed, though. The (itself) part can of course be replaced by { $0 }. (Others have called the itself function identity.)

Note that an A -> B function can be passed when A -> B? is needed.

Jean-Philippe Pellet
  • 59,296
  • 21
  • 173
  • 234