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 Introduction to Generics

Anjali Pasupathy
Anjali Pasupathy
28,883 Points

At 7:17, why use U and T when assigning the property values, rather than newMonster and monsterIn respectively?

Why not write the following code?

newMonster.lifeForce = monsterIn.lifeForce
newMonster.invincibility = monsterIn.invincibility
newMonster.position = monsterIn.position

1 Answer

Following your lead, here's a version with a magicSpellNonGeneric() function:

import UIKit

class Monster {
    var lifeForce: Int
    var invincibility: Int
    var position: Int //should be something like a Point, but I made it an Int instead, for simplicity

    init(lifeForce: Int, invincibility: Int, position: Int) {
        self.lifeForce = lifeForce
        self.invincibility = invincibility
        self.position = position
    }
}

class Goblin: Monster {
    var smell: Int

    init(lifeForce: Int, invincibility: Int, position: Int, smell: Int) {
        self.smell = smell
        super.init(lifeForce: lifeForce, invincibility: invincibility, position: position)
    }
}

class Troll: Monster {
    var jewels: Int

    init(lifeForce: Int, invincibility: Int, position: Int, jewels: Int) {
        self.jewels = jewels
        super.init(lifeForce: lifeForce, invincibility: invincibility, position: position)
    }
}

class Vampire: Monster {
    var numHollowTeeth: Int

    init(lifeForce: Int, invincibility: Int, position: Int, numHollowTeeth: Int) {
        self.numHollowTeeth = numHollowTeeth
        super.init(lifeForce: lifeForce, invincibility: invincibility, position: position)
    }
}

func randomMonsterGenerator() -> Monster {
    let randNum = Int(arc4random_uniform(3) + 1)

    switch randNum {  //the values should be random too, but for simplicity ...
    case 1:
        return Vampire(lifeForce: 2, invincibility: 3, position: 5, numHollowTeeth: 6)
    case 2:
        return Goblin(lifeForce: 2, invincibility: 3, position: 5, smell: 26)
    case 3:
        return Troll(lifeForce: 6, invincibility: 5, position: 3, jewels: 12)
    default:
        return Monster(lifeForce: 2, invincibility: 3, position: 5)
    }

}

func magicSpellNonGeneric(monsterIn: Monster) -> Monster {

    let newMonster = randomMonsterGenerator()

    newMonster.lifeForce = monsterIn.lifeForce
    newMonster.invincibility = monsterIn.invincibility
    newMonster.position = monsterIn.position

    return newMonster
}

let m1 = Goblin(lifeForce: 5, invincibility: 6, position: 23, smell: 25)
magicSpellNonGeneric(m1)

The above code works fine in a Playground.

But this, as a first attempt to translate Gabe's pseudo-code into Swift code, gives nothing but errors:

func magicSpell<T, U>(monsterIn: T) -> U {

    var newMonster: U = randomMonsterGenerator()
    //Cannot convert value of type 'Monster' to specified type 'U'

    U.lifeForce = T.lifeForce
    //Type 'U' has no member 'lifeForce'

    U.invincibility = T.invincibility
    //Type 'U' has no member 'invincibility'

    U.position = T.position
    //Type 'U' has no member 'position'

    //remove monsterIn
    return U
    //Cannot convert return expression of type 'U.type' to return type 'U'
}

So the challenge is, how to make the magicSpell() function work? How to translate Gabe's pseudo-code into Swift, assuming it can be?

Anjali Pasupathy
Anjali Pasupathy
28,883 Points

Using your code up to randomMonsterGenerator(), and modifying Gabe's pseudo-code, I wrote a solution that compiles and seems to do alright at runtime. I don't think the force unwrap should cause any problems....

func magicSpell<T: Monster, U: Monster>(monsterIn: T) -> U {

    let newMonster = randomMonsterGenerator() as! U

    newMonster.lifeForce = monsterIn.lifeForce

    newMonster.invincibility = monsterIn.invincibility

    newMonster.position = monsterIn.position

    return newMonster
}

Gabe Nadel would you be willing to comment?