C# Odds, Part II: More about Access Modifiers

In my previous post I argued about the behavior of the protected keyword in C# being counter-intuitive. Some people commented on my post (to whom I thank for the participation), with several kind of reactions: there were suggestions to just change the field to public, to make a getter/setter method (property in C#), to go back to university and stay awake in OOP classes (*sigh*), and to use a real language instead of a Microsoft one (eheh). I’ll try to answer to all of those comments here, because I believe that understanding the languages we work with is important to develop correct and sophisticated programs using the Object Oriented paradigm (and not just write C with Classes).

To clarify further the issue, let’s just call stuff by their name: the concept we are discussion is called Access Modifiers. Access Modifiers are also used in C++, Java, Smalltalk and several other OO (arguably more or less) languages. Access Modifiers exist to aid the process of Information Hiding which is part of the Encapsulation strategy used in OO (or separation of concerns). Some argue that Encapsulation and Data Hiding are the same. Personally (and several other people including some from the Python and Java community) I tend to disagree. But the important concepts to stick around can be summed up by the following quote from wikipedia:

“In computer science, the principle of information hiding is the hiding of design decisions in a computer program that are most likely to change, thus protecting other parts of the program from change if the design decision is changed. The protection involves providing a stable interface which shields the remainder of the program from the implementation (the details that are most likely to change). In modern programming languages, the principle of information hiding manifests itself in a number of ways, including encapsulation (given the separation of concerns) and polymorphism.”

You may follow the links for further information, but the main reasoning I’m trying to follow here is that using public everywhere around is bad (I’ve seen this countless times). It can appear to be harmless in simple/academic applications, but when designing a full blown framework that will be used by other people, don’t ever underestimate the capacity of users to screw up things (including yourself after you decide to reuse a component you’ve done 1 month ago and don’t remember that, while that field is public, YOU SHOULDN’T TOUCH IT!!).

That said, lets look at the definition given by Microsoft to their Access Modifiers:

  • public: The type or member can be accessed by any other code in the same assembly or another assembly that references it.
  • private: The type or member can only be accessed by code in the same class or struct.
  • protected: The type or member can only be accessed by code in the same class or struct, or in a derived class.
  • internal: The type or member can be accessed by any code in the same assembly, but not from another assembly.

Still with me? Great. Everyone knows public well enough. Internal is simple to understand too. But if you think private and protected follow the same rational, guess what: you’re wrong. Compare the following code with the one in the last post:

class A {
  private int protectedField;
  public void doStuff(A a) {
    a.protectedField = 3;
  }
}

class Program {
  static void Main(string[] args) {
    A a = new A();
    A aa = new A();
    aa.doStuff(a);
  }
}

It compiles, as it should! Though members doStuff and protectedField are of different instances, they are defined in the same class. Look at the definition of private: “The type or member can only be accessed by code in the same class or struct”. Are you following me? Private basically says: “I don’t care who tries to access this member, as long as it is within the context of the same *class*.”

Now let’s remember the code using protected:

class A {
  protected int protectedField;
}

class B: A {
  public void doStuff(A a) {
    a.protectedField = 3;
  }
}

It fails to compile, though the definition of protected says: “The type or member can only be accessed by code in the same class or struct, or in a derived class.” Can you spot the differences? The text is the same except that it adds “or in a derived class”. Well, B derives from A. So what is the problem? The problem, it seems, has nothing to do with instances being different. The exact error code the compile gives is: “Cannot access protected member ‘A.protectedField’ via a qualifier of type ‘A’; the qualifier must be of type ‘B’ (or derived from it)”. So in order for the member doStuff to have access to the protected field, a should be typed as B, despite the fact that protectedField is defined in A.

I would personally like to know the person who thinks this is intuitive (and sorry, but I will not even discuss why not just simply cast A to B).

To finalize, I just want to point out that these posts are called C# for a reason: this behavior does not emerge in Java :-) For example, the following code compiles and runs perfectly in JRE6:

public class A {
  protected int protectedField;
}

public class B extends A {
  public void doStuff(A a) {
    a.protectedField = 3;
  }
}

Tags: , ,

3 Responses to “C# Odds, Part II: More about Access Modifiers”

  1. Just a point:
    In Java access modifier “Protected” is equivalente to C# “Internal” not C# “Protected”

  2. > Just a point:
    > In Java access modifier “Protected” is equivalente to C# “Internal”
    > not C# “Protected”

    what are you considering to be the equivalent to an “assembly” in the java world?

  3. Bytter says:

    José Formiga is right. The “protected” keyword allows a member of a class to be accessed either by any of its subclasses, or be any class defined in the same “package” (roughly equivalent to assembly).

    Actually, this behavior is not so strange at all in C#, since C++ behaves exactly the same. For example, the following code won’t compile:

    class A {
    protected:
    int protectedField;
    };

    class B: A {
    public:
    void setValue(A a);
    };

    void B::setValue(A a) {
    a.protectedField = 3;
    };

    Nonetheless, this is still highly counter-intuitive for me and I’m looking forward to understand the reason behind this design choice.

Leave a Reply