Swift Magic: Public Getter, Private Setter

In my blog post on Constructor Injection, I had an example of a struct with a property that needed to be read externally but written only internally. I initially wrote the code like this:

I was not happy with this, but that’s the only way I could think of for making it do what I needed to do. Luckily, there is a better way!

@mipstian pointed out that I can choose to make only the setter private in Swift! Like this:

In my case, I’m ok with Counter being “public” to my module (aka internal). However, if you are building an SDK, you can make it make the getter public while keeping the setter private like this:

Not sure how I missed it (I think that’s because I tend to use let as much as possible 😇), but I’m glad to find this amazingly elegant feature of Swift I didn’t even know about!

Enjoy the article? Join over 20,000+ Swift developers and enthusiasts who get my weekly updates.

  • Awesome!

  • Bionik6

    Neat, really neat. That’s why I love the Swift language. I was exactly using the syntax of your first example but now I’ll use the private(set) syntax for upcoming projects.
    Thank you for sharing Natasha 🙂

  • Joshua Kaden

    How funny; I just discovered the same feature last night!

  • Vince O’Sullivan

    This simple construct is very welcome news. I had previously used a public and a private variable to achieve this but having it built into the language is much more succinct.

    • Nuno

      Dido 🙂

  • Drew Cover

    Yeah. It is nice that it is available.

    I find it a little irritating private(set) is allowed but not public(get) which is more readable to me. “public let” and “private(set) var” are functionally equivalent (ignoring module/package differences) and often sit together in my code. It is annoying that they look opposite. (Yes, I understand why it is this way, cuz Module Accessibility is default-I think file accessibility/private should be default, and modifiers should be required to make it more public. )

    • Jason Frost

      ‘public let’ and ‘private(set) var’ are not equivalent at all, a ‘public let’ can’t be changed after it’s been set, even by the object it belongs to.

      • Drew Cover

        If you are using ‘public’ and ‘private’ you are thinking from a client’s point of view. From the client’s point of view, ‘public let’ and ‘private(set) var’ are equivalent (again, ignoring module vs package).

        I am curious about why you decided to write this comment. Are you are trying to make a deeper point about the meaning of the word “equivalent”? If so, I stand by my original comment. In the context of a discussion of separate set and get accessibilities, “In both cases, clients can get it but not set it,” precisely abbreviates to “functionally equivalent”.

        • Cristik

          @drewcover:disqus, Jason has a valid point, as we’re not discussing here only about accessibility modifiers, we’re also taking in consideration the writability of the property, i.e. let vs. var.

          Technically speaking, you cannot write public/private let a: Int?, nor public/private let a: Int!, but you can do both with a var. The let/var modifiers take the accessibility ones to another level than the classical one.

        • Because there are enough incorrect/confusing information on the internet, especially for beginners!

  • Jason Thompson

    C# has had this feature for a long time.. it’s a real time saver! Thanks for sharing the swift equivalent.

  • Reed Harston

    Awesome! This is exactly what I was looking for, thank you!

  • Chlebta kaouach

    What If I want to do the opposite private getter and public setter ?

    • John Whitley

      public var thing: AType { set { self._thing = newValue } }
      private var _thing: AType

      This pattern is particuarly useful where you want a public var that acts as both getter and a rich-setter. E.g. var position: CGPoint, where the getter is normal, but the setter clamps CGPoint (say, from a touch) inside the valid region of a custom control.

  • Chitranshu Asthana

    I think it is worth mentioning that there is also “internal(set)” which comes in very handy while creating SDK. This makes the property writable from within the SDK. Used in combination with “public” will make it readonly from outside but read/write within sdk.

  • Saurabh Bajaj

    This is exactly what I was looking for. Thanks for this post.