Dan Rosenstark
Dan Rosenstark

Reputation: 69777

Filter function syntax?

This works:

func removeObject<T : Equatable>(object: T, array: [T]) -> Array<T>
{
    return array.filter() { $0 != object }
}

let threeThings = ["one", "two", "three"]
twoThings = removeObject("three", threeThings)

However, I'd like to check for inequality with this !==. Then I get error "Type 'T' does not conform to protocol 'AnyObject'"

How can this code be fixed? (I've see the code here but I'd like to learn how to use filter properly).

Upvotes: 0

Views: 352

Answers (3)

Aaron Rasmussen
Aaron Rasmussen

Reputation: 13316

!== checks for "identity", not "equality". Identity is a property of reference types which all support the AnyObject protocol, and it means that the two variables that you are comparing point to the same actual object, and not just another object with the same value.

That means you can't use === or !== with normal value types, like strings, integers, arrays, etc.

Try typing this into a playground:

let a = "yes"
let b = a

println(a === b)

You should get a message saying that String doesn't conform to the AnyObject protocol, because String is a value type (a struct) and doesn't support AnyObject, so you can't use === with it.

You can use === with any instance of a class, because classes are reference types, not value types.

You could put a constraint on T requiring that it conform to AnyObject.

func removeObject<T : Equatable where T: AnyObject>...

It should work, then, for reference types (including all class instances). But then your function won't work for value types (which include all structs).

Why do you need to check for identity (===) instead of equality (==)?

Upvotes: 1

matt
matt

Reputation: 535547

If you want to use !== instead of !=, then, instead of the type constraint <T : Equatable> say <T : AnyObject>. All you have to do is listen to what the error message is telling you!

Note that this has nothing to do with using the filter function. It is simply a matter of types. You cannot use a method with an object of a type for which that method is not implemented. !== is implemented for AnyObject so if you want to use it you must guarantee to the compiler that this type will be an AnyObject. That is what the type constraint does.

Upvotes: 2

Martin R
Martin R

Reputation: 539945

The identical operator === and its negation !== are only defined for instances of classes, i.e. instances of AnyObject:

func removeObject<T : AnyObject>(object: T, array: [T]) -> Array<T>
{
    return array.filter() { $0 !== object }
}

=== checks if two variables refer to the same single instance.

Note that your code

let threeThings = ["one", "two", "three"]
twoThings = removeObject("three", threeThings)

does still compile and run, but gives the (perhaps unexpected) result

[one, two, three]

The Swift strings (which are value types and not class types) are automatically bridged to NSString, and the two instances of NSString representing "three" need not be the same.

Upvotes: 3

Related Questions