Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS Generics in Swift 2 Introduction to Swift Generics Generic Methods

Benefits of Generics versus Protocols

What is the benefits of using Generics instead of using Swift Protocols. This example could also be solved with Protocols:

import UIKit


protocol CheckType {
    var subtotal: Double {get set}
    var note: String? {get set}
}

//Base Class
class GuestCheck: CheckType{

    var roomNo: Int?
    var chargeType: ChargeType?
    var note: String?
    var subtotal = 10.0
    var gratuity = 0.0
    var tax: Double{
        return subtotal * 0.05
    }
    var total: Double{
        return subtotal + gratuity + tax
    }

    enum ChargeType {

        case Restaurant
        case RoomService
        case SpaServices
        case Entertainment
        case Fitness
    }
}

class RestaurantCheck: GuestCheck{

    var foodSubtl = 0.0
    var bevSubtl = 0.0
    var tableNo: Int

    init(tableNo: Int){
        self.tableNo = tableNo
        super.init()
        self.chargeType = .RoomService
    }

}

class SpaCheck: GuestCheck{

    var therapistID: Int?
    var productsPurchased = []
    var servicesPurchased = []

    override init(){
        super.init()
        self.chargeType = .SpaServices
    }

    enum SpaServices {
        case massage
        case mudBath
        case manicure
        case pedicure
    }

    enum SpaProducts {
        case massage
        case mudBath
        case manicure
        case pedicure
    }
}

func guestRetroDiscountProt(discount: Double, originalGuestCheck: CheckType, note: String) -> CheckType{
    var guestCheck: CheckType = originalGuestCheck
    guestCheck.note = note
    guestCheck.subtotal = guestCheck.subtotal * (1-discount)
    return guestCheck
}


var tmpSpa2 = SpaCheck()
tmpSpa2.subtotal = 40.0

tmpSpa2 = guestRetroDiscountProt(0.25, originalGuestCheck: tmpSpa2, note: "Another note") as! SpaCheck

I agree that this requires force unwrapping and declaring another local variable. But otherwise it seems to work just fine. Or am I missing some other benefit here?

One other difference i found was the memory information passed in to the function.

i printed guestcheck from instructor's implementation which is 8 and originalGuestCheck from your implementation and that is 40.

which suggests that generics optimizes both implementation and memory. Curious to know if there are any other differences.

Abdulwahab Alansari
Abdulwahab Alansari
15,151 Points

Interesting input Hemanth C, how did you get the memory information?

5 Answers

The short answer is that there is no advantage to using Generics over Protocols because the two actually complement each other. But to answer your question more directly, which I have interpreted as, "Why did we use Generics when we could have used Protocols" the answer is that Gabe should have in fact used Protocols for this particular example as you have done. Swift was described as a Protocol oriented language at the WWDC in 2015 which means Protocols are the semantic way of doing things. The problem in Gabe's video could have been answered using Generics or Protocols but Protocols would have been the better design feature. Why? Because Protocols will keep the classes leaner and more composed.

jonathan chadeyras
jonathan chadeyras
15,015 Points

Hi,

My take on that is that even if it might not be obvious given the exemple above, you might want to be able to use one function to do similar tasks on 2 totally different objects that have nothing to do with each other and therefore should not conform to the same protocol.

David Lin
David Lin
35,864 Points

The proper use of protocols is to specify the required properties and methods which are expected to be in objects that conform to them. You use protocols to define the interfaces of objects.

Generics, on the other hand, are basically placeholders to represent any type of object (or, that which conforms to specified constraints). You use generics to increase the flexibility of your properties and methods, to help reduce the need to re-write nearly identical code which differs only on the expected type.

The two can be used together, for example, using a protocol in a generic type constraint. Refer to the video Generic Type Constraints.

Toby Morgan
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Toby Morgan
iOS Development Techdegree Graduate 23,133 Points

You could even add the method as an extension to the original protocol in this case:

extension CheckType {

    mutating func applyRetroDiscount(discount: Double, note: String) {
        self.note = note
        self.subtotal = self.subtotal * (1-discount)
    }
}

And call it like this:

tmpSpa2.applyRetroDiscount(discount: 0.25, note: "Yet another note!")
Abdulwahab Alansari
Abdulwahab Alansari
15,151 Points

Maybe it is something not related to the asked question, but why did you need to use "mutating" keyword here? I thought it is only the case in Structs

A late answer but...

The biggest advantage of generics over protocols is that generics don't require casting, and don't lose type information. Take a look at this example:

func returnSomeHashable(_ in hashable: Hashable)-> Hashable {
    return in
}

let a = 3
let b = returnSomeHashable(3) //b is now `Hashable`, not `Int`

If you want to use b as an Int you will have to cast it, which is a failable operation and leads to unsafe code and more code complexity.

With generics:

func returnSomeHashable<T: Hashable>(_ in hashable:T)-> T {
    return in
}

let a = 3
let b = returnSomeHashable(3) //b is still an `Int`

Now you don't need to cast b into anything. The compiler guarantees the type of the return value.

Protocols are there to lose type information. Often times you don't want that. Generics let you write equally generic code without losing any type information.