Associated types

An associated type declares a placeholder name that can be used instead of a type within a protocol. The actual type to be used is not specified until the protocol is adopted. While creating generic functions and types, we used a very similar syntax, as we have seen throughout this chapter so far. Defining associated types for a protocol, however, is very different. We specify an associated type using the associatedtype keyword.

Let's see how to use associated types when we define a protocol. In this example, we will define the QueueProtocol protocol that will define the capabilities that need to be implemented by the queue that implements it:

 

protocol QueueProtocol { 
  associatedtype QueueType 
  mutating func add(item: QueueType) 
  mutating func getItem() -> QueueType? 
  func count() -> Int 
} 

In this protocol, we defined one associated type named QueueType. We then used this associated type twice within the protocol-once as the parameter type for the add() method and once when we defined the return type of the getItem() method as an optional type that might return an associated type of QueueType or nil.

Any type that implements the QueueProtocol protocol must be able to specify the type to use for the QueueType placeholder, and must also ensure that only items of that type are used where the protocol uses the QueueType placeholder.

Let's look at how to implement QueueProtocol in a nongeneric class called IntQueue. This class will implement the QueueProtocol protocol using the Integer type:

class IntQueue: QueueProtocol { 
  var items = [Int]() 
  func add(item: Int) { 
    items.append(item) 
  } 
  func getItem() -> Int? { 
    return items.count > 0 ? items.remove(at: 0) : nil 
  } 
  func count() -> Int { 
    return items.count 
  } 
} 

In the IntQueue class, we begin by defining our backend storage mechanism as an array of integer types. We then implement each of the methods defined in the QueueProtocol protocol, replacing the QueueType placeholder defined in the protocol with the Integer type. In the add() method, the parameter type is defined as an instance of the integer type, and in the getItem() method the return type is defined as an optional that might return an instance of the integer type or nil.

We use the IntQueue class as we would use any other class. The following code shows this:

var intQ = IntQueue() 
int Q.add(item: 2) 
int Q.add(item: 4) 
print(intQ.getItem()) 
int Q.add(item: 6) 

We begin by creating an instance of the IntQueue class named intQ. We then call the add() method twice to add two values of the integer type to the intQ instance. We then retrieve the first item in the intQ instance by calling the getItem() method. This line will print Optional(2) to the console. The final line of code adds another instance of the integer type to the intQ instance.

In the preceding example, we implemented the QueueProtocol protocol in a nongeneric way. This means that we replaced the placeholder types with an actual type. QueueType was replaced by the Integer type. We can also implement the QueueProtocol with a generic type. Let's see how we would do this:

class GenericQueue<T>: QueueProtocol { 
  var items = [T]() 
  func add(item: T) { 
    items.append(item) 
  } 
  func getItem() -> T? { 
    return items.count > 0 ? items.remove(at:0) : nil 
  } 
  func count() -> Int { 
    return items.count 
  } 
} 

As we can see, the GenericQueue implementation is very similar to the IntQueue implementation, except that we define the type to use as the generic placeholder T. We can then use the GenericQueue class as we would use any generic class. Let's look at how to use the GenericQueue class:

var intQ2 = GenericQueue<Int>() 
intQ2.add(item: 2) 
intQ2.add(item: 4) 
print(intQ2.getItem()) 
intQ2.add(item: 6) 

We begin by creating an instance of the GenericQueue class that will use the integer type and name it intQ2. Next, we call the add() method twice to add two instances of the integer type to the intQ2 instance. We then retrieve the first item in the queue that was added using the getItem() method and print the value to the console. This line will print Optional(2) to the console.

We can also use type constraints with associated types. When the protocol is adapted, the type defined for the associated type must inherit from the class or conform to the protocol defined by the type constraint. The following line defines an associated type with a type constraint:

associatedtype QueueType: Hashable 

In this example, we specify that, when the protocol is implemented, the type defined for the associated type must conform to the Hashable protocol.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset