Group Group Group Group Group Group Group Group Group

raywenderlich.com Forums

What’s New in Swift 4.1?

Swift 4.1 is here! What does it mean for you? In this article, you'll learn about the most significant changes introduced in Swift 4.1 and the impact they will have on your code.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/97-what-s-new-in-swift-4-1

Thanks for the tutorial.

I’m just trying to understand why you get the hash that way:

var hashValue: Int {
    return name.hashValue ^ capital.hashValue &* 16777619
}

He used Fowler–Noll–Vo hash function, but for 64bit systems, the FNV_prime constant should be 1099511628211 (not 16777619) :smile:

At the beginning of this article you show how to make a generic Band equatable, but I still don’t understand the need in this particular example. how does the class band and extension differ any way from this

class Band {
    let name: String
    let lead: LeadInstrument
    
    init(name: String, lead: LeadInstrument) {
        self.name = name
        self.lead = lead
    }
}

extension Band: Equatable {
    static func ==(lhs: Band, rhs: Band) -> Bool {
         return lhs.name == rhs.name && lhs.lead == rhs.lead
   }
}

That actually seems cleaner

I think this example paints a clear picture for me.

class Band<TheLead> {
    let name: String
    let lead: TheLead
    
    init(name: String, lead: TheLead) {
        self.name = name
        self.lead = lead
    }
}

extension Band: Equatable where TheLead: Equatable {
    static func ==(lhs: Band<TheLead>, rhs: Band<TheLead>) -> Bool {
        return lhs.name == rhs.name && lhs.lead == rhs.lead
    }
}

I was confused by the “LeadInstrument” name and was thinking it had to be the inherited class, but it just needs to be named anything to show that it is generic.

@wardrip Thank you for bringing this one up - much appreciated!

Your implementation and version isn’t generic at all, so the == operator works for bands that have different lead instruments in this case. You can actually test if either a guitar band is equal to a keyboard band or the other way round for example.

My approach and solution uses conditional conformance for generics instead, so it only works for either two Band<Keyboard> or Band<Guitar> instances. You get an error if you try to either compare a Band<Keyboard> object with a Band<Guitar> one or vice versa, since the compiler now knows that the bands have different lead instruments to begin with and in the first place after all.

Please let me know if you have any other questions or issues regarding the whole thing. Thank you! :]

@wardrip Thank you for following up on this one - much appreciated!

The LeadInstrument base class implements the Equatable protocol that both the Keyboard and Guitar classes inherit.

If you choose not to use a base class, you would have to implement Equatable in both Keyboard and Guitar. This leads to code duplication in both classes and violates the DRY coding and software development and design principle.

The only drawback with this implementation is that nothing can actually stop you from creating an instance of the LeadInstrument abstract class after all. This is a limitation of Swift. Other languages, like Java for example, allow you to specifically state that a class is abstract and that you can’t create an instance out of and from it at all no matter what.

Please let me know if you have any other questions or issues regarding all of this. Thank you! :]

@coldfire Thank you for sharing the link and pointing this one out - much appreciated! :]

@nico75005 The country’s hash value is made up by combining its name and capital hash values in order to get an unique number for each and every particular country.

One way to actually achieve this after all is by using the bitwise exclusive OR operator (^) and overflow addition operator (&+) in order to truncate the number of available bits in the result.

You can read a whole lot more about the XOR operator for bits over here and about the overflow addition operator here.

Thank you! :]

I still had a base class called LeadInstrument that both the keyboard and guitar classes inherited. I just change the generic name in the band class and extension. the constant comparisons still worked. I was just saying that what you call the generic in the class doesn’t matter what you generalize the band class to be.

This is the code I am running in my playground

class LeadInstrument: Equatable {
    let brand: String
    init(brand: String) {
        self.brand = brand
    }
    func tune() -> String {
        return "Standard tuning."
    }
    static func ==(lhs: LeadInstrument, rhs: LeadInstrument) -> Bool {
        return lhs.brand == rhs.brand
    }
}
class Keyboard: LeadInstrument {
    override func tune() -> String {
        return "Keyboard standard tuning."
    }
}
class Guitar: LeadInstrument {
    override func tune() -> String {
        return "Guitar standard tuning."
    }
}
class Band<TheLead> {
    let name: String
    let lead: TheLead
    
    init(name: String, lead: TheLead) {
        self.name = name
        self.lead = lead
    }
}
extension Band: Equatable where TheLead: Equatable {
    static func ==(lhs: Band<TheLead>, rhs: Band<TheLead>) -> Bool {
        return lhs.name == rhs.name && lhs.lead == rhs.lead
    }
}
let rolandKeyboard = Keyboard(brand: "Roland")
let rolandBand = Band(name: "Keys", lead: rolandKeyboard)
let yamahaKeyboard = Keyboard(brand: "Roland")
let yamahaBand = Band(name: "Keys", lead: yamahaKeyboard)
let sameBand = rolandBand == yamahaBand
print(sameBand)
let fenderGuitar = Guitar(brand: "Fender")
let fenderBand = Band(name: "Strings", lead: fenderGuitar)
let ibanezGuitar = Guitar(brand: "Ibanez")
let ibanezBand = Band(name: "Strings", lead: ibanezGuitar)
let sameBands = fenderBand == ibanezBand
print(sameBands)
let guitar = Guitar(brand: "Fender")
let band1 = Band(name: "Strings", lead: fenderGuitar)
let keyboard = Keyboard(brand: "Ibanez")
let band2 = Band(name: "Strings", lead: ibanezGuitar)
let bandCompair = band1 == band2
print(bandCompair)

I am with wardrip on this one, naming the generic type and the LeadInstrument class the same causes some confusion.

class Band<T> {
    let name: String
    let lead: T
    
    init(name: String, lead: T) {
        self.name = name
        self.lead = lead
    }
}

extension Band: Equatable where T: Equatable {
    static func ==(lhs: Band<T>, rhs: Band<T>) -> Bool  {
        return lhs.name == rhs.name && lhs.lead == rhs.lead
    }
}

Also, This might be a good example of where the conformance is “working” by the compiler error on the comparison.

class someFakeInstrument {
    let data: String
    init(data: String) {
        self.data = data
    }
}
let guitar2 = Guitar(brand: "someBrand")
let band3 = Band(name: "bob", lead: guitar2)
let notAndInstrument = someFakeInstrument(data: "blabla")
let fakeBand = Band(name: "joe", lead: notAndInstrument)
let notCool = band3 == fakeBand

This tutorial is more than six months old so questions regarding it are no longer supported for the moment. Thank you!