views:

309

answers:

4

While cleaning some code today written by someone else, I changed the access modifier from Public to Private on a class variable/member/field. I expected a long list of compiler errors that I use to "refactor/rework/review" the code that used this variable. Imagine my surprise when I didn't get any errors. After reviewing, it turns out that another instance of the Class can access the private members of another instance declared within the Class. Totally unexcepted.

Is this normal? I been coding in .NET since the beginning and never ran into this issue, nor read about it. I may have stumbled onto it before, but only "vaguely noticed" and move on. Can anyone explain this behavoir to me? I would like to know the "why" I can do this. Please explain, don't just tell me the rule. Am I doing something wrong? I found this behavior in both C# and VB.NET. The code seems to take advantage of the ability to access private variables. The disadvantage is the programmer created a big plate of Spaghetti.

Sincerely,

  • Totally Confused

Class Jack
    Private _int As Integer
End Class
Class Foo
    Public Property Value() As Integer
        Get
            Return _int
        End Get
        Set(ByVal value As Integer)
            _int = value * 2
        End Set
    End Property
    Private _int As Integer
    Private _foo As Foo
    Private _jack As Jack
    Private _fred As Fred
    Public Sub SetPrivate()
        _foo = New Foo
        _foo.Value = 4  'what you would expect to do because _int is private
        _foo._int = 3   'TOTALLY UNEXPECTED
        _jack = New Jack
        '_jack._int = 3 'expected compile error 
        _fred = New Fred
        '_fred._int = 3 'expected compile error 
    End Sub
    Private Class Fred
        Private _int As Integer
    End Class
End Class
+12  A: 

This is "normal". Private members are private to the class, not to the particular instance.

Paul Baker
But, I am accessing a private member of the Class from two different instances of the Class.
AMissico
As he said, "Not to the particular instance"
Oskar Kjellin
@AMissico: That's what I mean: private prevents access from outside the class. Access is always permitted from within the class - to all instances.
Paul Baker
@Paul Baker: Please provide a reference. Where is the documentation? I cannot believe that I can access your Private _heart As Heart just because we are two instances of the same Human Class. This could be true, but I need the reference.
AMissico
How's this (for C#)? "private - Access is limited to the containing type." [ http://msdn.microsoft.com/en-us/library/ba0a1yw2%28VS.80%29.aspx ] Note that this makes no mention of instances of the type.
Paul Baker
The reference: "Private members are accessible only within the body of the class or the struct in which they are declared": http://msdn.microsoft.com/en-us/library/st6sy9xe.aspx
overslacked
Accessibility Domain at http://msdn.microsoft.com/en-us/library/zd74a9ww.aspx. Mentions that a Top-Level class cannot access private members of a nested class. A nested class can access the private members of its top-level class. It seems that a top-level class is "nested" within itself. I wonder is this is a compiler issue.
AMissico
I do not believe the references provided explain this issue. It seems only to explain the "expected compiler errors" in my question.
AMissico
Doesn't your confusion relate only to your class `Foo` and its `_int` and `_foo` members? Then I fail to see how nested classes are relevant.
Paul Baker
Hm, you are saying that private is not private between instances because the member "describes" the class? So how do I keep instances from corrupting each other? What stops an instance from going around my defined Property to access the private variable that holds the Property's value?
AMissico
@AMissco - "how do I keep instances from corrupting each other?"... well you're writing the class, just don't write code that corrupts other instances! There are many cases in which you need to access another instance's fields (equality comparisons, for example). The case you should be more interested in is with `protected` members, which have more complex rules, described here: http://blogs.msdn.com/ericlippert/archive/2005/11/09/why-can-t-i-access-a-protected-member-from-a-derived-class.aspx
Greg Beech
@Greg Beech: There is nothing "complex" about what that entry discusses. Typical inheritance and access rules.
AMissico
@Greg Beech: I have no control over other programmers code or their implementations. If I mark a member as private I do not believe that another instance should have access to it.
AMissico
@Greg Beech: Regarding equality comparisions, maybe that is where I noticed this behavior before.
AMissico
If I haven't noticed this behavior in all my years, I must be very disciplined or this does not come up much. I cringed as I accepted this answer. :O)
AMissico
@AMissico - "I have no control over other programmers code or their implementations" - but surely if you're writing the class, and the fields are private, then it doesn't matter what other programmers do? It's all down to you as the author. Unless you're saying you don't trust the people you work with who might also edit the class not to get it wrong? That's what code reviews and tests are for -- to make sure you have got it right!
Greg Beech
@Greg Beech: You make too many assumptions. The Class I am working on now, was written by at least 4 people. There are over 4000 lines of code. I have tried for over a week to make changes, but had to roll back code 4 times. I am now beginning to understand what is happening. They implemented a "queue" within the class. One instance of his "class" is making changes to other instances in the queue. The instance that is currently "first", is making these changes. Who is "first" is determined by other instances. An absolute mess. Today for instance, I moved one line of code and broke the class.
AMissico
@Greg Beech: "you don't trust...not to get it wrong." No, I am saying that private is private. If I have an instance of a Class within itself, then that instance should absolutely not have access to private "state" information of another instance. It has nothing to do with trust. In my opinion, an instance having access to the private members of other instances within itself completely violates "information hiding" (encapsulation). If this wasn't important then two instances of the same class would not be limited to "public" members.
AMissico
@Greg Beech: There are no code reviews.
AMissico
A: 

This is expected behavior. Nested classes can access private members of the container class.

Pierreten
Fred is the nested Class and has access, which is expected and the behavior I am aware of. Foo is not nested and can access another Foo's private implementation.
AMissico
+4  A: 

You said:

Please explain, don't just tell me the rule.

Well, here's my two cents.

As I see it, the premise of private members of a class is that a class may internally be aware of its own implementation without exposing that implementation to the outside world. Thus one instance of a class is perfectly capable of understanding the way another instance of the same class is implemented; so it is not restricted from taking advantage of that implementation knowledge.

As for instances manipulating each other, I will concede this is somewhat unusual. But take for example static construction methods. Would you also restrict these from accessing instances' private members? If so, you've rendered a lot of useful code impossible. If not, it's unclear why static methods should be able to access private members but instance methods shouldn't.

In other words, the word "private" in OOP is not meant to convey the idea of personal privacy, as in individuals hiding from one another. Rather, think of a class as more of a "members only" sort of club, where there are certain ways of doing things that only members of the club know about.

Dan Tao
@Dan Tao: Thank you. As I mentioned in a comment, I rarely have run across this use. Do you know of any documentation that describes why this behavior exists? (Static is a little different because I can still access static outside of the class.)
AMissico
A: 

The issue of access is about where the code is accessing the private members and not so much about what it is accessing them through.

You have access to the _foo._int field in the definition of the Foo class, but not outside of it.

It may surprise you further that the following extension to the nested Fred class is also legal.

Private Class Fred
    Private _int As Integer
    Private Sub Blah(ByVal foo As Foo)
        foo._int = 9
    End Sub
End Class
Enigmativity
After my initial surprise, I tested this to verify what I found. So I was already surprised. :O)
AMissico