In some languages, we may have to use underscore prefix for properties. Typical usage is to keep the modifiability inside and keep the accessibility outside. If you are not familiar with Swift, the following code may come to mind.

class Foo {
    private var _bar: Int
    var bar: Int { _bar }
}

But this is unnecessary in Swift.

Lower Access Level for Setter

We can give a setter a lower access level than its corresponding getter like below:

class Foo {
    private(set) var bar: Int { _bar }
}

But what about the modifiability is determined by the type? For example, CurrentValueSubject and AnyPublisher in Combine or BehaviorRelay and Observable in RxSwift.

Property Wrapper

Let’s see the official sample code first.

@propertyWrapper
struct TwelveOrLess {
    private var number: Int
    init() { self.number = 0 }
    var wrappedValue: Int {
        get { return number }
        set { number = min(newValue, 12) }
    }
}

struct SmallRectangle {
    @TwelveOrLess var height: Int
    @TwelveOrLess var width: Int
}

And here is a version without @propertyWrapper:

struct SmallRectangle {
    private var _height = TwelveOrLess()
    private var _width = TwelveOrLess()
    var height: Int {
        get { return _height.wrappedValue }
        set { _height.wrappedValue = newValue }
    }
    var width: Int {
        get { return _width.wrappedValue }
        set { _width.wrappedValue = newValue }
    }
}

I thought this is just an image for us to understand the property wrapper until yesterday1.

However, We can actually use the underscore prefix version of our wrapped properties. So using a property wrapper can avoid creating properties with a modifiable type. Here is an example:

@propertyWrapper
struct CurrentValueSubjectWrapper<Element> {
    private let subject: CurrentValueSubject<Element, Never>
    let wrappedValue: AnyPublisher<Element, Never>

    init(_ value: Element) {
        self.subject = CurrentValueSubject(value)
        self.wrappedValue = subject.eraseToAnyPublisher()
    }

    func send(_ input: Element) {
        subject.send(input)
    }
}

Then we can use it like below:

class Thermometer {
    @CurrentValueSubjectWrapper(0)
    var temperature: AnyPublisher<Double, Never>

    func measure() {
        ...
        _temperature.send(newTemperature)
    }
}

We got the the underscore prefix version of the temperature for free.

Conclusion

There may be other purposes to use an underscore prefix, but thanks to Swift syntax, we can avoid using an underscore prefix to keep the modifiability inside and keep the accessibility outside.

References