Protocol Oriented Programming - OOP REVISITED - Understanding Swift Programming: Swift 2 (2015)

Understanding Swift Programming: Swift 2 (2015)

PART 4: OOP REVISITED

34. Protocol Oriented Programming

At the June, 2015 Apple World Wide Developer's conference, the most popular presentation was Dave Abrahams' talk on "Protocol Oriented Programming."

Abrahams revealed that Swift had been designed from the beginning—with its lightweight alternatives to classes such as structures and enumerations, and its emphasis on protocols—to be what he called "the first protocol oriented programming language." This description was met with broad applause. Abrahams described protocols as being "at the heart of" the design of the language.

Protocol oriented programming is something that the Apple people seemingly hope will be a very big deal for Swift, for Swift's potential emergence as a more generally used language, and for programming methodology in general.

Swift 2 includes a capability for "protocol extensions," which allows methods and properties to be implemented in extensions to protocols and in this way obtained and used by classes, structures, and enumerations. Since a class, structure, or enumeration can conform to more than one protocol, and thus obtain methods and properties from multiple protocols, protocol oriented programming in Swift seems to be in this one sense more powerful than class-based inheritance, which (in Swift) only allows inheritance from one superclass.

In this chapter I will first describe some of the criticisms that have been made against classes and inheritance. I will then discuss how protocols might do things better. I'll describe various ways of using protocol extensions and the so-called Self requirement used with protocols. I'll finish with a discussion of some of the implications of protocol oriented programming.

What's Wrong with Classes and Inheritance?

Object-oriented programming has become so dominant and so widely practiced that it is easy to believe that the approach must be the best that software technology has to offer. In fact, however, there's been a lot of skepticism expressed by people with rather distinguished backgrounds. Much of this has been directed at classes and inheritance. Alan Kay has been quoted as saying "I invented the idea of object-oriented programming, and I can tell you that I did not have C++ in mind", and "Java is the most distressing thing to hit computing since MS-DOS."

Edsgar Dijkstra, a Dutch academic and Turing award winner, was highly critical of object-oriented programming. (The quote that has circulated most widely, however, that "Object oriented programming is an exceptionally bad idea which could only have originated in California," is apparently bogus.)

Of course, it is common for programmers to believe that "the language I use is great, but yours is garbage." What is perhaps more interesting and credible are statements from practitioners of object-oriented programming, such as the authors of the well-known book Design Patterns, written by the so-called Gang of Four. They and others warn about the overuse and abuse of inheritance, and one of the principles they suggest is "favor composition over inheritance." In other words, use the design pattern of composition instead of inheritance unless you really need inheritance. Composition is the use of classes in combination without any hierarchical relationship between them. Thus, a class that needs to use a method defined in another class will create an instance of that class (or access a class method directly), execute a method from that other class, and use the result. Often, a class will define a property that holds an instance of another class to allow it to quickly and easily use the methods of that other class. Both inheritance and composition are intended to avoid the necessity of duplicating methods (which makes maintenance a nightmare) by allowing a class to use methods contained in another class.

What is specifically wrong with inheritance? There are three general criticisms:

1. Inheritance too often isn't a good way to represent reality, and is inflexible over time.

2. Inheritance, as usually implemented, involves an automatic sharing of data that is unsafe and/or inefficient.

3. Inheritance is too intrusive, in a paradigm that claims to avoid tight coupling among different objects.

I'll discuss each of these in some detail:

NOT A GOOD, OR STABLE, REPRESENTATION

The use of classes and inheritance in object-oriented systems was originally considered a good idea largely because objects and their relationships were supposedly good models of the real world. And classes and inheritance were thought to be a good way to represent the real world in part because of the apparent success of two kinds of categorization and classification systems: the taxonomic system in biology, and the classification systems used for books in libraries.

Biological systems, of course, have anomalies. There are penguins (birds that cannot fly), bats (mammals that can fly), and whales (mammals that live in the ocean.) These cases, though annoying, could presumably be handled in software classes by overriding inherited properties and methods that did not apply to a particular class.

Evolution, however, proceeds slowly. Software requirements, in contrast, often change very quickly. And one of the biggest problems with inheritance is its inflexibility. We can see the effect of change quite clearly by looking at the Dewey Decimal system category for Religion (from Clay Shirky's paper "Ontology is Overrated"):

200: Religion

210 Natural theology

220 Bible

230 Christian theology

240 Christian moral & devotional theology

250 Christian orders & local church

260 Christian social theology

270 Christian church history

280 Christian sects & denominations

290 Other religions

Readers in the early 20th century West (when this system was created) were apparently not much interested in reading about non-Christian religions, which of course had far more adherents than Christianity. In the early 21st century, when the world is smaller, information about other religions is more accessible, and terrorists are crashing airplanes into buildings in the name of Islam, Western readers do have an interest.

However, it is not clear that software developers defining classes and class hierarchies are any better at predicting the future than librarians.

The library systems also have an inherent bias that has nothing to do with their apparent claim to be classifying general knowledge. Here's the Library of Congress system for History, again from Shirky:

D: History (general)

DA: Great Britain

DB: Austria

DC: France

DD: Germany

DE: Mediterranean

DF: Greece

DG: Italy

DH: Low Countries

DJ: Netherlands

DK: Former Soviet Union

DL: Scandinavia

DP: Iberian Peninsula

DQ: Switzerland

DR: Balkan Peninsula

DS: Asia

DT: Africa

DU: Oceania

DX: Gypsies

The Netherlands is at the same level as all of Asia and all of Africa.

As Shirky points out, the system doesn't reflect general knowledge, but only the number of books on the shelf at the Library of Congress for a particular topic.

And this "book on a shelf" observation points to another problem— the assumption that the particular piece of knowledge being categorized can be done so with a single dimension of categorization. This is a convenient assumption for libraries that (until recently) kept all their knowledge in the form of books on a shelf. A classifier picked the best classification and put the book on a particular shelf based on that single classification. Using more than one primary classification makes no sense, because a physical book can be on only one shelf. If a book is on the history of art, the classifier has to decide whether it is more about history or more about art, and put it on the appropriate shelf. (The system does have secondary classifications, and an art history book on the history shelf could be found for those looking for art, with additional effort, by such a cross-reference.)

In the digital world, however, as Shirky puts it, "there is no shelf." The implications are, for Shirky, are that there is no need for professional classifiers, for a standard (inheritance-based) classification system, or even for categories. It can all be done with links and tags, added by individuals.

Software, of course, and most of the real world it attempts to model, never had a shelf, and thinking that library classification systems, and hierarchies, are a good basis for representing knowledge generally, is a bad idea.

AUTOMATIC SHARING OF DATA

Another problem with inheritance is that a class and its superclasses all have references to the single copy of data kept in the heap part of the memory. Methods from these different classes can access this data essentially simultaneously, leading to the typical difficulties with such simultaneous access. While locks and similar threading mechanisms can prevent these issues, they add complexity and are difficult to implement in a safe and reliable manner. This often increases processing overhead and results in bugs.

INHERITANCE TOO INTRUSIVE

It is perhaps ironic that a common complaint about inheritance is that superclasses often excessively intrude upon their subclasses. The reason why this is ironic is the near-paranoid devotion to encapsulation and security voiced by so many commentators on object-oriented programming and embedded in many languages (although more recent language implementations seem to be more relaxed about this issue), and the insistence upon encapsulation and inheritance as two of the supposed fundamental principles of object-oriented programming.

The more complete "gorilla holding the banana" quote from the cartoon at the beginning of this chapter is:

The problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.

—Joe Armstrong

"Loose coupling" between objects, (or, more generally, parts of a program) is considered highly desirable as part of the general devotion to the principle of encapsulation. However, inheritance often makes it difficult to have loose coupling between objects that are instances of related classes because inheritance, and, particularly, chains of inheritance, often results in large numbers of properties and methods being inherited that substantially affect that object in a way that is difficult for the programmer to predict or keep track of. This is a frequent source of bugs.

Can Protocols Do it Better?

The protocol oriented programming approach is based on the assertion that in many situations, a protocol, along with a structure or enumeration, can work as well or better as a class would in the same situation, and without the negative side effects.

As part of the Swift design, structures and enumerations were developed that could do most of what classes could do.

We can see this most clearly with structures, which are very much like classes but with two critical differences: They do not have inheritance (and its baggage), and they are value types. That is, new instances of structures copy data, rather than reference it, so that there are none of the problems of automatic sharing of data.

Structures, like classes, encapsulate information and behavior in the form of properties and methods. Like classes, they can create instances. They provide a mechanism for controlling access to their code. They provide a namespace—code provided in the methods of a structure is accessed through the structure, avoiding collisions in naming. Structures provide a foundation for abstraction, and, like classes, are extensible.

Enumerations, perhaps less transparently, provide these same capabilities. They have the same ability to define methods and create instances, and in fact have something like stored properties, in the form of "associated values". They too are value types rather than reference types and thus avoid the automatic sharing problem.

The capability of protocol extensions to define implementations for methods and properties that can then be used by whatever structures and enumerations (and, indeed, classes) that specify that they conform to those protocols provides a mechanism that is similar to inheritance but that acts in a much more restrained manner. It is more flexible than inheritance, because a given instance-creating type (that is, a class, structure, or enumeration) can specify conformance to more than one protocol. And a given protocol, and its methods and properties, can be specified by more than one instance-creating type without regard to where it is in any knowledge representation. Protocols work much more like Clay Shirky's idea of having "no shelf" and "no categories", allowing knowledge to be represented in a more flexible, less rigid manner. Using protocols rather than inheritance is the difference between going into a restaurant and ordering strictly a la carte versus getting their No Substitutions Allowed combo special.

Because the decision about what protocols a new instance-creating type will conform to is made at a more local and individualized level, a programmer is much less likely to get a big surprise (and bug) from unexpectedly obtaining a method or property than would be the case with a large, and long, inheritance chain.

Thus, the use of structures (or enumerations) along with protocols provides the main things that classes provide with a flexible form of knowledge representation that in many situations will be superior than classes, without automatic sharing of data or the excessive intrusiveness of inheritance.

Protocols vs Protocol Extensions

There is perhaps some confusion between what defining a protocol can do and what defining a "protocol extension" can do. The latter uses the keyword extension and the name of a previously defined protocol.

A protocol definition specifies a name and defines what properties and methods are required if an instance creating type (class, structure, or enumeration) is to conform to that protocol. Defining a required method means providing the signature for that method, including its name and the types of input parameters and the return value. Defining a required property means defining the name and type of that property and whether it is a read-only and read-write property. It is also possible to indicate conformance of a protocol to a previously defined protocol or protocols, which results in properties and methods being inherited, much like class inheritance works.

A protocol extension (that is, an extension to a previously-defined protocol) could always indicate additional methods that were required for conformance to a protocol. What is new in Swift 2 is that a protocol extension can now include the implementation of one or more required methods and properties.

A Basic Protocol Extension

Suppose we have defined the following protocol:

protocol TypicalSquirrel {

var nameOfIndividual: String { get }

var nameOfSpecies: String { get }

var skinHasFur: Bool { get }

var breathesAir: Bool { get }

var whyYouShouldNotPetThem: String { get }

func sayWhetherICanFly()

}

This defines some interesting things we might want to know about a particular squirrel. We require that each individual creature (instance) have a name, and that a name be provided for the species that it is a member of. A { get }, or a { get set }, is required when properties are defined in protocols and indicates whether the property is read only ( { get } ) or read-write ( { get set } ). We also require that the instance indicate whether the squirrel has fur or not, whether or not it breathes air, and a reason for why you should not pet them.

The protocol also requires that a function be implemented, sayWhetherICanFly().

We don't want to bother defining the values for skinHasFur and breathesAir every time we define a squirrel, because they are always true. Still, at some point our program might need these values. We also don't want to bother implementing the method sayWhetherICanFly, since we rarely encounter squirrels that can fly. They almost always can't.

Thus, we provide an extension to the TypicalSquirrel protocol as follows:

extension TypicalSquirrel {

var skinHasFur: Bool { return true }

var breathesAir: Bool { return true }

var whyYouShouldNotPetThem: String { return "They might have fleas with the plague" }

func sayWhetherICanFly() {

print("I am a typical squirrel and I can walk and climb trees but not fly.")

}

}

Why don't we just use a class and inherit information and behavior from a big class like Mammal? Well, we could—but the general approach of protocol oriented programming is based on a bit of suspicion about whether we might get in trouble if we do this. Are there things about mammals—perhaps implemented in some third-party code written by people we don't completely trust—that might not be true of our squirrels? It is safer to use smaller components that, because they are intended to be more specific, are more likely to be trustable.

So we then define a structure that allows us to create instances of squirrels, named Squirrel, and we adopt the TypicalSquirrel protocol so that we can obtain the default characteristics and behavior of typical squirrels:

struct Squirrel: TypicalSquirrel {

var nameOfIndividual: String = ""

var nameOfSpecies: String = ""

}

We include the properties nameOfIndividual and nameOfSpecies in this structure because the protocol requires them. We also provide an initial value. We don't include either for properties that are already defined in the protocol extension. We don't include the method that is defined in the protocol extension.

We can then create a representation of an individual squirrel named "Pete" (an instance of the structure Squirrel):

var pete = Squirrel(nameOfIndividual: "Pete", nameOfSpecies: "Gray Squirrel")

And we can print out some of his characteristics:

print(pete.nameOfSpecies) // Prints: Gray Squirrel

print(pete.skinHasFur) // Prints: true

print(pete.breathesAir) // Prints: true

print(pete.whyYouShouldNotPetThem)

// Prints: They might have fleas with the plague

And execute the one method that indicates some of his 'margin-bottom:0cm;margin-bottom:.0001pt;line-height: normal'>

pete.sayWhetherICanFly()

// Prints: I am a typical squirrel and I can walk and climb trees but not fly.

What to Do When Squirrels Can Fly

This is fine. But say we drive up to the mountains. And in a remote area, high up, we meet another squirrel, George. And he is a Northern Flying Squirrel.

He's pretty rare. In any particular place, it is likely that there will be only one species of flying squirrels. It's thus not worth creating a protocol just for them. So perhaps we just create a different structure we call FlyingSquirrel. We also use the protocol TypicalSquirrel, but we effectively override a few things. We provide a different value for whyYouShouldNotPetThem than the protocol extension provides. And we provide a new method that overrides the implementation of the method sayWhetherICanFly.

struct FlyingSquirrel: TypicalSquirrel {

var nameOfIndividual: String = ""

var nameOfSpecies: String = ""

var whyYouShouldNotPetThem: String = "They are not friendly and have sharp teeth."

init (nameOfIndividual: String, nameOfSpecies: String) {

self.nameOfIndividual = nameOfIndividual

self.nameOfSpecies = nameOfSpecies

}

func sayWhetherICanFly() {

print("I am a flying squirrel and I can walk and climb trees and also fly, or at least glide.")

}

}

Note that we do not include the keyword override with our new implementation of that method. (We would need this if we were using a class and overriding a method that was inherited from a superclass, but not with protocols.)

We can then create an instance of Flying Squirrel named "George":

var george = FlyingSquirrel(nameOfIndividual: "George", nameOfSpecies: "Northern Flying Squirrel")

And print out some of his information:

print(george.nameOfSpecies) // Prints: Northern Flying Squirrel

print(george.skinHasFur) // Prints: true

print(george.breathesAir) // Prints: true

print(george.whyYouShouldNotPetThem)

// Prints: They are not friendly and have sharp teeth

And execute the one method that indicates some of his 'margin-bottom:0cm;margin-bottom:.0001pt;line-height: normal'>

george.sayWhetherICanFly()

// Prints: I am a flying squirrel and I can walk and climb trees and also fly, or at least glide.

This is a book about programming, not biology, so I won't get into the issue of whether flying squirrels actually fly. But see the animation of a flying squirrel coming in for a landing and decide for yourself at:

http://understandingswiftprogramming.com/flyingsquirrel

Note that we could have, as an alternative, created an additional protocol and protocol extension named TypicalFlyingSquirrel, and done things in the way that we did them for Squirrel. But you don't want to create zillions of protocols.

Using Protocols for Conditional Implementations

Now let's say that you are a biologist working in Monterey, California, and spend most of your time at the shore of the ocean, or on a boat. For most people in most places, if they see a mammal, it will be one that lives on land. Here the situation is reversed: even on the beach, the mammals you see, aside from humans, will likely be those that live in the ocean. Here we might be especially suspicious of the idea of using a class and inheriting stuff from a very large, complicated class like all mammals.

So we will use instead a protocol MarineMammal. And because some marine mammals (e.g., seals and sea lions) can walk on land, we'll define a second protocol CanWalkOnLand.

We will use a protocol extension to define some behavior, but that behavior depends on whether a structure conforms to both protocols.

We start by defining the MarineMammal protocol:

protocol MarineMammal {

var nameOfIndividual: String { get }

var nameOfSpecies: String { get }

var skinHasFur: Bool { get }

var breathesAir: Bool { get }

}

We need a protocol extension for some basic things about marine mammals that we don't want to set every time:

extension MarineMammal {

var skinHasFur: Bool { return false }

var breathesAir: Bool { return true }

}

We then define the protocol CanWalkOnLand:

protocol CanWalkOnLand {

func iCanWalkOnLand()

}

The protocol CanWalkOnLand requires that an instance-creating type implement the function iCanWalkOnLand(), but does not actually provide an implementation for that function.

We then implement a protocol extension that provides an implementation for the iCanWalkOnLand() method, but that is only implemented if the instance-creating type we are using conforms to both the MarineMammal protocol and also the CanWalkOnLand protocol:

extension MarineMammal where Self: CanWalkOnLand {

func iCanWalkOnLand() {

print("I can walk on land.")

}

}

We can define a structure for whales:

struct Whale: MarineMammal {

var nameOfIndividual: String = ""

var nameOfSpecies: String = ""

}

Since whales cannot walk on land, it conforms only to the protocol MarineMammal. The function iCanWalkOnLand cannot be accessed.

var cynthia = Whale(nameOfIndividual: "Cynthia", nameOfSpecies: "California Gray Whale")

print(cynthia.nameOfSpecies) // Prints: "California Gray Whale"

cynthia.iCanWalkOnLand() // Compiler Error

We can now define a structure for seals and sea lions:

struct SealsAndSeaLions: MarineMammal, CanWalkOnLand {

var nameOfIndividual: String = ""

var nameOfSpecies: String = ""

}

This conforms to both the MarineMammal and CanWalkOnLand protocols. And because of the conditional protocol extension that implements the method iCanWalkOnLand(), that method will be available:

var sammy = SealsAndSeaLions(nameOfIndividual: "Sammy", nameOfSpecies: "Harbor Seal")

print(sammy.nameOfSpecies) // Prints: Harbor Seal

sammy.iCanWalkOnLand()

// Prints: "I can walk on land."

Adopting Multiple Protocols That Have Duplicate Methods

What happens if you use extensions to protocols that result in multiple implementations of the same method?

For example, we might define protocols for Mammal and MarineMammal, and require that a method be provided in both cases, the method sayCanIWalkOnLand.

We then provide protocol extensions that implement the method for each protocol.

In the case of Mammal, the method is:

func sayCanIWalkOnLand () {

print("I am a Mammal and I CAN walk on land')

}

In the case of MarineMammal, the method is:

func sayCanIWalkOnLand () {

print("I am a Marine Mammal and I CANNOT walk on land')

}

If you then define a structure, say for HarborSeal, create an instance, and try to call this method, what will happen? Which method will be executed?

The answer is that Swift (based on Swift 2 beta 2) will not allow you to create a structure that adopts multiple protocols that each have a function with the same name. The compiler gives you an error.

protocol Mammal {

func sayCanIWalkOnLand()

}

protocol MarineMammal {

func sayCanIWalkOnLand()

}

extension Mammal {

func sayCanIWalkOnLand() {

print("I am a mammal and I CAN walk on land")

}

}

extension MarineMammal {

func sayCanIWalkOnLand() {

print("I am a marine mammal and I CANNOT walk on land")

}

}

struct HarborSeal: Mammal, MarineMammal {

}

var seal = HarborSeal()

seal.sayCanIWalkOnLand()

This is the sequence of code. It allows Mammal and MarineMammal to be defined and to have extensions that define the function sayCanIWalkOnLand, which is reasonable. But it blows up on the definition of the structure HarborSeal with the following error message: multiple matching functions named 'sayCanIWalkOnLand'.

Extending Behavior of the Swift Standard Library

A frequent use of protocol extensions will likely be to provide methods that are added to the Swift standard library, and perhaps also third-party libraries.

Extensions to specific types can be added in Swift 1 by using simple extensions. For example, in standard Swift it is not possible to access a String using a subscript containing an integer. The reason is that Swift strings use Unicode and a single character can be up to four bytes long, such as an emoji or logographic (e.g., Chinese) character.

However, if you know that the strings you are dealing with contain only ordinary ASCII characters, you can use an extension to String to add the capability of accessing a character via a subscript using an integer.

In Swift 2, you can use protocol extensions to add capabilities like this. They allow you to add capabilities not to just a single type, but to multiple types at once. Thus, for example, by using a protocol extension specifying the protocol Collection Type, you can add a new capability to arrays, dictionaries, and sets (which all conform to the CollectionType protocol.)

The Self Requirement for Protocols

In an example shown by Abrahams to argue for the superiority of protocols and structures over classes in certain situations, he has a function that determines what order two values should be placed in. Such a function is commonly needed for sorting an array or for using binary search with an array. It is difficult to provide a general solution for such ordering because the correct order can depend upon the type of the values and there is often more than one reasonable way to do ordering. (The integer 5 is always greater than the integer 4, but what order should the strings "05" and "4" be in?)

In Abrahams' preferred solution, making use of a protocol and a structure, he uses the following code:

protocol Ordered d{

func precedes(other: Self) -> Bool

}

struct Number : Ordered {

var value: Double = 0

func precedes(other: Number) -> Bool {

return self.value < other.value

}

}

In the protocol, it specifies that for the instance creating type (a structure in this case) that conforms to the protocol, a function is required with the given signature, which includes an input parameter with a type of Self. This means that the input parameter must be of the same type as the structure that is being defined, Number.

(In Swift, a reference to "self" (all lower case) refers to the current instance of an instance creating type such as a class or structure. A reference to Self (first letter only in upper case) refers to that instance creating type. Note that Self can also be used in where clauses that have nothing to do with setting the Self requirement that is discussed here, but just refer to the current type.)

This reference to Self goes beyond simply indicating the type of the input parameter.

Every protocol either is subject to or is not subject to what is known as the "Self requirement." This is achieved in one of two ways.

The first way is by having that protocol specify Self as a type in a signature that is required by that protocol.

The second way is for that protocol to conform to another protocol that itself either conforms to the Self requirement or to a protocol that does. (That is, conformance to the Self requirement can be passed along indirectly like an inheritance chain.)

As an example, any protocol that conforms to the Equatable protocol will itself have a Self requirement.

Whether a class, structure, or enumeration is subject to a Self requirement has important implications for how that class, structure, or enumeration's code gets executed, how types it uses must be specified, and what types are allowed in collections that code may operate on. Execution of code with a Self requirement versus execution without are two different worlds. The differences include:

Static or dynamic dispatch. A class, structure, or enumeration that is not subject to the Self requirement is dispatched dynamically, meaning that the mapping between the reference to the name of a method and the code that executes it is determined at runtime. In contrast, code subject to a Self requirement is dispatched statically, meaning that the mapping is determined at compile time. Static dispatch is desirable because it often allows the compile to perform optimizations that it would otherwise be unable to do.

Generic Type Symbols Required. A class, structure, or enumeration that is not subject to a Self requirement can use the normal types (e.g., Int, Double, Float, String) in its methods and properties. However, if it is, that instance-creating type must specify all types by generic symbols.

Homogeneous Collections. Another requirement imposed on classes, structures, and enumerations that are subject to the Self requirement is that collections must be homogeneous. That is, an array, set, or dictionary must contain elements that are of the same actual type, not the more liberal "same type" allowed by subtyping (the subtype polymorphism principle.) This may require that elements in collections be downcast before they are used in code.

Implications of Protocol-Oriented Programming

Swift has provided us with two new ways of using object-oriented programming without inheritance. The first, in the initial design of Swift, was structures and enumerations, which do most of what classes can do except for inheritance, and are based on copying rather than referencing memory.

Now, in Swift 2, protocol extensions allow implementations of methods and properties to be part of protocols, and allow structures and enumerations, as well as classes, to obtain these implementations automatically if they conform to the protocol. This allows something like inheritance, even multiple inheritance, but without inheritance chains, based on a flat rather than hierarchical model of knowledge.

This gives us quite a few choices. The principle of "favor composition over inheritance" provided in the Design Patterns book is still valid, but composition can now be realized with structures and enumerations as well as classes. Implementations can be made part of protocols if it makes sense for those implementations to be used in more than one instance-creating type.

We don't yet know what the implications of protocol-oriented programming will be. If Apple really believes in protocol oriented programming, perhaps there will be an effort to rewrite Cocoa Touch with new APIs that are not only more oriented toward Swift but organized not as inheritance chains but with protocols.

Will protocol oriented programming, along with such other Swift attractions as type and value safety and fast execution, lead to Swift becoming popular as a server-side language in the same way that Java, Python, and Ruby are now used? Will these other languages adopt some aspects of protocol oriented programming?

It is not clear whether how revolutionary protocol oriented programming will turn out to be, but its development not only provides seemingly valuable additional capabilities, but also a lot of encouragement for programmers to think more about the architecture of their apps and to avoid the overuse and abuse of inheritance.

Hands-On Exercises

Go to the following web address with a Macintosh or Windows PC to do the Hands-On Exercises.

For Chapter 34 exercises, go to

understandingswiftprogramming.com/34