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

SOLVED: Question: Private(set) is already belong to a specific Struct, what does it mean by exposed to the world.

Forums > 100 Days of SwiftUI

@boat  

When Paul is demonstrating private(set) in CheckPoint6 solution, he wrote this

struct Car {
    let model: String
    let seats: Int
    var gear = 1
}

mutating func changeGear(difference: Int) {
    let newGear = gear + difference

    if newGear > 1 && newGear <= 10 {
        gear = newGear
    }
}

var car = Car(model: "BMW X3", seats: 5)
car.changeGear(difference: 1)
print(car.gear)

Then he said:

That’s a good start, but our struct has a classic problem: we’ve exposed the gear variable to the world, so it’s possible to modify it directly to something impossible like 1000.

To fix this we need to add some access control to gear. You could use private if you want, but here I think private(set) makes the most sense – let anyone read it, but only the struct’s methods can modify it:

private(set) var gear = 1

So, I tried to understand the concept of we’ve exposed the gear variable to the world, so it’s possible to modify it directly to something impossible like 1000.

I tried to take advantage of the "exposed gear variable ", so I wrote var car = Car (model: "BMW X3", seats: 5, gear: 1000)

Indeed I could make this riculous instance.

But even if I add private(set)" to var gear = 0, I still can give it a 1000 integar when I am creating a new instance.

My Question:

1, , if it is NOT a private(set) variable, what does Paul mean by "exposed it to the world" and " modify it directly " (taking advantage of its exposure) ?

I mean, it is a variable in a specific Struct anyway, it is not a global variable anyway, right ? So how private it could be ? hiding from whom ?

2, Or, if it is a private(set) variable, the mutating func can work on it anyway, without it being private, right ?

Boat

2      

He means you can't do something like this:

var car = Car(model: "Hruck Bugbear", seats: 2)
print(car.gear) //reading gear is allowed
car.gear = 1000 //setting gear is not allowed

Yes, methods of a struct have full access to the properties of the struct, which is why changeGear() would be able to alter the value of gear even if it is marked as private(set).

That's the reason why you can do this without error:

var car = Car(model: "Hruck Bugbear", seats: 2, gear: 1000)

The initializer has full access to gear.

3      

@boat  

@roosterboy , thanks for prompt reply. Really helpful.

Yes I just tried car.gear with and without private(set) , all clear now.

Have a great rest of the day !

Boat.

2      

You’ll hear @twostraws say in his videos that structs get a free member-wise initializer.

As @rooster points out, this allows you to create a new Car structure with an insane starting gear.

As your Structs become more complex, and as you design structs to be reused in your programs and in libraries you share with other developers, you’ll find business reasons to PREVENT developers from using the default member-wise initializer.

This may be an example of that!

You’ll never want to create a new car that starts off in gear 1000. But this is exactly what you can do with the default initializer. It’s a bit more work, but probably you’ll want to create your own initializer. Here’s my crack at it:

struct Car {
    let model: String
    let seats: Int
    // allow programmers to see the gear value
    // but not change the value directly.
    private(set) var gear = 1

    // Create your own initializer ----------------------------
    // This removes the default member-wise initializer
    init ( model: String, withSeats: Int) {
        if model.isEmpty { self.model = "Unknown"}
        else { self.model = model }

        if withSeats > 0 { seats = withSeats }
        else { seats = 0 }
    }

    // I want developers to use this one function to change gears.
    public mutating func changeGear(difference: Int) {
        let newGear = gear + difference
        if newGear > 1 && newGear <= 10 { gear = newGear }
    }
}

var myBMW = Car(model: "BMW X3", withSeats: 5)
myBMW.changeGear(difference: 3)

// myBMW.gear = 1000  // 'gear setter is inaccessable
print("My BMW is in gear \(myBMW.gear)")

// This fails because the Car struct does not have
// an initializer with these parameters.
var someOldCar = Car(model: "Ford Prefect", seats: 3, gear: 42)

3      

@boat  

@Obelix

I haven't learned about public mutating func, does this mean the method can be called and used on properties outside of the Struct ?

2      

@boat asks:

I haven't learned about public mutating func, does this mean the method can be called and used on properties outside of the Struct ?

mutating means "Changing". This tells SwiftUI that you intend to change one of the struct's variables in this function. public means methods and code outside of this struct can call this function. functions are public by default. This is probably why you don't see this keyword too often.

I've been corrected by that guy. Don't pay attention to what I said about functions being public by default. Probably my definition of public is also technically wrong, but probably good enough to share with this small group. Also, I don't know what I'm talking about 90% of the time.

Paste into Playgrounds:

struct GearBox {
    // allow programmers to see the gear value
    // but not change the value directly.
    private(set) var gear = 1
    private let validGears = 1...10  // range from 1 to 10

    // Create your own initializer ----------------------------
    // This removes the default member-wise initializer
    init ( withInitialGear: Int) {
        // sneaky syntax!  ~= is the contains operator for a range!
        // Set your internal private variable
        gear = 0
        if validGears ~= withInitalGear { gear = withInitalGear }
    }

    // I want developers to use this one function to change gears.
    // Because you are changing (MUTATING) an internal variable,
    // you must mark this func as mutating
    public mutating func changeGear(to newGear: Int) {
        // sneaky syntax!  ~= is the contains operator for a range!
        if validGears ~= newGear { gear = newGear }  // MUTATING the internal gear variable
    }
}

var bmwGearbox = GearBox( withInitialGear: 5)  // create a new gearbox object
bmwGearbox.gear  // Outside the object, I can read the value of gear
// bmwGearbox.gear = 7  // Outside the object, I CANNOT change the gear! Compiler complains.
bmwGearbox.changeGear(to: 7) // Outside the object, I must use the changeGear function
bmwGearbox.gear // Outside the object, I can read the gear value

Try removing the mutating keyword from the changeGear function. What does the compiler report?

Bonus Code Snip

This was fun. Notice I created a range for the valid gears. It's a private let, so it cannot be accessed from outside this struct.

But also notice how I validated input to functions. I used the ~= operator. This is the contains operator for ranges.

private let validGears = 1...10  // range from 1 to 10
if validGears ~= withInitalGear { print("\(withInitalGear) is a valid gear.") }

3      

public means methods and code outside of this struct can call this function. functions are public by default.

Not to be that guy, but...

The default access level (with a few edge case exceptions) is actually internal. In simpler projects this is pretty much the same as public, but in larger projects with multiple modules or targets, there are some important differences.

See Default Access Levels for more details.

3      

I've been corrected by that guy. Don't pay attention to what I said about functions being public by default. Probably my definition of public is also technically wrong, and only passably good enough to share with this small group of learners. Also, I don't know what I'm talking about 90% of the time. Which is about half the time.

I have corrected the text. Will review it again, and delete it in total, if still inadequate.

3      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

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.