Private fields are not that private, after all

Arialdo Martini — 12/09/2020 — C#

The following code is just legit:

class Foo
{
    private string _privateField;
    
    void DoSomething(Foo anotherInstance)
    {
        anotherInstance._privateField = "doh!";
    }
}

Private fields are on types, not on instances. This means that every instance of a class can access any private fields of any other instance of the same class.
This may come as a surprise.

That’s defined in the C# Language Specification: private limits access to the containing type, not to the containing instance.

Why?

One of the possible reasons is because otherwise the compiler would have big issues in figuring out if code such this should be considered valid or not:

class Foo
{
    private string _privateField;
    
    void DoSomething(Foo justTheSameInstance)
    {
        justTheSameInstance._privateField = "doh!";
    }
    
    void CallWithSelf()
    {
        DoSomething(this);
    }
}

One could argue that the code above should be invalid in any case, as the signature of DoSomething takes no enforcement at all on which instance it could receive.

Another argument is that private fields are designed for encapsulation, and for protecting the client of a class from knowing the internals of the implementation

* users are protected from implementation changes breaking their code
* designers are protected from having to keep implementation details features unchanged forever

A class needn’t be protected from itself and from the changes in its own code. In other words, private fields are meant to protect a class source code from other programmers.

Rephrasing this argument, the purpose of the private access modifier is to lower the mutual dependence of different modules of code, rather than different objects in memory.

A last argument could be that access of private fields from other instances makes writing the code for objects equality easier.

Whatever the argument, the visibility of private fields seems to violate the Least Astonishment Principle, to the point that the average C# programmer might perceive the _ right after . in justTheSameInstance._privateField as a possible syntax error, or an abused naming convention.

What about other languages?

Java in on the same boat

class Foo {
    private String foo;
    
    void DoSomething(Main anotherInstance){
        anotherInstance.foo = "doh!";
    }
}

and so is C++.

But not all languages took the same decision: Scala provides instance private fields.