Errata for Swift Apprentice v1.3

This topic is for bugs, typos, and other mistakes in Swift Apprentice v1.3.

Chapter 20: Protocol-Oriented Programming, page 262
In Example:

protocol MyProtocol {
    func bar() // not foo()
}

extension MyProtocol {
    func bar() { print("Hello!") }
}

struct MyType: MyProtocol {
    func bar() { print("Good Day!") }
}

When method is not defined in the protocol - Calls Protocol Extension (not local implementation)

When method is defined in the protocol - Calls local implementation: the result will be “Good Day!”
(Sorry, I can’t post second image, because I’m a new user.)

1 Like

Edit
I’m going to keep a running list of things I find instead of making a new post for each.

1. Page 48 PDF.

Typo in top example, variable used in the operation should be counter += 1

This is what’s currently there:

var counter = 0 count += 1 counter // counter = 1 counter -= 1 counter // counter = 0

2. Page 61 PDF

typo: “is” for “if” and “that” for “than”

Just as with numbers, you can compare not just for equality, but also to determine is one value is greater than or less that another value.

1 Like

On page 238 the sentence “You follow the name of the named type with a semicolon and the name of the protocol you want to conform to.” says to use a “semicolon ( ; )”. I believe that should be a “colon( : )”

On page 244 in the declaration of wheeledVehicleBike:

let wheeledVehicleBike: WheeledVehicle5 = bike

I believe the ‘5’ at the end of “WheeledVehicle5” is a typo.

1 Like

Chapter 20: Solution of challenge A
Clothing(name: "Shirt", msrp: 12.99, clearance: true).totalPrice() = 12.99
Clothing(name: "Last season shirt", msrp: 12.99, clearance: false).totalPrice() = 12.99, too ?

Chapter 12: Sets > Accessing elements (page 145)

You can also use the first and last properties, which return one of the elements in the set.

When in fact .first works but .last does not - it returns the Swift error:

Type 'SetIndex<Int> does not conform to protocol 'BidirectionalIndexType'

Chapter 13: Structures > Introducing methods (page 160)

The function isInRange3 is defined:

func isInRange3(customer: Location) -> Bool {

However undefined isInRange is subsequently called right after (top of page 161):

print(isInRange(customer)) // Pizza time!

These function names should be the same (isInRange).

Chapter 13: Structures > Introducing methods (page 161)

For the following code snippet:

struct DeliveryRange { var range: Double let center: Location func isInRange(customer: Location) -> Bool { let difference = sqrt(pow((latitude - center.latitude), 2) + pow((longitude - center.longitude), 2)) return difference < range } // initializers here }

Swift complains that latitude and longitude are unresolved identifiers. This can be resolved by correcting the code as follows:

let difference = sqrt(pow((customer.latitude - center.latitude), 2) + pow((customer.longitude - center.longitude), 2))

Chapter 15: Advanced classes > Polymorphism (page 183)

print( phonebookName(person) ) // Appleseed, John

The commend should instead read: // Appleseed, Johnny

Chapter 19: Protocols > Typealias in protocols (page 243)

protocol WeightCalculatable { typealias WeightType func calculateWeight() -> WeightType }

Swift is reporting that typealias is deprecated here, and wants to replace it with associatedtype.

Chapter 19: Protocols > Equatable and comparable (page 252)

In the second code block, this line:

leagueRecords.minElement() // {wins 23, losses 8}

Should be corrected as:

leagueRecords.minElement() // {wins 14, losses 11}

Page 261 - Introducing protocol extensions

Code is missing parenthesis for the winningPercentage calculation, should be:

func winningPercentage() -> Double {
return Double(wins) / (Double(wins) + Double(losses))
}

Page 266 struct HockeyRecord should be HockeyRecord2

or on page 267 you should change the == func to refer to HockeyRecord

Chapter 20 - Challenge A -Page 271

Extra () in Item protocol definition should be:
protocol Item {
var name: String { get }
var clearance: Bool { get }
var msrp: Float { get }
func totalPrice() -> Float
}

also the solution file uses a Double instead of a Float

Solution for Chapter 20 - Challenge A

The solution has a lot of errors in it:

Specifically:

Clothing(name: "Shirt", msrp: 12.99, clearance: true).totalPrice()

returns $12.99 when it should have adjusted the price to $9.74

The reason for this error is because it is using the totalPrice function from the Item protocol and wasn’t overriden with the extension that required the struct have both TaxableItem and ClearanceableItem protocols.

Here is a version I came up with that cleaned up the errors, and I think helps demonstrate the concepts from the chapter:

import Foundation

// Item Protocol
protocol Item: CustomStringConvertible {
    var name: String { get }
    var msrp: Double { get }
    func totalPrice() -> Double
}

extension Item {
    func totalPrice() -> Double {
        return msrp
    }
}

extension Item {
    var description: String {
        let stringMsrp = String(format: "$%.2f", msrp)
        var _description = "\(name) - \(stringMsrp)"
        if let e = self as? ExpirableItem {
            _description += e.expirableDescription
        }
        if let c = self as? ClearanceableItem {
            _description += c.clearanceableDescription
        }
        return _description
    }
}

// ClearanceableItem Protocol

protocol ClearanceableItem: Item {
    var clearance: Bool { get set }
    var discount: Double { get }
    var adjustedMsrp: Double { get }
}

extension ClearanceableItem {
    var adjustedMsrp: Double {
        return msrp * (clearance ? (1 - discount) : 1.0)
    }
    
    var clearanceableDescription: String {
        let stringAdjustedMsrp = String(format: "$%.2f", adjustedMsrp)
        return clearance ? " -> ON SALE! Now just \(stringAdjustedMsrp)" : ""
    }
    
    func totalPrice() -> Double {
        return adjustedMsrp
    }
}

// TaxableItem Protocol

protocol TaxableItem: Item {
    var salesTaxPercent:Double { get }
}

extension TaxableItem {
    var salesTaxPercent: Double {
        return 0.075
    }
    
    func totalPrice() -> Double {
        return msrp + msrp*salesTaxPercent
    }
}

extension TaxableItem where Self:ClearanceableItem {
    func totalPrice() -> Double {
        return adjustedMsrp + adjustedMsrp*salesTaxPercent
    }
}

// Clothing Struct

struct Clothing: ClearanceableItem {
    let name: String
    let msrp: Double
    var clearance: Bool
    let discount = 0.25
}

// Electronic Struct

struct Electronic: TaxableItem, ClearanceableItem {
    let name: String
    let msrp: Double
    var clearance: Bool
    let discount = 0.05
}

// ExpirableItem Protocol

protocol ExpirableItem: Item {
    var expirationMonth:Int {get}
    var expirationYear:Int {get}
}

extension ExpirableItem where Self: Item {
    var expirableDescription: String {
        return " expires \(expirationMonth)/\(expirationYear)"
    }
}

// Food Struct

struct Food: ClearanceableItem, TaxableItem, ExpirableItem {
    let name: String
    let msrp: Double
    var clearance: Bool
    let expirationMonth: Int
    let expirationYear: Int
    let discount = 0.5
}

Food(name: "Bread", msrp: 2.99, clearance: false, expirationMonth: 11, expirationYear: 2016).totalPrice()
Food(name: "Old Bread", msrp: 2.99, clearance: true, expirationMonth: 11, expirationYear: 2016).totalPrice()

Clothing(name: "Shirt", msrp: 12.99, clearance: false).totalPrice()
Clothing(name: "Last season shirt", msrp: 12.99, clearance: true).totalPrice()

Electronic(name: "Apple TV", msrp: 139.99, clearance: false).totalPrice()
Electronic(name: "Apple TV 3rd gen", msrp: 99.99, clearance: true).totalPrice()

//// Custom string convertible demonstration
Food(name: "Bread", msrp: 2.99, clearance: false, expirationMonth: 11, expirationYear: 2016)
var e = Electronic(name: "Apple TV 3rd gen", msrp: 99.99, clearance: false)

// Show the impact of changing the clearance flag
e.totalPrice()
e.clearance = true
e.totalPrice()

Just FYI, their solution (and yours) still do not have a struct for a Household item. The challenge calls for 4 item varieties, not 3.

The last closure definition on page 101

multiplyClosure = { (a, b) in a*b }

returns an error because the parameter types and return type cannot be inferred:

Playground execution failed: Chapter02.playground:62:38: error: ambiguous use of operator ‘*’
let multiplyClosure4 = { (a, b) in a * b }

Chapter 8: Closures, page 105 (PDF)
Incorrect result given in text for code example.

Text says, "For example, you could write this function:

func countingClosure() -> (() -> Int) {
  var counter = 0
  let incrementCounter: () -> Int = {
    counter += 1
    return counter
}
return incrementCounter
}

"… this could be used like so:

let counter1 = countingClosure()
let counter2 = countingClosure()
counter1() // 0
counter2() // 0
counter1() // 1
counter1() // 2
counter2() // 1

But instead, the first call to each instance returns ‘1’, because the internal counter is incremented before its value is returned.

Chapter 8: Arrays, page 136
Deleting elements: Deleting an element leaves a gap where the removed element was. As was mentioned earlier, all elements in the array have to be sequential so this gap needs to be closed by shifting elements forward.
The complexity is similar to inserting elements: If you’re removing an element from the beginning or the end, it’s an O(1) operation. If you’re removing from the middle, the complexity is O(N).

I am wondering if you remove the first element while keep the array address not change, you may need to shift all rest elements forward, then the complexity will be O(n), right?

Chapter 11. Structures.
On page 168, there’s a mini-exercice to calculate if 2 areas are overlapping. In the code provided, the function goes as follow:
func overlaps(with area: DeliveryArea) -> Bool { return distance(from: center, to: area.center) >= (range + area.range) }
Shouldn’t this be <= ? With this code, I can demonstrate that these 2 areas overlap:
let area1 = DeliveryArea(range: 2.5, center: Location(x: 2, y: 4)) let area2 = DeliveryArea(range: 2.5, center: Location(x: 2, y: 15)) area1.overlaps(with: area2)

1 Like

I couldn’t find an Errata for v2.0 of this book, so I posted it here.

I just started the book(v2.0), and I made it to chapter#2 challenge question#8 where I hit a wall. The only solution I could come up with involved a basic cast operation, but cast operations hadn’t yet been covered. So after banging my head against the wall for another 20 minutes I opened up the solutions file that’s included with the book, and lo and behold you guys used a cast operation… :confused:

I’m able to work through the issue because this isn’t my first programming language, but given the books narrative and the first chapter being a very very brief introduction to how a computer works; I’m assuming that the target audience is not necessarily a seasoned programmer. Type conversions isn’t discussed until the following chapter.

Unless I missed something extremely obvious when I was reading/skimming, I think if you’re going to require the use of casting to solve your challenge problems, you need to at least touch on the subject before it’s required :wink:

Looks, like you never got a response.
I concluded the same thing you did, but thought, “I must be wrong somehow”, and went over it and over it.
So, I was glad to see your post, which made me feel a little better.
I think we’re right.
Too bad they didn’t reply.

1 Like

They haven’t replied at all :sweat:

Page 16, Introduction: “…languages, and some that Swift approves upon in novel ways.” Should be, “improves”

Thank you all for your valuable feedback on the book chapters - much appreciated. We are currently in the process of updating the whole thing to Swift 4 after all for sure and for good indeed, so stay tuned. Thanks again all! :]