Multiple Type Constraints in Swift

Multiple Type Constraints in Swift

You can use a where clause which lets you specify as many requirements as you want (all of which must be fulfilled) separated by commas

Swift 2:

func someFunc<T where T:SomeProtocol, T:SomeOtherProtocol>(arg: T) {
// stuff
}

Swift 3 & 4:

func someFunc<T: SomeProtocol & SomeOtherProtocol>(arg: T) {
// stuff
}

or the more powerful where clause:

func someFunc<T>(arg: T) where T:SomeProtocol, T:SomeOtherProtocol{
// stuff
}

You can of course use protocol composition (e.g., protocol<SomeProtocol, SomeOtherProtocol> ), but it's a little less flexible.

Using where lets you deal with cases where multiple types are involved.

You may still want to compose protocols for reuse in multiple places, or just to give the composed protocol a meaningful name.

Swift 5:

func someFunc(arg: SomeProtocol & SomeOtherProtocol) { 
// stuff
}

This feels more natural as the protocols are next to the argument.

Multiple Type Constraints

You could use an if statement when your method is called. Then have two different versions of the method (one for each type of constraint) and depending on which constraint you need to use, call the appropriate method.

More than one protocol in a type constraint

you can use this workaround

class MyCustomClass<T: Equatable where T: IndexableBase > {
var a: Array<T>
init() {
a = Array<T>()
}
}

Swift 4:

class MyCustomClass<T: Equatable> where T: Collection  {
var a: Array<T>
init() {
a = Array<T>()
}
}

Multi-level generic type constraints in Swift

I'm not sure if that's what you're looking for, but you can do it using a protocol with associated type:

struct Foo<T> { }

protocol BarProtocol {
associatedtype U: Codable
}

struct Bar<U: Codable>: BarProtocol {

}

// Now this works
extension Foo where T: BarProtocol {
// T.U can be of any type that implements Codable
}

Edit - Changed to T: BarProtocol, thanks Marcel!

How to add multiple generic type constraints in Swift?

Put it like this instead,

TableViewDataSource
<Model:ManagedObject, Cell: UITableViewCell
where Model:ManagedObjectType, Cell:ConfigurableCell>:
NSObject,UITableViewDataSource

All generic types should to be first declared separated with delimeter(comma) and then constraints should be provided later and each constraint also should be separated with comma. All the constraints has to be fulfilled in order for it to work.

Multiple constraints on parameter of a generic function

Actually You can do that.

If you have seen Codable in swift it is actually Decodable and Encodable

 typealias Codable = Decodable & Encodable

So in some function if you are using generic T as Codable

struct StructOfCodable<T:Codable>: Codable {
....
}

Here is example

protocol Test {}
class TClass {

}

typealias Common = Test & TClass

func generic <T:Common>(method:T) {

}

Another way is protocol and class both can have super class. So you can create common protocol

like

protocol CommonInProtocolAndStruct { }

protocol ProtocolUsedAsConstraint:CommonInProtocolAndStruct {}

struct StructUsedAsConstraint:CommonInProtocolAndStruct {}

And any method you can use CommonInProtocolAndStruct as generic constraint

Complex extensions with multiple type constraints

Yes, you are nearly there!

  • KeyedDecodingContainer doesn't have a RawValue type, it's K that does, as K conforms to RawRepresentable
  • AnyHashable is a concrete implementation of Hashable. Use Hashable when you want to constrain generic parameters.
  • KeyedDecodingContainer<K>.Key can be simplified to just Key, since you are in the scope of KeyedDecodingContainer<K>.
  • You don't need as Any. Everything can be implicitly converted to Any.
extension KeyedDecodingContainer where K : CodingKey,
K : RawRepresentable,
K.RawValue : Hashable {

/// A helper method
func decode<T>(into object: inout [K.RawValue : Any], _ type: T.Type,
forKey key: Key) throws where T : Decodable {
object[key.rawValue] = try self.decode(type, forKey: key)
}
}


Related Topics



Leave a reply



Submit