swift how to compare generics - ios

I have a protocol called SomeProtocol
I want to create a function that get an object that confirms to this protocol, and add it to an array.
then I have another function that remove an object from this array.
var allObjs = [SomeProtocol]()
func addObj<T: AnyObject where T: SomeProtocol>(obj: T) {
allObjs.append(obj)
}
func removeObj<T: AnyObject where T: SomeProtocol>(obj: T) {
for someObj in allObjs {
if someObj == obj { // compile time error -> Binary operator '==' cannot be applied to operands of type 'SomeProtocol' and 'T'
}
}
}
This code will cause a compile time error "Binary operator '==' cannot be applied to operands of type 'SomeProtocol' and 'T'"
not sure how can i fix that, both object where defined as AnyObject who confirm to the SomeProtocol protocol, so what is the problem here?

For comparing two generics, you can declare the generics such that, types, that are capable to be in the place of your generic type, should conform to Comparable protocol.
struct Heap<T: Comparable>{
var heap = [T]()
}}
Now we will be able to do:-
if heap[parentIndex] < heap[childIndex] {
//Your code
}
How this works?
As we know, conforming to a protocol means implementing all the required methods in that protocol. Comparable protocol has got all the comparison methods as required parameters, and any type that is implementing Comparable will be able to do a comparison.
Happy coding using Generics.

If you want reference equality, then you need to ensure SomeProtocol only applies to classes (since you can’t use reference equality on structs, as they’re value types):
protocol SomeProtocol: class { }
Now, only classes can implement SomeProtocol.
You don’t need generics to use reference equality now, just regular run-time polymorphism:
func removeObj(obj: SomeProtocol) {
// since any SomeProtocol-conforming object
// must be a class, you can now use ===
if let idx = allObjs.indexOf({ $0 === obj}) {
allObjs.removeAtIndex(idx)
}
}

The generic function must also conform to the Equatable protocol

Related

Can #dynamicMemberLookup be used to call methods?

In the documentation for #dynamicMemberLookup it says,
Apply this attribute to a class, structure, enumeration, or protocol to enable members to be looked up by name at runtime.
If I'm not mistaken, instance methods are considered members of a struct / class. However, when I try to call a function dynamically I get an error saying:
Dynamic key path member lookup cannot refer to instance method foo()
To reproduce the problem:
struct Person {
var name: String
var age: Int
func greet() {
print("hello, my name is \(name)")
}
}
#dynamicMemberLookup
struct Wrapper {
var value: Person
subscript<T>(dynamicMember keypath: KeyPath<Person, T>) -> T {
value[keyPath: keypath]
}
}
let person = Person(name: "John Doe", age: 21)
let wrapper = Wrapper(value: person)
wrapper.greet() // << Error: Dynamic key path member lookup cannot refer to instance method `greet()`
// Or
let function = wrapper.greet // << Error: Dynamic key path member lookup cannot refer to instance method `greet()`
function()
How can I dynamically call greet() using #dynamicMemberLookup? Is there any way to achieve what I'm trying to do?
Thanks in advance!
No, dynamicMemberLookup does not work for methods. As the signature of the subscript suggests, it only works for things that can be represented as a KeyPath. Method calls cannot be part of a key path. :(
Key-Path Expression
A key-path expression refers to a property or subscript of a type.
The path consists of property names, subscripts, optional-chaining
expressions, and forced unwrapping expressions. Each of these key-path
components can be repeated as many times as needed, in any order.
At compile time, a key-path expression is replaced by an instance of
the KeyPath class.
I suspect the reason why it is called "dynamic member lookup" is because it also works with subscripts. The alternative of dynamicPropertyOrSubscriptLookup is rather a mouthful isn't it?
One rather hacky fix would be to change greet into a computed property:
var greet: () -> Void { {
print("hello, my name is \(name)")
} }
If greet has had parameters, you could also change it into a subscript, but I think that is an even uglier solution.

Meaning of .type in Swift [duplicate]

What's the difference between metatype .Type and .self in Swift?
Do .self and .Type return a struct?
I understand that .self can be used to check with dynamicType. How do you use .Type?
Here is a quick example:
func printType<T>(of type: T.Type) {
// or you could do "\(T.self)" directly and
// replace `type` parameter with an underscore
print("\(type)")
}
printType(of: Int.self) // this should print Swift.Int
func printInstanceDescription<T>(of instance: T) {
print("\(instance)")
}
printInstanceDescription(of: 42) // this should print 42
Let's say that each entity is represented by two things:
Type: # entitiy name #
Metatype: # entity name # .Type
A metatype type refers to the type of any type, including class types, structure types, enumeration types, and protocol types.
Source.
You can quickly notice that this is recursive and there can by types like (((T.Type).Type).Type) and so on.
.Type returns an instance of a metatype.
There are two ways we can get an instance of a metatype:
Call .self on a concrete type like Int.self which will create a
static metatype instance Int.Type.
Get the dynamic metatype instance from any instance through
type(of: someInstance).
Dangerous area:
struct S {}
protocol P {}
print("\(type(of: S.self))") // S.Type
print("\(type(of: S.Type.self))") // S.Type.Type
print("\(type(of: P.self))") // P.Protocol
print("\(type(of: P.Type.self))") // P.Type.Protocol
.Protocol is yet another metatype which only exisits in context of protocols. That said, there is no way how we can express that we want only P.Type. This prevents all generic algorithms to work with protocol metatypes and can lead to runtime crashes.
For more curious people:
The type(of:) function is actually handled by the compiler because of the inconsistency .Protocol creates.
// This implementation is never used, since calls to `Swift.type(of:)` are
// resolved as a special case by the type checker.
public func type<T, Metatype>(of value: T) -> Metatype { ... }
First and foremost see Apple docs on type(of:)
The functions signature is interesting:
func type<T, Metatype>(of value: T) -> Metatype
Where is it used?
If you are writing/creating a function that accepts a type e.g. UIView.Type, not an instance e.g. UIView()then to you would write T.Type as the type of the parameter. What it expects as a parameter can be: String.self, CustomTableView.self, someOtherClass.self.
But why would a function ever need a type?
Normally a function which requires a type, is a function that instantiates objects for you. I can think of a few examples:
register function from tableview
tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "CustomTableViewCell")
Notice that you passed CustomTableViewCell.self. If later on you try to dequeue a tableView of type CustomTableViewCell but didn't register CustomTableViewCell type then it would crash because the tableView hasn't dequeued/instantiated any tableviewcells of CustomTableViewCell type.
decode function from JSONDecoder. Example is from the link
struct GroceryProduct: Codable {
var name: String
var points: Int
var description: String?
}
let json = """
{
"name": "Durian",
"points": 600,
"description": "A fruit with a distinctive scent."
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
let product = try decoder.decode(GroceryProduct.self, from: json)
print(product.name)
Notice try decoder.decode(GroceryProduct.self, from: json). Because you passed GroceryProduct.self it knows that it needs to instantiate an object of type GroceryProduct. If it can't then it would throw an error. For more on JSONDecoder see this well written answer
Trying to find a value of a certain class type. Example trying to find a viewController of a certain type among all viewcontrollers of a navigationController:
func popBackTo<T>(type: T.Type, in nav: UINavigationController? = nil, completion: ((T?) -> Void)? = nil) {
let nav = window?.rootViewController as? UINavigationController
guard let nav = nav, let destinationVC = nav.viewControllers.first(where: { $0 is T }) else {
return
}
nav.popToViewController(destinationVC, animated: true)
}
# Example call site:
popBackTo(LoginVC.self)
As an alternate workaround for where types are needed see the following question: Swift can't infer generic type when generic type is being passed through a parameter. The accepted answer offers an intersting alternative.
More about the internals and how it works:
.Type
The metatype of a class, structure, or enumeration type is the name of
that type followed by .Type. The metatype of a protocol type—not the
concrete type that conforms to the protocol at runtime—is the name of
that protocol followed by .Protocol. For example, the metatype of the
class type SomeClass is SomeClass.Type and the metatype of the
protocol SomeProtocol is SomeProtocol.Protocol.
From Apple : metaType Type
Under the hood AnyClass is
typealias AnyClass = AnyObject.Type // which is why you see T.Type
Basically where ever you see AnyClass, Any.Type, AnyObject.Type, its because it's in need of a type. A very very common place we see it is when we want to register a class for our tableView using register func.
func register(_ cellClass: Swift.AnyClass?, forCellReuseIdentifier identifier: String)
If you are confused as to what does 'Swift.' do then above, then see the comments from here
The above could have also been written as:
func register(_ cellClass: AnyObject.Type, forCellReuseIdentifier identifier: String)
.self
You can use the postfix self expression to access a type as a value.
For example, SomeClass.self returns SomeClass itself, not an instance
of SomeClass. And SomeProtocol.self returns SomeProtocol itself, not
an instance of a type that conforms to SomeProtocol at runtime. You
can use a type(of:) expression with an instance of a type to access
that instance’s dynamic, runtime type as a value, as the following
example shows:
From Apple : metaType Type
Playground code:
Easy example
struct Something {
var x = 5
}
let a = Something()
type(of:a) == Something.self // true
Hard example
class BaseClass {
class func printClassName() {
print("BaseClass")
}
}
class SubClass: BaseClass {
override class func printClassName() {
print("SubClass")
}
}
let someInstance: BaseClass = SubClass()
/* | |
compileTime Runtime
| |
To extract, use: .self type(of)
Check the runtime type of someInstance use `type(of:)`: */
print(type(of: someInstance) == SubClass.self) // True
print(type(of: someInstance) == BaseClass.self) // False
/* Check the compile time type of someInstance use `is`: */
print(someInstance is SubClass) // True
print(someInstance is BaseClass) // True
I highly recommend to read Apple documentation on Types. Also see here
They appear in different places syntactically.
In a place syntactically where you have to specify a type, Something.Type is a valid type, corresponding to the type that is the metatype (which is metaclass for classes) of Something. Something.self is not a valid syntax for a type.
In a place syntactically where you have to write an expression, Something.self is a valid expression. It's an expression of type Something.Type, and the value is the thing ("class object" in the case of classes) that represents the type Something. Something.Type is not a valid expression syntax.
This was one of those topics that confused the hell out of me today.
I was writing a generic function:
func foo<T: Protocol>(ofType: T.Type) {
T.bar()
}
And tried calling it as follows:
foo(ofType: ClassImplementingProtocol.Type) // Compiler error
Spent about 30 min researching why it wasn't working. Then I tried this:
foo(ofType: ClassImplementingProtocol.self) // Works
Turns out Xcode's code completion is very bad at showing the difference between meta types and types... From the code completion pop-up it looks like .self and .Type are the same thing:
But the "explain like im 5" of it is, when you have a method parameter of Class.Type, it is expecting an instance of Class.Type.
Class.self returns an instance of Class.Type, whereas Class.Type is referring to Class.Type...
Very unclear if you ask me.
Metatype .Type
Metatype is a type which allows you to access to parts of Class and Struct[About] type(not instance) like initializers class and static[About] properties and methods
let var1: String = HelloWorld
let var2: String.Type = HelloWorld.self
Some experiments:
class SomeClass {
required init() { }
class func foo1() { }
static func foo2() { }
func foo3() { }
}
class SomeSubClass: SomeClass { }
let a1: SomeClass = SomeClass()
let a2: SomeClass = a1
let a3: SomeClass = a1.self
SomeClass.self.foo1() //class func
SomeClass.foo1() //class func
//static. metatype by type(class name) <class_name/structure_name>.self
let c1: SomeClass.Type = SomeClass.self
//dynamic. metatype by instance
let c2: SomeClass.Type = type(of: a1)
//access to type's init, class, static throught Metatype
let d1: SomeClass = c1.self.init()
let d2: SomeClass = c1.init()
//call
c1.foo1() //class func
c1.foo2() //static func
// c1.foo3() //instance func. Instance member 'foo3' cannot be used on type 'SomeClass'
// c1.foo3(SomeClass()) //Expression resolves to an unused function
//Sub
// <class_name>.Type allows to save class and sunclass
var e1: SomeClass.Type = SomeClass.self //class
e1 = SomeSubClass.self //sub class
//Any.Type allows to save class and struct
var e2: Any.Type = SomeClass.self //class
e2 = String.self //struct
//AnyObject.Type allows to save only class
var e3: AnyObject.Type = SomeClass.self //class
e3 = NSString.self //class
get String
let typeString = "\(SomeType.Type)"
func register<T>(instance: T) {
instanceString = String(describing: type(of: instance))
}

Swift compile time errors when using generics and accessing dictionary's values

Below I have a class, B, with a generic type and the generic type has a subclass type constraint. In a separate class, A, I create a dictionary property, values, with the key as String and value as B. Class A then has methods to return or set values in the dictionary such that the values are not constrained to a single type (they maintain their generic SomeType type which is a subclass of NSObject). However, this produces the following two errors noted inline below:
class A: NSObject {
var values = [String : B]()
func get<SomeType: NSObject>(key: String) -> B<SomeType>? {
// #1 Error on line below: cannot convert return expression of type 'B<NSObject>?' to return type 'B<SomeType>?'
return values[key]
}
func set<SomeType: NSObject>(key: String, value: B<SomeType>) {
// #2 Error on line below: cannot assign value of type 'B<SomeType>' to type 'B<NSObject>?'
values[key] = value
}
}
class B<SomeType: NSObject>: NSObject {
}
I've attempted various forms of declaring the values dictionary to tell the compiler that SomeType is a subclass of NSObject and everything is going to be ok, but have been unsuccessful. Similarly to this question, I'm a bit stumped because the methods define SomeType as a subclass of NSObject and therefore things appear to be type safe when setting and getting from values.
I could remove the generic types from the methods and instead force the type to be <NSObject>, but then I'd run into the same problem as noted here.
This may not be doing what you think it's doing:
var values = [String : B]()
This isn't really [String : B], it's [String : B<NSObject>]. (I'm actually kind of surprised that this is legal syntax; I'd be tempted to open a bugreport about that; B isn't a proper type in Swift.) You may realize this already, but it's the first important note.
The second important note is that generic types are not covariant in Swift. A Thing<Cat> is not a subtype of Thing<Animal>. There are some type-theory reasons for this, and there are some technical implementation reasons for this, but the important fact is that it's not possible in Swift.
If you need to hold a variety of B types, then you'll need to build a type eraser. In your case, the type eraser could possibly be B<NSObject> with something like this:
class B<SomeType: NSObject>: NSObject {
let value: SomeType
init(value: SomeType) {
self.value = value
}
func liftGeneric() -> B<NSObject> {
return B<NSObject>(value: value)
}
}
If you need to hold just one kind of B type, then make A generic as well.

Comparing type of Generic associated type in Swift

I have the next code:
protocol Flyable {
var airspeedVelocity: Double { get }
}
func topSpeed<T: CollectionType where T.Generator.Element == Flyable>(collection: T) -> Double {
return collection.map { $0.airspeedVelocity }.reduce(0) { max($0, $1) }
}
I understood, by reading the Swift Documentation that:
You write a where clause by placing the where keyword immediately after the list of type parameters, followed by constraints for associated types or equality relationships between types and associated types.
This is the example given on the docs:
func allItemsMatch<C1: Container, C2: Container where
C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
(someContainer: C1, _ anotherContainer: C2) -> Bool {
// code
}
Note that when expressing that the associated type ItemType of the C1 type must conform to Equatable protocol you use : and not ==, why is that not the case in my example, where I have to use == to state that the Element associated type of T.Generator must conform with Flyable?
When changing == with : the compiler complains with this:
error: cannot invoke 'topSpeed' with an argument list of type '([Flyable])' note: expected an argument list of type '(T)'
You can achieve this without using Generics.
protocol Flyable {
var airspeedVelocity: Double { get }
}
func topSpeed(collection: [Flyable]) -> Double {
return collection.map { $0.airspeedVelocity }.reduce(0) { max($0, $1) }
}
class Airplane: Flyable {
var airspeedVelocity: Double = 10
}
class Rocket: Flyable {
var airspeedVelocity: Double = 50
}
topSpeed([Airplane(),Rocket()]) //50
I've found the reason here. The where clause has the next grammar:
conformance-requirement → type-identifier­:­type-identifier­
same-type-requirement → type-identifier­==­type­
So, when you want to state that your type parameter conforms to certain protocol you use :. BUT, when you want your type to be exactly of a certain type, you use ==. In my example, I wanted to take as a parameter a collection of Flyable. So, when trying to use : the compiler complained because Flyable doesn't conform to Flyable. Flyable IS Flyable, thus I must use == (or do something like what #Rahul Katariya answered)

How to create an enumeration that accepts a generic type as associated type

I'm trying to create an enumeration that accepts a generic type as associated value.
The compiler complains:
Reference to generic type 'GenericItem' requires arguments in <...>
The scheme is pretty simple:
struct GenericItem <Item:FormattableAsStringWithPrecision> {
let value: Item
}
enum Enumeration {
case Generic(values: [GenericItem])
}
I can't understand how to make this possible.
You need to add the Generic type to the enum too, the types can be inferred from the initialiser so you do not need to pass it as a generic type argument.
Below is an example of how you might do it.
struct GenericItem<T: CustomDebugStringConvertible> {
let value: T
}
enum Enumeration<T: CustomDebugStringConvertible> {
case Generic(value: [GenericItem<T>])
}
let someValue = Enumeration.Generic(value: [ GenericItem(value: "") ])
edit: I changed the FormattableAsStringWithPrecision to CustomDebugStringConvertible as I assumed it was one of your own custom protocols which can be easily swapped out, but the same logic would still apply for any protocol.

Resources