UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: How do I build the car? Losing my mind lol

Forums > 100 Days of SwiftUI

@xan  

Going through Day 9 and am absolutely stumped here on how this closure should work from this optional guide: https://www.hackingwithswift.com/quick-start/understanding-swift/when-would-closures-with-parameters-be-used-as-parameters

let changeSpeed = { (speed: Int) in
    print("Changing speed to \(speed)kph")
}

func buildCar(name: String, engine: (Int) -> Void) {
    // build the engine
}

I have tried everything imaginable to use this buildCar function and pass in a closure, been banging my head on it for over an hour now and have no idea how to actually use it.

This is the closest I've gotten, which still doesn't print anything at all, doesn't error but does give a warning of "Constant 'jeep' inferred to have type '()', which may be unexpected"

let jeep = buildCar(name: "Jeep", engine: { (speed: Int) -> Void in
    print("Beep")
})

print(jeep)

2      

I don't think that Paul is actually expecting you to write the code to build the car here. I think he was just putting in that comment to say "The code for building the car would go here, but we're not going to get into all that right now. Right now, I'm just trying to show you that a closure with parameters can be passed into a function as a parameter."

But, I find this example to be very confusing. It basically tries to say that we need an engine to put into a car, and the function of changing speed is representing the whole physical engine that we are putting into our car for some reason. I don't really understand that myself.

I think it would have made more sense to give an example like this...

import Foundation

let speedUp = { (speed: Int) in
    print("Speeding up to \(speed)kph")
}

let slowDown = { (speed: Int) in
    print("Slowing down to \(speed)kph")
}

func driveCar(desiredSpeed: Int, speedAdjuster: (Int) -> Void) {
    speedAdjuster(desiredSpeed)
}

//Then we can use the driveCar function like this
driveCar(desiredSpeed: 100, speedAdjuster: speedUp)
driveCar(desiredSpeed: 10, speedAdjuster: slowDown)

You see that we can pass either our speedUp or our slowDown closure into the call to the driveCar function as our speedAdjuster. That is because both closures are of the type (Int) -> Void (A closure that takes an Int as a parameter, and doesn't return anything.)

You might notice that you could have set the car to 10kph last, but then use this

driveCar(desiredSpeed: 100, speedAdjuster: slowDown)

And it would print "Slowing down to 100 kph" which doesn't make much sense. But I didn't put tests in to make sure that you are actually setting the speed lower or higher when using each of those closures.

4      

@xan is driving on the wrong side of the road:

This is the closest I've gotten .. but does give a warning of "Constant 'jeep' inferred to have type '()', which may be unexpected"

At times like this, pull over to the shoulder, take a good look at the map, and ask the age old question, "What is the compiler telling me?"

See -> What type is this?

Using the technique described above, hold down the option key and hover over the variable jeep in your code. XCode will report back and tell you what type it thinks the variable is.

For example:

// Hover over the variable theUltimateAnswerToLife
// XCode will tell you this variable is an Integer
let theUltimateAnswerToLife = 42

// Hover over the variable favoriteWebSite
// XCode reports that this is a String
var favoriteWebSite = "hackingWithSwift.com"

// Now hover over the variable jeep in your code.
// What do YOU think jeep should be?  An integer? A string?
let jeep = buildCar(name: "Jeep", engine: { (speed: Int) -> Void in
    print("Beep")
})

When you hover over your variable jeep, what do YOU think jeep should be? An integer? A string?

What type is jeep ?

You are setting a constant by using let. You are setting the constant jeep to the value returned by the buildCar() function. You defined the buildCar() function to take in some variables, but returns nothing! So, you are trying to create a constant variable whose type will always be (). Yeah, the compiler is your friend here. Listen to it.

The compiler is correctly telling you that jeep is (). If further alerts you that this may be unexpected!

How to fix

Indeed, sometime you want code to just run and you don't care about the return type. In the CS193p courses, Paul Hegarty calls these variables Don't Cares.

So, if you don't care what type jeep is, then the normal course of action is to TELL the compiler you don't care.

In Swift, please use the underscore character to tell XCode that you don't care.

// Tell the compiler you don't care about what is returned.
// Use the underscore character!
// XCode will execute the buildCar() function and ignore the undefined return type.
let _ = buildCar(name: "Jeep", engine: { (speed: Int) -> Void in
    print("Beep")
})

// Compiler warning goes away!

How to fix, part II

@FlyOstrich shows another way to fix, but this only works in Playgrounds. Instead of assigning to a constant, just run the function!

// You CAN assign the function's return value to a Don't Care.
let _ = buildCar(name: "Jeep", engine: { (speed: Int) -> Void in
    print("Beep")
})

// OR, you can just run the function without the assignment
buildCar(name: "Jeep", engine: { (speed: Int) -> Void in
    print("Beep")
})

3      

@xan  

Awesome, appreciate both the responses, helped me learn a lot. Still only on day 10 now but loving it, coming from PHP-land.

It turns out this page might not even be linked anywhere normally. When on Day 9 it's not any of the optional reading, but if you start at the top optional article and keep hitting the next article link in the top you end up there. I'm not sure why there's links at the top left and top right for optional reading that don't seem to follow the order of the lessons, but that's how I got lost trying to figure out how to do something before reading about how to do it haha.

Thanks again, and have a great next few days!

2      

I must be doing something wrong in this post because it's not formatting the code properly. I put three double quotes around the code. Is that not the right way?

But the original question remains unanswered: How do you call buildCar?

func buildCar(name: String, engine: (Int) -> Void) {
    // some code
}

buildCar is a function that takes a String and a closure of type (Int) -> Void and the function returns nothing. We've already created a closure called changeSpeed of type (Int) -> Void

let changeSpeed = { (speed: Int) in
    print("Changing speed to \(speed)")
}

My thinking was to pass in changeSpeed to the buildCar function for the engine parameter

buildCar(name: "tesla", engine: changeSpeed)

Shouldn't that work? In playgrounds, it does not print anything. In fact, this prints nothing as well:

buildCar(name: "jeep", engine: { (speed: Int) -> Void in
    print("the jeep goes beep")
})

How should buildCar be called?

A couple of asides:

  • How do you make some text red and also increase the font size in your posts?
  • Also, when I'm in playgrounds and I option-click on something, I get the question mark, but it never tells me what the type is. It shows a plus sign.

Thanks, Rob

2      

Not double quotes, backticks: ```

Or just hit the </> button in the toolbar above and paste your code in between the marks that are inserted. This is how you would post a block of code.

If you hit that button while on a line that already has text, you'll get the markdown for inline code: `` and can paste something in between them. This is useful for marking short snippets like if you wanted to call out a map(_:) function or a single variable name.

2      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.