3

Following the guides on generics and type constraints, I attempted to create an Array.without function as follows:

extension Array {
  func without<T: Equatable>(item:T) -> T[] {
    return self.map { $0 != item }
  }
}

Testing this in a playground, I can't get it to work as the != value triggers a compiler error, "Could not find an overload for != that accepts the supplied arguments".

I believe the <T: Equatable> should be enough to allow the use of != but obviously it didn't work. What's missing here?

2
  • 1
    you should use filter not map... unless you really want it return Bool[] Commented Jun 12, 2014 at 2:55
  • I think the main problem is that Array<T> does not constrain its element need to be Equatable. and I don't know is it possible to provide method only for some Array<T> (you can't have this method for non-equatable element array) Commented Jun 12, 2014 at 2:58

1 Answer 1

2

The problem is that the T you define in the method has nothing to do with the T defined in the actual struct. Your local T is constrained to be Equatable, but the Array version of T is still not constrained and that is what self.map is providing to the closure. The closure is getting an Array type T and you are trying to compare that to your local T which isn't necessarily the same type.

I think the best you can do is something like this:

extension Array {
    func without<U : Equatable>(item : U) -> [T]  {
        return self.filter { $0 as? U != item }
    }
}

Unfortunately, this will still work if you call it with an instance of a different type as is stored in the array. If you do, it will simply return the original Array. It will not let you call it with an instance that is not equatable though.

Notes:

  1. I used filter instead of map because that is the method that allows you to filter out contents of an array. map is for changing contents
  2. I changed without to return an array. filter and map do not modify the array, instead they return a new version of the array that is altered according to the closure.
Sign up to request clarification or add additional context in comments.

3 Comments

This looks great, thanks! Sorry for the silly question: what is the 'U' type? I've missed that so far in reading about Swift.
Type "U", like type "T" is just an arbitrary name. Arrays could have easily used Array<BlahBlah>, T is just a convention. Just like T is a convention, it is common to use U as a second type because it is the next letter after T. However, if you look at a dictionary you see they use KeyType and ValueType. All of these types are placeholder types that are determined each time the struct is created. The U above is inferred from what you call the method with, but U must be Equatable for the compiler to not complain because of the restriction we put on it
@Andrew for more info than what I wrote above, read the Generics section of The Swift Programming Language book

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.