157

In C# (and many other languages) it's perfectly legitimate to access private fields of other instances of the same type. For example:

public class Foo
{
    private bool aBool;

    public void DoBar(Foo anotherFoo)
    {
        if (anotherFoo.aBool) ...
    }
}

As the C# specification (sections 3.5.1, 3.5.2) states access to private fields is on a type, not an instance. I've been discussing this with a colleague and we're trying to come up with a reason why it works like this (rather than restricting access to the same instance).

The best argument we could come up with is for equality checks where the class may want to access private fields to determine equality with another instance. Are there any other reasons? Or some golden reason that absolutely means it must work like this or something would be completely impossible?

AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
RichK
  • 11,318
  • 6
  • 35
  • 49
  • 18
    What are the benefits for the alternative? – Jon Skeet Aug 08 '11 at 14:25
  • 19
    It is true that it doesn't model the real world very well. After all, just because my car can report how much gas it has left doesn't mean that my car should be able to tell how much gas EVERY car has left. So, yes, I can theoretically see having a "private instance" access. I feel like I would really never use it though because I would be worried that in 99% of the cases, I really WOULD want to have another instance access that variable. – aquinas Aug 08 '11 at 14:33
  • 3
    @Jon The position that was taken for the so called 'benefits' is that classes shouldn't know the internal state of another instance - regardless of the fact that it's the same type. Not a benefit per say, but there's probably a pretty good reason to choose one over the other and that's what we've been trying to figure out – RichK Aug 08 '11 at 14:54
  • 5
    You can always make the variable into a pair of getter/setter closures, initialised in the constructor, which will fail if _this_ isn't the same as it was during the initialisation ... – Martin Sojka Aug 08 '11 at 16:13
  • Fairly certain a question about instance-locals has been asked before, but I can't find it. This one's related, however: http://programmers.stackexchange.com/questions/82047/function-locals-variable-used-in-just-one-function – Jon Purdy Aug 09 '11 at 02:15
  • 10
    Scala provides *instance private* members -- along with many other access levels not found in Java, C# and many other languages. This is a perfectly legitmate question. – Bruno Reis Aug 12 '11 at 09:13
  • 1
    @RichK: The question is whether an object should know that another object is "really" the same type. If `Foo` objects access the internals of other `Foo` object, then every object which is substitutable for `Foo` must have those same internals. By contrast, if a `Foo` object never accesses the internals of another `Foo`, one could split `Foo` into an abstract base class (which is used for everything except constructor calls that are made by a factory within that class), and a concrete instance type, and implementations of the base class could have whatever internals they wanted. – supercat Dec 17 '12 at 02:06
  • 1
    I think what @JonSkeet is getting at is that, access modifiers have to do with `Public API` of a class. Since I have written MY class, I know all times that it should be able to access other instances. The fact that my class can see other instances private members is irrelevant to the Public API. If you want your private members to be invisible to other instances of the class it's easy, very easy. You just don't ever do it in the class. – Cruncher Feb 14 '14 at 14:56
  • See also [Why and how does C# allow accessing private variables outside the class itself when it's within the same containing class?](http://stackoverflow.com/questions/5737602/) ... and additionally [Why can private member variable be changed by class instance?](http://stackoverflow.com/questions/4244818/) – Jeppe Stig Nielsen Jan 28 '15 at 10:34

10 Answers10

75

I think one reason it works this way is because access modifiers work at compile time. As such, determining whether or not a given object is also the current object isn't easy to do. For example, consider this code:

public class Foo
{
    private int bar;

    public void Baz(Foo other)
    {
        other.bar = 2;
    }

    public void Boo()
    {
        Baz(this);
    }
}

Can the compiler necessarily figure out that other is actually this? Not in all cases. One could argue that this just shouldn't compile then, but that means we have a code path where a private instance member of the correct instance isn't accessible, which I think is even worse.

Only requiring type-level rather than object-level visibility ensures that the problem is tractable, as well as making a situation that seems like it should work actually work.

EDIT: Danilel Hilgarth's point that this reasoning is backwards does have merit. Language designers can create the language they want, and compiler writers must conform to it. That being said, language designers do have some incentive to make it easier for compiler writers to do their job. (Though in this case, it's easy enough to argue that private members could then only be accessed via this (either implicitly or explicitly)).

However, I believe that makes the issue more confusing than it needs to be. Most users (myself included) would find it unneccessarily limiting if the above code didn't work: after all, that's my data I'm trying to access! Why should I have to go through this?

In short, I think I may have overstated the case for it being "difficult" for the compiler. What I really meant to get across is that above situation seems like one that the designers would like to have work.

dlev
  • 48,024
  • 5
  • 125
  • 132
  • 35
    IMHO, this reasoning is the wrong way around. The compiler enforces the rules of the language. It does not MAKE them. In other words, if private members were "instance private" and not "type private", the compiler would have been implemented in other ways, e.g. only allowing `this.bar = 2` but not `other.bar = 2`, because `other` could be a different instance. – Daniel Hilgarth Aug 08 '11 at 15:46
  • @Daniel That's a good point, but as I mentioned, I think having that restriction would be worse than having class-level visibility. – dlev Aug 08 '11 at 15:49
  • 4
    @dlev: I didn't say anything about whether or not I think "instance private" members are a good thing. :-) I just wanted to point out, that you are arguing that a technical implementation dictates the rules of the language and that in my opinion, this argumentation is not correct. – Daniel Hilgarth Aug 08 '11 at 15:53
  • 2
    @Daniel Point taken. I still think this is a valid consideration, though you're of course correct that ultimately the language designers figure out what they want, and compiler writers conform to that. – dlev Aug 08 '11 at 15:55
  • In the line in question, "other.bar = 2;". If you want to do something like this then shouldn't bar be internal and not private? – MikeKulls Aug 10 '11 at 06:21
  • @MikeKulls, no, that's exactly the point of my question, it doesn't need to be. – RichK Aug 10 '11 at 09:01
  • 1
    "after all, that's my data I'm trying to access! Why should I have to go through `this`" You could think of it like accepting any old IEnumerable, passing in a LinkedList, and trying to call `.RemoveFirst()` on it without casting. – Rag Aug 10 '11 at 13:37
  • 3
    I don't think the compiler-argument holds. There are languages around that allow instance-private only (like Ruby) and that allow instance-private and class-private by choice (like Eiffel). Compiler generation wasn't necessary harder or easier for these languages. For more info, see also my answer down the thread. – Abel Aug 11 '11 at 15:01
  • Another reason, how would you implement linked list structures who access times didn't grow exponentially with private fields if private meant instance private? – iheanyi Feb 14 '14 at 20:00
  • Eric Lippert has described some c# language design decisions as being guided by "too hard / too complicated" to justify dealing with for the time being, and simpler approaches being good enough. So whole that may or may not be the case in this specific situation, it is a valid reason in general. – Rex M Aug 31 '17 at 15:56
61

Because the purpose of the kind of encapsulation used in C# and similar languages* is to lower mutual dependence of different pieces of code (classes in C# and Java), not different objects in memory.

For example, if you write code in one class that uses some fields in another class, then these classes are very tightly coupled. However, if you are dealing with code in which you have two objects of the same class, then there is no extra dependency. A class always depends on itself.

However, all this theory about encapsulation fails as soon as someone creates properties (or get/set pairs in Java) and exposes all the fields directly, which makes classes as coupled as if they were accessing fields anyway.

*For clarification on kinds of encapsulation see Abel's excellent answer.

Goran Jovic
  • 9,418
  • 3
  • 43
  • 75
  • 4
    I don't think it fails once `get/set` methods are provided. Accessor methods still maintain an abstraction (the user doesn't need to know there's a field behind it, or what field(s) may be behind the property). For example, if we're writing a `Complex` class, we can expose properties to get/set the polar coordinates, and another get/set for Cartesian coordinates. Which one the class uses underneath is unknown to the user (it could even be something entirely different). – Ken Wayne VanderLinde Aug 08 '11 at 14:49
  • 5
    @Ken: It does fail if you provide a property for every single field you have without even considering if it should be exposed. – Goran Jovic Aug 08 '11 at 15:33
  • @Goran Although I agree that wouldn't be ideal, it still doesn't fail completely as the get/set accessors allow you to add additional logic if the underlying fields change for example. – ForbesLindesay Aug 10 '11 at 10:50
  • 2
    _"Because the purpose of encapsulation is to lower mutual dependence of different pieces of code"_ >> no. Encapsulation can also mean instance-encapsulation, it depends on the language or school-of-thought. One of the most definitive voices on OO, Bertrand Meyer, considers this even the default for `private`. You may check my answer for my view on things if you like ;). – Abel Aug 11 '11 at 15:04
  • @Abel: I based my answer on languages with class encapsulation because OP asked about one of them, and frankly because I know them. Thanks for the correction and for new interesting info! – Goran Jovic Aug 11 '11 at 15:41
  • If instances of type `Foo` are allowed to access private members of other instances, that creates a dependency that any object which expects a `Foo` will require an object with those internals, even though it doesn't actually care about them. If one creates instances of `Foo` using something like `Foo.Create()` rather than `new Foo()`, then `Foo` doesn't have to have *any* internals; the thing that's created could be a `ConcreteFoo` which derives from `Foo` but wouldn't necessarily be the only class that could do so. – supercat Dec 17 '12 at 02:09
51

Quite some answers have already been added to this interesting thread, however, I didn't quite find the real reason for why this behavior is the way it is. Let me give it a try:

Back in the days

Somewhere between Smalltalk in the 80's and Java in the mid 90's the concept of object-orientation matured. Information hiding, not originally thought of as a concept only available to OO (mentioned first in 1978), was introduced in Smalltalk as all data (fields) of a class is private, all methods are public. During the many new developments of OO in the 90's, Bertrand Meyer tried to formalize much of the OO concepts in his landmark book Object Oriented Software Construction (OOSC) which has since then be considered an (almost) definitive reference on OO concepts and language design.

In the case of private visibility

According to Meyer a method should be made available to a defined set of classes (page 192-193). This gives obviously a very high granularity of information hiding, the following feature is available to classA and classB and all their descendants:

feature {classA, classB}
   methodName

In the case of private he says the following: without explicitly declaring a type as visible to its own class, you cannot access that feature (method/field) in a qualified call. I.e. if x is a variable, x.doSomething() is not allowed. Unqualified access is allowed, of course, inside the class itself.

In other words: to allow access by an instance of the same class, you have to allow the method access by that class explicitly. This is sometimes called instance-private versus class-private.

Instance-private in programming languages

I know of at least two languages currently in use that use instance-private information hiding as opposed to class-private information hiding. One is Eiffel, a language designed by Meyer, that takes OO to its utmost extremes. The other being Ruby, a far more common language nowadays. In Ruby, private means: "private to this instance".

Choices for language design

It has been suggested that allowing instance-private would be hard for the compiler. I don't think so, as it is relatively simple to just allow or disallow qualified calls to methods. If for a private method, doSomething() is allowed and x.doSomething() is not, a language designer has effectively defined instance-only accessibility for private methods and fields.

From a technical point of view, there's no reason to choose one way or the other (esp. when considering that Eiffel.NET can do this with IL, even with multiple inheritance, there's no inherent reason not to provide this feature).

Of course, it's a matter of taste and as others already mentioned, quite some methods might be harder to write without the feature of class-level visibility of private methods and fields.

Why C# allows only class encapsulation and not instance encapsulation

If you look at internet threads on instance encapsulation (a term sometimes used to refer to the fact that a language defines the access modifiers on instance level, as opposed to class level), the concept is often frowned upon. However, considering that some modern languages use instance encapsulation, at least for the private access modifier, makes you think it can be and is of use in the modern programming world.

However, C# has admittedly looked hardest at C++ and Java for its language design. While Eiffel and Modula-3 were also in the picture, considering the many features of Eiffel missing (multiple inheritance) I believe they chose the same route as Java and C++ when it came to the private access modifier.

If you really want to know the why you should try to get a hold of Eric Lippert, Krzysztof Cwalina, Anders Hejlsberg or anyone else who worked on the standard of C#. Unfortunately, I couldn't find a definitive note in the annotated The C# Programming Language.

Abel
  • 56,041
  • 24
  • 146
  • 247
  • 2
    That's a lovely answer with a lot of background, very interesting, thanks for taking the time to respond to a (relatively) old question – RichK Aug 10 '11 at 16:41
  • 2
    @RichK: you're welcome, just caught the question too late I guess, but found the topic intriguing enough to respond with some depth :) – Abel Aug 10 '11 at 17:37
  • 1
    Under COM, "private" meant "instance-private". I think this was in some measure because a definition of class `Foo` effectively represented an interface and an implementing class; since COM didn't have a concept of a class-object reference--just an interface reference--there was no way a class could hold a reference to something that was guaranteed to be another instance of that class. This interface-based design made some things cumbersome, but it meant one could design a class which was substitutable for another without it having to share any of the same internals. – supercat Dec 17 '12 at 02:16
  • 3
    Great answer. OP should consider marking this question the answer. – Gavin Osborn Oct 09 '13 at 00:16
18

This is only my opinion, but pragmatically, I think that if a programmer has access to the source of a class, you can reasonably trust them with accessing the class instance's private members. Why bind a programmers right hand when in their left you've already given them the keys to the kingdom?

FishBasketGordo
  • 22,904
  • 4
  • 58
  • 91
  • 14
    I don't understand this argument. Let's say you are working on a program where *you* are the only developer and you are the only one who would EVER use your libraries, are you saying in that case you make EVERY member public because you have access to the source code? – aquinas Aug 08 '11 at 14:36
  • @aquinas: that's quite different. Making everything public will lead to horrible programming practices. Allowing a type to see private fields of other instances of itself is a very narrow case. – Igby Largeman Aug 08 '11 at 14:41
  • 2
    No, I'm not advocating making every member public. Heavens no! My argument is, if you're already in the source, can see the private members, how they are used, conventions employed, etc., then why not be able to use that knowledge? – FishBasketGordo Aug 08 '11 at 14:44
  • 7
    I think the way of thinking is still in the terms of the type. If the type cannot be trusted to deal with the members of the type properly, what can? (*Normally*, it would be a programmer actually controlling the interactions, but in this age of code-generation tools, that may not always be the case.) – Anthony Pegram Aug 08 '11 at 14:47
  • 3
    My question isn't really of trust, more of necessity. Trust is totally irrelevant when you can use reflection to heinous things to privates. I'm wondering why, conceptually, you can access the privates. I assumed there was a logical reason rather than a best-practices situation. – RichK Aug 08 '11 at 14:50
13

The reason indeed is equality check, comparison, cloning, operator overloading... It would be very tricky to implement operator+ on complex numbers, for example.

Lorenzo Dematté
  • 7,638
  • 3
  • 37
  • 77
  • 4
    But everything that you mention requires one type GETTING the value of another type. I am on board with saying: you want to inspect my private state? Fine, go ahead. You want to *set* my private state? No way, buddy, change your own damn state. :) – aquinas Aug 08 '11 at 16:04
  • 2
    @aquinas It doesn't work that way. Fields are fields. They're only read-only if declared as `readonly` and then that applies to the declaring instance as well. Evidently you're asserting that there should be a specific compiler rule to forbid this, but every such rule is a feature that the C# team has to spec out, document, localize, test, maintain, and support. If there's no compelling *benefit* then why would they do it? – Aaronaught Aug 08 '11 at 23:47
  • I agree with @Aaronaught: there is a cost associated with implementing every new spec and change to the compiler. For a set scenario, consider a Clone method. Sure, you may want to realize it with a private constructor, but maybe in some scenarios it is not possible/advisable. – Lorenzo Dematté Aug 09 '11 at 06:58
  • 2
    C# team? I'm just debating possible theoretical language changes in ANY language. "If there's no compelling benefit..." I think there *may* be a benefit. Just like with *any* compiler guarantee, someone may find it useful to guarantee that a class only modifies its own state. – aquinas Aug 09 '11 at 13:56
  • @aquinas: Features get implemented because they *are* useful to *many* or *most* users - not because they *might* be useful in some isolated cases. – Aaronaught Aug 09 '11 at 22:29
  • 1
    @Aaron "It doesn't work that way. Fields are fields." What are you even talking about? It's trivial to allow reads and to disallow writes. – Rag Aug 10 '11 at 13:31
  • @Brian: Uh, no? Fields don't have get/set modifiers. They're either visible or they aren't. There's no more fine-grained control than that. – Aaronaught Aug 10 '11 at 21:24
9

First of all, what would happen to private static members? Can they only be accessed by static methods? You certainly wouldn't want that, because then you wouldn't be able to access your consts.

As to your explicit question, consider the case of a StringBuilder, which is implemented as a linked list of instances of itself:

public class StringBuilder
{
    private string chunk;
    private StringBuilder nextChunk;
}

If you can't access the private members of other instances of your own class, you have to implement ToString like this:

public override string ToString()
{
    return chunk + nextChunk.ToString();
}

This will work, but it's O(n^2) -- not very efficient. In fact, that probably defeats the whole purpose of having a StringBuilder class in the first place. If you can access the private members of other instances of your own class, you can implement ToString by creating a string of the proper length and then doing an unsafe copy of each chunk to its appropriate place in the string:

public override string ToString()
{
    string ret = string.FastAllocateString(Length);
    StringBuilder next = this;

    unsafe
    {
        fixed (char *dest = ret)
            while (next != null)
            {
                fixed (char *src = next.chunk)
                    string.wstrcpy(dest, src, next.chunk.Length);
                next = next.nextChunk;
            }
    }
    return ret;
}

This implementation is O(n), which makes it very fast, and is only possible if you have access to private members of other instances of your class.

Gabe
  • 84,912
  • 12
  • 139
  • 238
  • Yeah but aren't there other ways around that, such as exposing some fields as internal? – MikeKulls Aug 10 '11 at 06:25
  • 2
    @Mike: Exposing a field as `internal` makes it *less* private! You'd end up exposing the internals of your class to everything in its assembly. – Gabe Aug 10 '11 at 07:05
4

This is perfectly legitimate in many languages (C++ for one). The access modifiers come from the encapsulation principle in OOP. The idea is to restrict access to outside, in this case outside is other classes. Any nested class in C# for example can access it's parents private members also.

While this is a design choice for a language designer. The restriction of this access can complicate some very common scenarios extremely without contributing much to isolation of entities.

There is a similar discussion here

Community
  • 1
  • 1
Mehran
  • 1,977
  • 1
  • 18
  • 33
2

I don't think that there's a reason we couldn't add another level of privacy, where data is private to each instance. In fact, that might even provide a nice feeling of completeness to the language.

But in actual practice, I doubt it would really be that useful. As you pointed out, our usual private-ness it is useful for things such as equality checks, as well as most other operations involving multiple instances of a Type. Although, I also like your point about maintaining data abstraction, as that is an important point in OOP.

I think all around, providing the ability to restrict access in such a way could be a nice feature to add to OOP. Is it really that useful? I'd say no, since a class should be able to trust its own code. Since that class is the only things that can access private members, there's no real reason to need data abstraction when dealing with an instance of another class.

Of course, you can always write your code as if private applied to instances. Use the usual get/set methods to access/change the data. That would probably make the code more manageable if the class may be subject to internal changes.

Ken Wayne VanderLinde
  • 18,915
  • 3
  • 47
  • 72
0

Great answers given above. I would add that part of this problem is the fact that instantiating a class inside itself is even allowed in the first place. It makes since in a recursive logic "for" loop, for example, to use that type of trick as long as you have logic to end the recursion. But instantiating or passing the same class inside itself without creating such loops logically creates its own dangers, even though its a widely accepted programming paradigm. For example, a C# Class can instantiate a copy of itself in its default constructor, but that doesn't break any rules or create causal loops. Why?

BTW....this same problem applies to "protected" members as well. :(

I never accepted that programming paradigm fully because it still comes with a whole suite of issues and risks that most programmers don't fully grasp until issues like this problem rise up and confuse people and defy the whole reason for having private members.

This "weird and wacky" aspect of C# is yet one more reason why good programming has nothing to do with experience and skill, but just knowing the tricks and traps.....like working on a car. Its the argument that rules were meant to be broken, which is a very bad model for any computing language.

Stokely
  • 12,444
  • 2
  • 35
  • 23
-1

It seems to me that if data was private to other instances of the same type, it wouldn't necessarily be the same type anymore. It wouldn't seem to behave or act the same as other instances. Behavior could easily be modified based on that private internal data. That would just spread confusion in my opinion.

Loosely speaking, I personally think that writing classes derived from a base class offers similar functionality you are describing with 'having private data per instance'. Instead, you just have a new class definition per 'unique' type.

C.J.
  • 15,637
  • 9
  • 61
  • 77