C# nested classes are like C++ nested classes, not Java inner classes

Date:August 1, 2006 / year-entry #259
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20060801-19/?p=30273
Comments:    24
Summary:When you declare a class inside another class, the inner class still acts like a regular class. The nesting controls access and visibility, but not behavior. In other words, all the rules you learned about regular classes also apply to nested classes. The this keyword in an instance methods of a class (nested or not)...

When you declare a class inside another class, the inner class still acts like a regular class. The nesting controls access and visibility, but not behavior. In other words, all the rules you learned about regular classes also apply to nested classes.

The this keyword in an instance methods of a class (nested or not) can be used to access members of that class and only those members. It cannot be used to access members of other classes, at least not directly. (And the this can be omitted when it would not result in ambiguity.) You create an instance of a class (nested or not) by saying new ClassName(...) where ... are the parameters to an applicable class constructor.

Java nested classes behave the same way, but Java also has the concept of inner classes. To construct an instance of an inner class in Java, you write new o.InnerClass(...) where ... as before are the parameters to an applicable class constructor. The o in front is an expression that evaluates to an object whose type is that of the outer class. The inner class can then use the this keyword to access its own members as well as those of the instance of the outer class to which it was bound.

In C++ and C#, you will have to implement this effect manually. It's not hard, though:

// Java
class OuterClass {
 string s;
 // ...
 class InnerClass {

  public InnerClass() { }
  public string GetOuterString() { return s; }
 }
 void SomeFunction() {
  InnerClass i = new this.InnerClass();
  i.GetOuterString();
 }
}
// C#
class OuterClass {
 string s;
 // ...
 class InnerClass {
  OuterClass o_;
  public InnerClass(OuterClass o) { o_ = o; }
  public string GetOuterString() { return o_.s; }
 }
 void SomeFunction() {
  InnerClass i = new InnerClass(this);
  i.GetOuterString();
 }
}

In Java, the inner class has a secret this$0 member which remembers the instance of the outer class to which it was bound. Creating an instance of an inner class via the new o.InnerClass(...) notation is treated as if you had written new InnerClass(o, ...), where o is automatically assigned to the secret this$0 member, and attempts to access members of the outer class are automatically treated as if they were written this$0.outermember. (This description of how inner classes are implemented is not just conceptual. It is spelled out in the language specification.)

The C# equivalent to this code merely makes explicit the transformation that in Java was implicit. We give the inner class a reference to the outer class (here, we called it o_) and pass it as an explicit parameter to the inner class's constructor. And when we want to access a member of that outer class, we use o_ to do it.

In other words, Java inner classes are syntactic sugar that is not available to C#. In C#, you have to do it manually.

If you want, you can create your own sugar:

class OuterClass {
 ...
 InnerClass NewInnerClass() {
  return new InnerClass(this);
 }
 void SomeFunction() {
  InnerClass i = this.NewInnerClass();
  i.GetOuterString();
 }
}

Where you would want to write in Java new o.InnerClass(...) you can write in C# either o.NewInnerClass(...) or new InnerClass(o, ...). Yes, it's just a bunch of moving the word new around. Like I said, it's just sugar.

Now, I'm not saying that the Java way of representing inner classes isn't useful. It's a very nice piece of sugar if you access the outer class's members frequently from the inner class. However, it's not the type of transformation that makes you say, "Well, if a language doesn't support this, it's too hard for me to implement it manually, so I'll just give up." The conversion is not that complicated and consists entirely of local changes that can be performed without requiring a lot of thought.

As a postscript, my colleague Eric Lippert points out that JScript.NET does have instance-bound inner classes.

class Outer {
 var s;
 class Inner {
  function GetOuterString() {
   return s;
  }
 }
}

var o = new Outer();
o.s = "hi";
var i = new o.Inner();
i.GetOuterString();

Comments (24)
  1. Anonymous coward says:

    This is cruel.

    Most java evangelists tell to their believers that C# has too much syntactic sugar. :D.

  2. Phill says:

    IIRC Java actually supports both types. If you declare your inner class with the static keyword then it will not have any access to the outer class. This saves the implicit reference being added by the compiler.

    Inner classes were a necessity in Java due to the event model, your inner class could implement IFocusListener (or whatever) and access the private members of the outer class to perform some action on the event.

  3. Michiel Salters says:

    Tom’s technically right. Inner classes were accidentily left out of the list of members that could access the (outer) classes private parts.

    I’m not sure any compiler actually enforced that rule, and e.g. VC2005 certainly doesn’t. So in practice this restriction doesn’t matter.

  4. KJK::Hyperion says:

    "In C++, your friends can see your privates"

  5. The (bizarre) Java syntax for instantiating an inner class is actually:

    this.new InnerClass();

  6. lf says:

    The Java syntax is sligthly off, it’s "object.new InnerClass()".

    In 98% of cases the object is ‘this’, and you can just use "new InnerClass()".

  7. JavaSharp says:

    I suspect the reason this is in Java and not in C# is because C# has delegates, whereas Java must rely on inner classes (specifially, "anonymous inner classes").

  8. Brian Vargas says:

    I agree with JavaSharp’s statement.  The primary reason that inner classes are useful in Java is the lack of delegates.

    Also, it’s interesting to note the awful syntax when you want to do an explicit reference from an inner class method to a containing class member:

    Outerclass.this.s = "foo";

    Ugh.

    However, it can be necessary when the inner class has a member with the same name as the outer class, and one needs to access the outer class method from the inner class.

  9. Anonymous coward says:

    But are not delegates just syntactic sugar?

    http://java.sun.com/docs/white/delegates.html

    “We believe bound method references are unnecessary because another design alternative, inner classes, provides equal or superior functionality…”
    “We believe bound method references are harmful because they detract from the simplicity of the Java programming language….”

    [In a sense, everything beyond “if” and “goto” is syntactic sugar. If you prefer your code unsweetened, nobody’s forcing you to add sugar. -Raymond]
  10. Smartass says:

    AC: Yes, but it’s not the type of transformation that makes you say, "Well, if a language doesn’t support this, it’s too hard for me to implement it manually, so I’ll just give up."

    :-)

  11. Tom says:

    I’m glad to see that the inner C# class has access to the outer class’s private members.  The current C++ standard does not allow that type of access without a friend declaration.  If memory serves, Pete Becker in a recent issue of Dr. Dobb’s Journal (I miss you CUJ! *sniff* ) made mention that the latest C++ draft standard will allow for C#-like access semantics.  [Note: After searching hard for verification on the C++ Committe Website, I have been unable to corroborate my own statement; it may, in fact, be totally wrong!]

  12. "Java inner classes are syntactic sugar"

    True: in the exact same way that non-virtual instance methods are syntactic sugar over static methods ;-)

  13. NoDotNet says:

    "Not actually a .Net blog"

  14. Dean Harding says:

    But are not delegates just syntactic sugar?

    >

    > http://java.sun.com/docs/white/delegates.html

    They just don’t like delegates because they’re not "object-oriented" enough for Java. They seem to think this idea of "everything is an object" adds to the "simplicity" of Java. I love this essay:

    http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html

  15. silkio says:

    lack of delegates aren’t the reason for inner classes in java.

    inner classes are useful for hashmap nodes, enumerators, and any other object who’s existence is based in the life of the parent object.

  16. steven says:

    any particular reason you chose to refer to third party spec instead of official Sun’s spec?

    [That was the first spec I found. -Raymond]
  17. andy says:

    You’ve got a bad google-fu (http://ask.metafilter.com/mefi/21557), Raymond :P

    First hit for this search: http://www.google.no/search?q=java+language+specification

    .. is http://java.sun.com/docs/books/jls/ :)

    Similar with MSN Search, btw.

    [Well, yeah, but I wasn’t searching for the java language specification. I was looking for pages that talked about java inner classes. -Raymond]
  18. Darren Winsper says:

    Is there a reason the Java-like behaviour wasn’t adopted?  After
    all, Java does support both methods, it wouldn’t have been hard for C#
    to do the same thing.

    [Minus 100 points. -Raymond]
  19. Norman Diamond says:

    [Minus 100 points. -Raymond]

    Perhaps Mr. Winsper will be reassured to know that Mr. Chen wasn’t rating Mr. Winsper’s posting ^_^  The link points to the minus 100 points posting that really explains the answer.

    (The linked posting doesn’t entirely explain if the answer is good or not, which of course is the subject of enough debates itself.  It does explain what this answer is.)

  20. Neil says:

    Why not get rid of the syntactic sugar that allows you to write i.GetOuterString() and write Outer_Inner_GetOuterString(i) instead ;-)

  21. There’s been a lot of debates out there recently about how useful is the method reference (or function pointer) in programming or scripting languages such as JavaScript, C# and J++. It looks like Java turns out to be the loser in this debate because it

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index