2

While reading the docs on apex properties I noticed that you can use access modifiers on class instance property getters / setters. While playing around with private setters and running a few examples in anonymous apex, I noticed some confusing behavior:

public class Person {
  public Person() {
    this.name = '';
  }

  public String name { get; private set; }
}

Person peter = new Person();
peter.name = 'Peter'; // I expected this to throw a private property error
System.debug(peter.name); // Outputs 'Peter' to the console

The instance variable name has a public getter and a private setter. I expected this property to be accessible when referenced by client code (e.g. new Person().name) but to throw some type of method access control error when the client attempts to set its value (e.g. new Person().name = 'Ricky').

In the example above, even though the name setter is private, the name property of the peter object is still being modified via the setter, bypassing the private access modifier.

Am I missing something here? Why can I set the name property even though it has a private setter?

1 Answer 1

5

A private attribute is accessible anywhere in the top-level class.

Consider this class:

public class Messenger {
  public class Message {
    public String data { get; private set; }
  }
  public static Message createMessage(String inputValue) {
    Message result = new Message();
    result.data = inputValue;
    return result;
  }
  public static void readMessage(Message incoming) {
    System.debug(incoming.data);
  }
}

Now, if you run some code in Execute Anonymous, you'll see how it works:

Messenger.Message temp = Messenger.createMessage('Hello World');
// This next line won't compile, comment out to run code
temp.data = 'Goodbye World';
Messenger.readMessage(temp);

This does not work in Execute Anonymous, because that feature actually wraps your code in an anonymous top-level class. It's for this reason you can't have nested classes inside Execute Anonymous, why your private setter doesn't cause a compilation error, and other weird quirks you may encounter compared to normal Apex rules.

Let's take your code, and imagine how Salesforce sees your code during Execute Anonymous:

public class ExecuteAnonymousWrapper {
  public class Person {
    public Person() {
      this.name = '';
    }
    public String name { get; private set; }
  }
  static {
    Person peter = new Person();
    peter.name = 'Peter'; // I expected this to throw a private property error
    System.debug(peter.name); // Outputs 'Peter' to the console
  }
}

Note that this isn't a literal translation, as I don't know how it works internally, but I am familiar many of the quirks of Apex in general, and Execute Anonymous is probably the strangest of the bunch, including triggers, which are also a weird hybrid between Execute Anonymous and normal Apex classes.

3
  • Thank you so much! This makes so much more sense now. It's good to know that there's a wrapper class surrounding my anonymous code, I had never considered that. I appreciate the quick response too! Oct 21, 2022 at 20:44
  • 1
    My suspicion on the anonymous block mapping to a temporary class is similar, though I suspect executable code is simply dropped into a static block.
    – Phil W
    Oct 22, 2022 at 6:12
  • @PhilW You're likely correct, as this is not accessible in Execute Anonymous code that's not in a class, though it's more academic than anything someone seriously needs to think about when writing Execute Anonymous code. But I'll edit that in anyways, it's more technically correct.
    – sfdcfox
    Oct 22, 2022 at 6:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .