I am trying to extend Swift's Array class with the following func:
func containsObjectIdenticalTo(obj: T) -> Bool {
// objectPassingTest returns the first object passing the test
return objectPassingTest { x in x == obj }
}
Apparently, this won't compile as the compiler doesn't know yet if == is implemented for type T. I then change the code to this
func containsObjectIdenticalTo(obj: T) -> Bool {
return objectPassingTest {
x in
assert(x is Equatable && obj is Equatable)
return (x as Equatable) == (obj as Equatable)
} != nil
}
Which doesn't work either, since conformance against Equatable can't be checked (because Equatable wasn't defined with #obj) !
Any thoughts on this? Would be nice if there's some way to assert directly if T conforms to Equatable, but I haven't read that anywhere. Swift seems to be less dynamic than Obj-C in these stuffs.
UPDATE:
Tried this suggestion and it doesn't work (don't know exactly what <T: Equatable> is for, tho it does compile).
func containsObjectIdenticalTo<T: Equatable>(obj: T) -> Bool {
var x = self[0]
var y = self[0]
return x == y // Error here
}
Specify that T must be equatable in the Method's signature:
func containsObjectIdenticalTo<T: Equatable>(obj: T) -> Bool {/*...*/}
i got this from ExSwift : https://github.com/pNre/ExSwift
func contains <T: Equatable> (items: T...) -> Bool {
return items.all { self.indexOf($0) >= 0 }
}
func indexOf <U: Equatable> (item: U) -> Int? {
if item is Element {
if let found = find(reinterpretCast(self) as Array<U>, item) {
return found
}
return nil
}
return nil
}
func all (call: (Element) -> Bool) -> Bool {
for item in self {
if !call(item) {
return false
}
}
return true
}
maybe you can try it
How about:
func containsObjectIdenticalTo<T : Equatable>(obj: T) -> Bool {
... etc ...
}
In the end, I resorted to this solution
func containsObjectIdenticalTo<U: Equatable>(obj: U) -> Bool {
return objectPassingTest({
x in
return x as U == obj
}) != nil
}
Might not be the best (ie safest) one. But it works great.
Related
In the below example,
let value1: Int? = 23
let value2: Int = 20
let answer = value1 + value2 // Compiler warning that + operator cannot be applied to Int? and Int
So I would have to change the code to
if let value1 = value1 {
let answer = value1 + value2
}
How to create an extension for + that supports Optional values as well? In that case it should give nil as output.
What if the operation has multiple operands?
let value1: Int? = 2
let answer = value1 + 3.0
You just have to find the right protocol type to constrain the generic types, really. After that the implementation is trivial:
// plus and minus is supported by AdditiveArithmetic
func +<T: AdditiveArithmetic>(lhs: T?, rhs: T?) -> T? {
return lhs.flatMap { x in rhs.map { y in x + y } }
/* the above is just a more "functional" way of writing
if let x = lhs, let y = rhs {
return x + y
} else {
return nil
}
*/
}
func -<T: AdditiveArithmetic>(lhs: T?, rhs: T?) -> T? {
return lhs.flatMap { x in rhs.map { y in x - y } }
}
// times is supported by Numeric
func *<T: Numeric>(lhs: T?, rhs: T?) -> T? {
return lhs.flatMap { x in rhs.map { y in x * y } }
}
// divide is not supported by a single protocol AFAIK
func /<T: BinaryInteger>(lhs: T?, rhs: T?) -> T? {
return lhs.flatMap { x in rhs.map { y in x / y } }
}
func /<T: FloatingPoint>(lhs: T?, rhs: T?) -> T? {
return lhs.flatMap { x in rhs.map { y in x / y } }
}
To make value1 + 3.0 work, you'd have to do something like this:
func +<T: BinaryInteger, U: FloatingPoint>(lhs: T?, rhs: U?) -> U? {
return lhs.flatMap { x in rhs.map { y in U(x) + y } }
}
But it's usually not a good idea to go against the restrictions put in place. I don't recommend this.
Only pasting solution for addition, but other operators will work analogously (but mind subtract and division, since they are not commutative)
Three reasonable solutions
Global function(s)
Extend existential* (conforming to AdditiveArithmetic) to some new protocol e.g. AdditiveArithmeticOptional
Extend Optional
* Note: you can read about existentials here, e.g. protocol isn't an existential, but a concrete type, e.g. a struct is.
1 Global function(s)
See #Sweepers answer
Note: a global function is a function not implemented on a type (protocol or existential). Swift's zip function is an example
2 Extend existentials to new protocol
public protocol AdditiveArithmeticOptional: AdditiveArithmetic {
static func + (lhs: Self, rhs: Self?) -> Self
}
public extension AdditiveArithmeticOptional {
static func + (lhs: Self, rhs: Self?) -> Self {
guard let value = rhs else { return lhs }
return value + lhs
}
static func + (lhs: Self?, rhs: Self) -> Self {
rhs + lhs
}
}
extension Int8: AdditiveArithmeticOptional {}
extension Int16: AdditiveArithmeticOptional {}
extension Int32: AdditiveArithmeticOptional {}
extension Int64: AdditiveArithmeticOptional {}
extension Int: AdditiveArithmeticOptional {} // same as `Int64` on 64 bit system, same as `Int32` on 32 bit system
extension UInt8: AdditiveArithmeticOptional {}
extension UInt16: AdditiveArithmeticOptional {}
extension UInt32: AdditiveArithmeticOptional {}
extension UInt64: AdditiveArithmeticOptional {}
extension UInt: AdditiveArithmeticOptional {} // same as `UInt64` on 64 bit system, same as `UInt32` on 32 bit system
3 extend Optional
extension Optional where Wrapped: AdditiveArithmetic {
static func + <I>(optional: Self, increment: I) -> I where I: AdditiveArithmetic & ExpressibleByIntegerLiteral, I.IntegerLiteralType == Wrapped {
guard let value = optional else { return increment }
let base = I.init(integerLiteral: value)
return base + increment
}
static func + <I>(increment: I, optional: Self) -> I where I: AdditiveArithmetic & ExpressibleByIntegerLiteral, I.IntegerLiteralType == Wrapped {
optional + increment
}
}
You could create your own custom operator function if you have multiple scenarios where you require arithmetic operations between optionals as follows:
func + (lhs: Int?, rhs: Int?) -> Int {
(lhs ?? 0) + (rhs ?? 0)
}
func + (lhs: Int?, rhs: Int) -> Int {
(lhs ?? 0) + rhs
}
func + (lhs: Int, rhs: Int?) -> Int {
lhs + (rhs ?? 0)
}
Note: Add return keyword if you are using Swift 5 or below.
Update: Upon further investigation and inspiration from the answer of #sweeper following solution seemed more elegant.
func + <T: AdditiveArithmetic>(lhs: T?, rhs: T?) -> T {
(lhs ?? .zero) + (rhs ?? .zero)
}
or if you need a nil when operation was not successful
func + <T: AdditiveArithmetic>(lhs: T?, rhs: T?) -> T? {
lhs.flatMap { lhs in rhs.flatMap { lhs + $0 }}
}
Optionals don't make much sense to be added, a nil value usually represents something went wrong along the way and a value could not be retrieved. It's better to be explicit, and to write the if-let statements. This way you can handle the cases where you end up with nil values.
But if you want to ignore the nils, then you can use the nil coalescing operator:
let value1: Int? = 23
let value2: Int = 20
let answer = (value1 ?? 0) + value2
You are still explicit about the unwrap, but you also have a fallback route in case you want to ignore the nil value. And, maybe even more important, the code transmits its scope in a clear manner. If someone later on stumbles upon your code it will be clear to them what the code does and how it recovers from unexpected situations (nil is an unexpected value in regards to the addition)
I don't think this can be done but I'll ask anyway. I have a protocol:
protocol X {}
And a class:
class Y:X {}
In the rest of my code I refer to everything using the protocol X. In that code I would like to be able to do something like:
let a:X = ...
let b:X = ...
if a == b {...}
The problem is that if I try to implement Equatable:
protocol X: Equatable {}
func ==(lhs:X, rhs:X) -> Bool {
if let l = lhs as? Y, let r = hrs as? Y {
return l.something == r.something
}
return false
}
The idea to try and allow the use of == whilst hiding the implementations behind the protocol.
Swift doesn't like this though because Equatable has Self references and it will no longer allow me to use it as a type. Only as a generic argument.
So has anyone found a way to apply an operator to a protocol without the protocol becoming unusable as a type?
If you directly implement Equatable on a protocol, it will not longer be usable as a type, which defeats the purpose of using a protocol. Even if you just implement == functions on protocols without Equatable conformance, results can be erroneous. See this post on my blog for a demonstration of these issues:
https://khawerkhaliq.com/blog/swift-protocols-equatable-part-one/
The approach that I have found to work best is to use type erasure. This allows making == comparisons for protocol types (wrapped in type erasers). It is important to note that while we continue to work at the protocol level, the actual == comparisons are delegated to the underlying concrete types to ensure correct results.
I have built a type eraser using your brief example and added some test code at the end. I have added a constant of type String to the protocol and created two conforming types (structs are the easiest for demonstration purposes) to be able to test the various scenarios.
For a detailed explanation of the type erasure methodology used, check out part two of the above blog post:
https://khawerkhaliq.com/blog/swift-protocols-equatable-part-two/
The code below should support the equality comparison that you wanted to implement. You just have to wrap the protocol type in a type eraser instance.
protocol X {
var name: String { get }
func isEqualTo(_ other: X) -> Bool
func asEquatable() -> AnyEquatableX
}
extension X where Self: Equatable {
func isEqualTo(_ other: X) -> Bool {
guard let otherX = other as? Self else { return false }
return self == otherX
}
func asEquatable() -> AnyEquatableX {
return AnyEquatableX(self)
}
}
struct Y: X, Equatable {
let name: String
static func ==(lhs: Y, rhs: Y) -> Bool {
return lhs.name == rhs.name
}
}
struct Z: X, Equatable {
let name: String
static func ==(lhs: Z, rhs: Z) -> Bool {
return lhs.name == rhs.name
}
}
struct AnyEquatableX: X, Equatable {
var name: String { return value.name }
init(_ value: X) { self.value = value }
private let value: X
static func ==(lhs: AnyEquatableX, rhs: AnyEquatableX) -> Bool {
return lhs.value.isEqualTo(rhs.value)
}
}
// instances typed as the protocol
let y: X = Y(name: "My name")
let z: X = Z(name: "My name")
let equalY: X = Y(name: "My name")
let unequalY: X = Y(name: "Your name")
// equality tests
print(y.asEquatable() == z.asEquatable()) // prints false
print(y.asEquatable() == equalY.asEquatable()) // prints true
print(y.asEquatable() == unequalY.asEquatable()) // prints false
Note that since the type eraser conforms to the protocol, you can use instances of the type eraser anywhere an instance of the protocol type is expected.
Hope this helps.
The reason why you should think twice about having a protocol conform to Equatable is that in many cases it just doesn't make sense. Consider this example:
protocol Pet: Equatable {
var age: Int { get }
}
extension Pet {
static func == (lhs: Pet, rhs: Pet) -> Bool {
return lhs.age == rhs.age
}
}
struct Dog: Pet {
let age: Int
let favoriteFood: String
}
struct Cat: Pet {
let age: Int
let favoriteLitter: String
}
let rover: Pet = Dog(age: "1", favoriteFood: "Pizza")
let simba: Pet = Cat(age: "1", favoriteLitter: "Purina")
if rover == simba {
print("Should this be true??")
}
You allude to type checking within the implementation of == but the problem is that you have no information about either of the types beyond them being Pets and you don't know all the things that might be a Pet (maybe you will add a Bird and Rabbit later). If you really need this, another approach can be modeling how languages like C# implement equality, by doing something like:
protocol IsEqual {
func isEqualTo(_ object: Any) -> Bool
}
protocol Pet: IsEqual {
var age: Int { get }
}
struct Dog: Pet {
let age: Int
let favoriteFood: String
func isEqualTo(_ object: Any) -> Bool {
guard let otherDog = object as? Dog else { return false }
return age == otherDog.age && favoriteFood == otherDog.favoriteFood
}
}
struct Cat: Pet {
let age: Int
let favoriteLitter: String
func isEqualTo(_ object: Any) -> Bool {
guard let otherCat = object as? Cat else { return false }
return age == otherCat.age && favoriteLitter == otherCat.favoriteLitter
}
}
let rover: Pet = Dog(age: "1", favoriteFood: "Pizza")
let simba: Pet = Cat(age: "1", favoriteLitter: "Purina")
if !rover.isEqualTo(simba) {
print("That's more like it.")
}
At which point if you really wanted, you could implement == without implementing Equatable:
static func == (lhs: IsEqual, rhs: IsEqual) -> Bool { return lhs.isEqualTo(rhs) }
One thing you would have to watch out for in this case is inheritance though. Because you could downcast an inheriting type and erase the information that might make isEqualTo not make logical sense.
The best way to go though is to only implement equality on the class/struct themselves and use another mechanism for type checking.
Determining equality across conformances to a Swift protocol is possible without type erasure if:
you are willing to forgo the operator syntax (i.e. call isEqual(to:) instead of ==)
you control the protocol (so you can add an isEqual(to:) func to it)
import XCTest
protocol Shape {
func isEqual (to: Shape) -> Bool
}
extension Shape where Self : Equatable {
func isEqual (to: Shape) -> Bool {
return (to as? Self).flatMap({ $0 == self }) ?? false
}
}
struct Circle : Shape, Equatable {
let radius: Double
}
struct Square : Shape, Equatable {
let edge: Double
}
class ProtocolConformanceEquality: XCTestCase {
func test() {
// Does the right thing for same type
XCTAssertTrue(Circle(radius: 1).isEqual(to: Circle(radius: 1)))
XCTAssertFalse(Circle(radius: 1).isEqual(to: Circle(radius: 2)))
// Does the right thing for different types
XCTAssertFalse(Square(edge: 1).isEqual(to: Circle(radius: 1)))
}
}
Any conformances don't conform to Equatable will need to implement isEqual(to:) themselves
maybe this will be helpful for you:
protocol X:Equatable {
var name: String {get set}
}
extension X {
static func ==(lhs: Self, rhs: Self) -> Bool {
return lhs.name == rhs.name
}
}
struct Test : X {
var name: String
}
let first = Test(name: "Test1")
let second = Test(name: "Test2")
print(first == second) // false
All people who say that you can't implement Equatable for a protocol just don't try hard enough. Here is the solution (Swift 4.1) for your protocol X example:
protocol X: Equatable {
var something: Int { get }
}
// Define this operator in the global scope!
func ==<L: X, R: X>(l: L, r: R) -> Bool {
return l.something == r.something
}
And it works!
class Y: X {
var something: Int = 14
}
struct Z: X {
let something: Int = 9
}
let y = Y()
let z = Z()
print(y == z) // false
y.something = z.something
print(y == z) // true
The only problem is that you can't write let a: X = Y() because of "Protocol can only be used as a generic constraint" error.
Not sure why you need all instances of your protocol to conform to Equatable, but I prefer letting classes implement their equality methods.
In this case, I'd leave the protocol simple:
protocol MyProtocol {
func doSomething()
}
If you require that an object that conforms to MyProtocol is also Equatable you can use MyProtocol & Equatable as type constraint:
// Equivalent: func doSomething<T>(element1: T, element2: T) where T: MyProtocol & Equatable {
func doSomething<T: MyProtocol & Equatable>(element1: T, element2: T) {
if element1 == element2 {
element1.doSomething()
}
}
This way you can keep your specification clear and let subclasses implement their equality method only if required.
I would still advise against implementing == using polymorphism. It's a bit of a code smell. If you want to give the framework user something he can test equality with then you should really be vending a struct, not a protocol. That's not to say that it can't be the protocols that are vending the structs though:
struct Info: Equatable {
let a: Int
let b: String
static func == (lhs: Info, rhs: Info) -> Bool {
return lhs.a == rhs.a && lhs.b == rhs.b
}
}
protocol HasInfo {
var info: Info { get }
}
class FirstClass: HasInfo {
/* ... */
}
class SecondClass: HasInfo {
/* ... */
}
let x: HasInfo = FirstClass( /* ... */ )
let y: HasInfo = SecondClass( /* ... */ )
print(x == y) // nope
print(x.info == y.info) // yep
I think this more efficiently communicates your intent, which is basically "you have these things and you don't know if they are the same things, but you do know they have the same set of properties and you can test whether those properties are the same." That is pretty close to how I would implement that Money example.
You have to implement a protocol extension constrained to your class type. Inside that extension you should implement the Equatable operator.
public protocol Protocolable: class, Equatable
{
// Other stuff here...
}
public extension Protocolable where Self: TheClass
{
public static func ==(lhs: Self, rhs:Self) -> Bool
{
return lhs.name == rhs.name
}
}
public class TheClass: Protocolable
{
public var name: String
public init(named name: String)
{
self.name = name
}
}
let aClass: TheClass = TheClass(named: "Cars")
let otherClass: TheClass = TheClass(named: "Wall-E")
if aClass == otherClass
{
print("Equals")
}
else
{
print("Non Equals")
}
But let me recommend you add the operator implementation to your class. Keep It Simple ;-)
Swift 5.1 introduces a new feature into the language called opaque types
Check code below
that still gets back a X, which might be an Y, a Z, or something else that conforms to the X protocol,
but the compiler knows exactly what is being returned
protocol X: Equatable { }
class Y: X {
var something = 3
static func == (lhs: Y, rhs: Y) -> Bool {
return lhs.something == rhs.something
}
static func make() -> some X {
return Y()
}
}
class Z: X {
var something = "5"
static func == (lhs: Z, rhs: Z) -> Bool {
return lhs.something == rhs.something
}
static func make() -> some X {
return Z()
}
}
let a = Z.make()
let b = Z.make()
a == b
I came cross this same issue and I figured that the == operator can be implemented in the global scope (as it used to be), as opposed to a static func inside the protocol's scope:
// This should go in the global scope
public func == (lhs: MyProtocol?, rhs: MyProtocol?) -> Bool { return lhs?.id == rhs?.id }
public func != (lhs: MyProtocol?, rhs: MyProtocol?) -> Bool { return lhs?.id != rhs?.id }
Note that if you use linters such as SwiftLint's static_operator, you'll have to wrap that code around // swiftlint:disable static_operator to silent linter warnings.
Then this code will start compiling:
let obj1: MyProtocol = ConcreteType(id: "1")
let obj2: MyProtocol = ConcreteType(id: "2")
if obj1 == obj2 {
print("They're equal.")
} else {
print("They're not equal.")
}
took some of the code from above and came with the following sollution.
it uses the IsEqual protocol instead of the Equatable protocol and with a few line codes you will be able to compare any two protocol objects with each other, wether they are optional or not, are in an array and even add comparing dates while I was at it.
protocol IsEqual {
func isEqualTo(_ object: Any) -> Bool
}
func == (lhs: IsEqual?, rhs: IsEqual?) -> Bool {
guard let lhs = lhs else { return rhs == nil }
guard let rhs = rhs else { return false }
return lhs.isEqualTo(rhs) }
func == (lhs: [IsEqual]?, rhs: [IsEqual]?) -> Bool {
guard let lhs = lhs else { return rhs == nil }
guard let rhs = rhs else { return false }
guard lhs.count == rhs.count else { return false }
for i in 0..<lhs.count {
if !lhs[i].isEqualTo(rhs[i]) {
return false
}
}
return true
}
func == (lhs: Date?, rhs: Date?) -> Bool {
guard let lhs = lhs else { return rhs == nil }
guard let rhs = rhs else { return false }
return lhs.compare(rhs) == .orderedSame
}
protocol Pet: IsEqual {
var age: Int { get }
}
struct Dog: Pet {
let age: Int
let favoriteFood: String
func isEqualTo(_ object: Any) -> Bool {
guard let otherDog = object as? Dog else { return false }
return age == otherDog.age && favoriteFood == otherDog.favoriteFood
}
}
I want to use generic protocol type as a function return type like this:
protocol P {
associatedtype T
func get() -> T?
func set(v: T)
}
class C<T>: P {
private var v: T?
func get() -> T? {
return v
}
func set(v: T) {
self.v = v
}
}
class Factory {
func createC<T>() -> P<T> {
return C<T>()
}
}
But this code compile with errors complained:
Cannot specialize non-generic type 'P'
Generic parameter 'T' is not used in function signature
Is there any way to achieve similar function with Swift?
Swift 5.1 supports returning associated types using Opaque type. Using opaque type, your code builds successfully. Ref
protocol P {
associatedtype T
func get() -> T?
func set(v: T)
}
class C<T>: P {
private var v: T?
func get() -> T? {
return v
}
func set(v: T) {
self.v = v
}
}
class Factory {
func createC<T>() -> some P {
return C<T>()
}
The problem is you cannot use the syntax P<T>. P is a protocol, meaning it can't be treated as a generic type (Cannot specialize non-generic type 'P'), even though it may have a given associatedtype.
In fact, because it has an associatedtype, you now can't even use the protocol type itself directly – you can only use it as a generic constraint.
One solution to your problem is to simply change your function signature to createC<T>() -> C<T>, as that's exactly what it returns.
class Factory {
func createC<T>() -> C<T> {
return C<T>()
}
}
I'm not entirely sure what you would gain from having the return type be a protocol here. Presumably your example is just a simplification of your actual code and you want to be able to return an arbitrary instance that conforms to P. In that case, you could use type erasure:
class AnyP<T> : P {
private let _get : () -> T?
private let _set : (T) -> ()
init<U:P where U.T == T>(_ base:U) {
_get = base.get
_set = base.set
}
func get() -> T? {return _get()}
func set(v: T) {_set(v)}
}
class Factory {
func createC<T>() -> AnyP<T> {
return AnyP(C<T>())
}
}
I have the following code:
class Function<T> {
var ptr: () throws -> T
init<Func>(block: Func, args: AnyObject...) {
self.ptr = {() throws -> T in
let result: AnyObject? = nil
if T.self == Void.self {
return Void() as! T
}
return result //Error Here.. Cannot as! cast it either.. Cannot unsafeBitCast it either..
}
}
}
postfix operator ^ { }
postfix func ^ <T>(left: Function<T>) throws -> T {
return try left.ptr()
}
func call() {
let block: (String) -> String? = {(arg) -> String? in
return nil
}
let fun = Function<String?>(block: block, args: "Hello")
fun^
}
The function Block.execute returns AnyObject?. My Generic class Function<T> expects a return type of T.
If T is already String? why can't I return nil?
Is there any way to return nil as type T which is already Optional?
If I make T Optional, then the return type becomes Optional<Optional<String>> which is not what I want.. then the compiler complains that OptionalOptional is not unwrapped with ?? That is how I know that T is already optional.
After a long hunt on google I have finally found an elegant way to do this. It's possible to write a class extension with type constraints.
class Foo<T> {
func bar() -> T {
return something
// Even if T was optional, swift does not allow us to return nil here:
// 'nil' is incompatible with return type 'T'
}
}
extension Foo where T: ExpressibleByNilLiteral {
func bar() -> T {
return nil
// returning nil is now allowed
}
}
The appropriate method will be invoked depending on whether T is optional or not.
I solved it with a nasty work around.. I throw an exception for nil return type. Then in the generic function operator I catch that specific exception and return nil if T is NilLiteralConvertible.. Otherwise I just execute normally..
class Function<T> {
var ptr: () throws -> T
init<Func>(block: Func, args: AnyObject...) {
self.ptr = {() throws -> T in
let result: AnyObject? = execute(block, args...)
if T.self == Void.self {
return Void() as! T
}
throw BlockError.BlockReturnsNil
}
}
}
postfix func ^ <T>(left: Function<T>) throws -> T {
return try left.ptr()
}
postfix func ^ <T : NilLiteralConvertible>(left: Function<T>) throws -> T {
do {
return try left.ptr()
}
catch BlockError.BlockReturnsNil {
return nil
}
}
The following casts Any? to T returning nil only if T is optional and from is nil. It crashes, if from cannot be cast to T.
func cast<T>(from v: Any?)->T {
return v as! T
}
func cast<T>(from v: Any?)->T where T: ExpressibleByNilLiteral {
guard let v = v else { return nil }
return v as! T
}
This does the trick as of Swift 3.1. Modification of user3763801's answer.
func cast<T>(_ v: Any) -> T {
return v as! T
}
I'm trying to add an extension method in Array like so:
extension Array {
func contains(obj: T) -> Bool {
let filtered = self.filter {$0 == obj}
return filtered.count > 0
}
}
But self.filter {$0 == obj} don't work. Compiler error:
could not find an overload for '==' that accepts the supplied arguments
you don't actually need to write an extension, you can use the global func contains from the Swift library:
contains([1,2,3], 1)
Swift 1.x
As I mentioned in the comments, there is a contains function. But to answer the question of how to write an extension and what the compiler error means:
The elements in the array can't necessarily be compared with ==. You need to make sure the parameter is Equatable and you need to make sure the array element is of the same type.
extension Array {
func contains<T : Equatable>(obj: T) -> Bool {
let filtered = self.filter {$0 as? T == obj}
return filtered.count > 0
}
}
Swift 2/Xcode 7 (Beta)
Swift 2 includes SequenceType.contains, which is exactly what you were trying to create.
This is made possible by a Swift syntax that allows restricting methods to certain (e.g. Equatable) type arguments. It looks like this:
extension SequenceType where Generator.Element: Equatable {
func contains(element: Self.Generator.Element) -> Bool {
...
}
}
I found that the built-in contains doesn't work with reference types. I needed this and solved it with the code below. I'm pasting it here because somebody else might be confused about contains() like I was.
extension Array {
func containsReference(obj: AnyObject) -> Bool {
for ownedItem in self {
if let ownedObject: AnyObject = ownedItem as? AnyObject {
if (ownedObject === obj) {
return true
}
}
}
return false
}
}
This works with Swift 2.1 for reference types pretty good.
extension SequenceType where Generator.Element: AnyObject {
func contains(obj: Self.Generator.Element?) -> Bool {
if obj != nil {
for item in self {
if item === obj {
return true
}
}
}
return false
}
}
For value types you can add this:
extension SequenceType where Generator.Element: Equatable {
func contains(val: Self.Generator.Element?) -> Bool {
if val != nil {
for item in self {
if item == val {
return true
}
}
}
return false
}
}
Not perfect, but this version built on nschum's answer supports optional arguments (though not arrays with optional types) as well:
extension Array {
private func typeIsOptional() -> Bool {
return reflect(self[0]).disposition == .Optional
}
func contains<U : Equatable>(obj: U) -> Bool {
if isEmpty {
return false
}
if (typeIsOptional()) {
NSException(name:"Not supported", reason: "Optional Array types not supported", userInfo: nil).raise()
}
// cast type of array to type of argument to make it equatable
for item in self.map({ $0 as? U }) {
if item == obj {
return true
}
}
return false
}
// without this version, contains("foo" as String?) won't compile
func contains<U : Equatable>(obj: U?) -> Bool {
if isEmpty {
return false
}
if (typeIsOptional()) {
NSException(name:"Not supported", reason: "Optional Array types not supported", userInfo: nil).raise()
}
return obj != nil && contains(obj!)
}
}
If you have an array of optionals, you can get a copy of it with non-optionals (nil arguments removed) with this global function thanks to jtbandes:
func unwrapOptionals<T>(a: [T?]) -> [T] {
return a.filter { $0 != nil }.map { $0! }
}
Usage:
1> func unwrapOptionals<T>(a: [T?]) -> [T] {
2. return a.filter { $0 != nil }.map { $0! }
3. }
4>
5> let foo = ["foo" as String?]
foo: [String?] = 1 value {
[0] = "foo"
}
6> let bar = unwrapOptionals(foo)
bar: [String] = 1 value {
[0] = "foo"
}
For good measure, add one that just returns the array if its type is not optional. This way you avoid runtime errors if you call unwrapOptionals() on a non-optional array:
func unwrapOptionals<T>(a: [T]) -> [T] {
return a
}
Note you might think you could just call unwrapOptionals inside func contains<U : Equatable>(obj: U?). However, that doesn't work, because the Element type in the Array extension is just a type--it doesn't "know" it's an optional type. So if you call unwrapOptionals, the second version will be invoked, and you'll just get the array full of optionals back.