Reputation: 62062
How do I determine whether two instances of a generic struct are of the same type?
For example, given the following struct:
struct FooBar<T> {
let variable: T
init(arg: T) {
variable = arg
}
}
And the following snippet:
let foo = FooBar(1)
let bar = FooBar(1.0)
let baz = FooBar("1")
How can I determine whether foo
, bar
, or baz
are of the same or different types?
func areExactType(x: FooBar) -> Bool {
return self.dynamicType === x.dynamicType
}
This gives
Type 'Foo' does not conform to protocol 'AnyObject'
func areExactType(x: FooBar) -> Bool {
return self.dynamicType === x.dynamicType
}
This gives
Cannot invoke '==' with an argument list of type '(Foo.Type, Foo.Type)'
func areExactType(x: FooBar) -> Bool {
return self is x.dynamicType
}
This gives three errors:
Consecutive statements on a line must be separated by ';'
(this wants to put a semicolon between the period and 'dynamicType')
Expected identifier in dotted type
and
Expected expression
Upvotes: 34
Views: 19794
Reputation: 72760
If I haven't misunderstood, you don't want to know if variables of type FooBar
are of the same type (because they are), you want to check whether they are using the same generic type.
Since the struct already contains a property of the generic type, you can use it for type comparison, rather than using the struct itself:
func areExactType<U>(x: FooBar<U>) -> Bool {
return x.variable is T
}
I've tested in a playground, and it works with basic data types, arrays, dictionaries etc. The downside is that in order for it to work, the struct must have a property of the generic type.
Upvotes: 2
Reputation: 62062
Taking some inspiration from Sebastian's answer, I came up with this solution:
func sameType<L,R>(left: L, right: R) -> Bool {
if let cast = left as? R {
return true
} else {
return false
}
}
This works even if nested within a function accepting generics:
func compare<T,U>(foo: T, bar: U) -> Bool {
return sameType(foo, bar)
}
But it does have some of the downfalls that Sebastian's answer mentioned. Namely, if you've retrieved your values from an Objective-C collection, they'll both have a type of AnyObject
. Moreover, if we nest my sameType
function within a function whose arguments are not generics, such as:
func compare(foo: Any, bar: Any) -> Bool {
return sameType(foo, bar)
}
The sameType
function here will always return true
. The type of foo
and bar
, as far as sameType
is concerned, is Any
, rather than whatever most specific type I could potentially downcast it to.
It's also probably worth noting that if I try nesting this as an instance method, Xcode crashes. Read that again, Xcode crashes. Not "produces undesired results". The application crashes.
For example:
func sameType<L,R>(left: L, right: R) -> Bool {
if let cast = left as? R {
return true
} else {
return false
}
}
struct Foo<T> {
func sameType<U>(bar: U) -> Bool {
return sameType(self, bar)
}
}
let x = Foo<Int>()
let y = Foo<Float>()
if x.sameType(y) {
println("x is a y")
}
This code snippet crashes Xcode. I have no idea why... but it does...
If we instead write:
if sameType(x,y) {
println("x is a y")
}
Xcode compiles and runs just fine.
Upvotes: 7
Reputation: 7720
Sorry for the premature answer, it actually doesn't work, because the compiler will choose the function for different types when called from within another function:
func foobar<T,U> (lhs: Foo<T>, rhs: Foo<U>) -> Bool {
return lhs.sameType(rhs)
}
Given a simple generic struct
struct Foo<T> {
let v : T
}
You can define a function sameType
that takes to Foo
s of the same type and just return true
:
func sameType<T> (a: Foo<T>, b: Foo<T>) -> Bool {
return true
}
and overload the function with two different Foo
s:
func sameType<T,U> (a: Foo<T>, b: Foo<U>) -> Bool {
return false;
}
The compiler will choose a method based on the argument type:
let a = Foo(v: 1.0)
let b = Foo(v: "asdf")
sameType(a, b) // false
sameType(a, a) // true
This works the same way with instance methods on the struct:
func sameType (other: Foo) -> Bool {
return true
}
func sameType<U> (other: Foo<U>) -> Bool {
return false
}
import Foundation
let x = NSArray(object: 1)
let y = NSArray(object: "string")
sameType(Foo(v: x[0]), Foo(v: y[0])) // true
The result is true because because Foo(v: x[0])
has type Foo<AnyObject>
Upvotes: 13