57

I really don't get it.

If the base class is abstract and only intended to be used to provide common functionality to public subclasses defined in the assembly, why shouldn't it be declared internal?

I don't want the abstract class to be visible to code outside the assembly. I don't want external code to know about it.

svick
  • 236,525
  • 50
  • 385
  • 514
David
  • 15,750
  • 22
  • 90
  • 150

5 Answers5

51

UPDATE: This question was the subject of my blog on November 13th of 2012. See it for some more thoughts on this issue. Thanks for the great question!


You're right; it doesn't have to be that way. Other OO languages allow "private inheritance", whereby the fact that D inherits from B can only be taken advantage of by code that has the ability to see B.

This was a design decision of the original C# designers. Unfortunately I am away from my desk right now - I'm taking a couple of days off for the long weekend - so I don't have the language design notes from 1999 in front of me. If I think of it when I get back I'll browse them and see if there is a justification for this decision.

My personal opinion is that inheritance should be used to represent "is a kind of" relationships; that is, inheritance should represent the semantics of the domain being modelled in the language. I try to avoid situations where inheritance is used as a code sharing mechanism. As others have mentioned, it's probably best to prefer composition to inheritance if what you want to represent is "this class shares implementation mechanisms with other classes".

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    "prefer encapsulation to inheritance" - can you show an example of this? I'm not sure I understand exactly what you mean here, or how you'd use encapsulation to provide shared implementation code. – Erik Forbes Sep 02 '10 at 14:27
  • @Erik: I intended to type "prefer composition" and accidentally typed "prefer encapsulation". A rather large typo! – Eric Lippert Sep 02 '10 at 14:33
  • I see your point, although chin-stroking on architecture is a luxury for people with a better grip of the language than me! (I mean this in the best possible way, if by some mistake it reads as sarcastic or aggressive.) – David Sep 02 '10 at 14:54
  • @Eric - Ah, okay. Glad I'm not totally missing something, lol =) Thanks for clearing it up. – Erik Forbes Sep 02 '10 at 17:47
  • @Eric: Can these design notes be published? Or would that be a violation of MS policy? – James Dunne Sep 02 '10 at 18:54
  • 1
    @James: The notes are not in a form that is fit for public consumption. We can either spend time debugging the compiler and adding features, or we can spend time cleaning up thousands of pages of design notes mostly about features that were cut a decade ago. The vast majority of our customers would prefer that we spend our budget doing the former activities. – Eric Lippert Sep 02 '10 at 19:03
  • @Eric, public class extending internal base is not permitted, OK. What about interfaces? That seems to be permitted. If memory serves, `Tuple<>` implements `ITuple`, which is internal. – Anthony Pegram Sep 17 '10 at 16:41
  • @Anthony: Good point, I forgot to mention that. Yes, an interface may effectively be a implementation detail of a class. – Eric Lippert Sep 17 '10 at 18:07
42

By inheriting from a class, you expose the functionality of the base class through your child.

Since the child class has higher visibility than its parent, you would be exposing members that would otherwise be protected.

You can't violate the protection level of the parent class by implementing a child with higher visibility.

If the base class is really meant to be used by public child classes, then you need to make the parent public as well.

The other option is to keep your "parent" internal, make it non-abstract, and use it to compose your child classes, and use an Interface to force classes to implement the functionality:

public interface ISomething
{
    void HelloWorld();
}

internal class OldParent : ISomething
{
    public void HelloWorld(){ Console.WriteLine("Hello World!"); }
}

public class OldChild : ISomething
{
    OldParent _oldParent = new OldParent();

    public void HelloWorld() { _oldParent.HelloWorld(); }
}
Justin Niessner
  • 242,243
  • 40
  • 408
  • 536
  • 6
    Thanks. But why shouldn't an internal class's members be considered internal, except when exposed through a public subclass? I think that makes sense. – David Sep 02 '10 at 12:19
  • 2
    Thank you for your detailed answer and suggestion to use composition. Am I right in thinking that the answer to my question is more 'because C# wasn't created that way' than 'because it would be a stupid thing to do'? – David Sep 02 '10 at 12:36
  • 1
    It is a matter of convention. If you are looking to change the scope of the class through inheritance, you can simply not alter the rules to make something more accessible. Internal specifically should be used to make something accessible to all classes in an assembly. Changing the scope to public violates this, by making a subclass available to other assemblies. A good use of an internal class is protecting core framework concerns, for example. If you insist that your internal class should be accessible outside of the assembly, you likely should not be using the internal modifier. – Joseph Ferris Sep 02 '10 at 12:36
  • 3
    I prefer the interface approach, but I think David specifically wants to keep such functionality in a "common place" and not have to reimplement the same code in every derived class. – Dave Sep 02 '10 at 12:37
  • 1
    I don't think it is a matter of "because C# wasn't created that way". Internal is not a limitation, but a feature. It is similar to creating a class in Java with no access modifier, which constrains it to the JAR. It serves a very specific purpose, just one that is not often used (or used often enough, if you will). – Joseph Ferris Sep 02 '10 at 12:40
  • Okay, I think we can all see that composition is the way to muddle with accessibility of classes. I'm going to just make the base class public because I'm a bad person who can't be bothered to refactor. Thank you all for your enlightening answers. – David Sep 02 '10 at 12:52
  • @David: Internal class members are internal because you can not use them outside the assembly. (because internal class will not visible outside the assembly). But if you create a public sub class with base internal class, it will violate the rule, because through the public sub class, internal base class will be visible out side the assembly which will violate the internal class concept. – Zeeshanef Nov 28 '13 at 11:19
20

I think the closest thing you can do is prevent other assemblies creating the abstract class by making its constructor internal, to quote from MSDN:

An internal constructor prevents the abstract class from being used as the base class of types that are not in the same assembly as the abstract class.

You can then try adding an EditorBrowsableAttribute to the class to try and hide it from IntelliSense (though, I've had mixed results using it to be honest) or put the base class in a nested namespace, such as MyLibrary.Internals to seperate it from the rest of your classes.

Pang
  • 9,564
  • 146
  • 81
  • 122
Samuel
  • 2,516
  • 2
  • 24
  • 26
4

I think you're mixing concerns here, and C# is to blame, actually (and Java before it).

Inheritance should serve as a categorization mechanism, whereas it's often used for code reuse.

For code reuse it's always been known that composition beats inheritance. The problem with C# is that it gives us such an easy way to inherit:

class MyClass : MyReusedClass { }

But in order to compose, we need to do it by ourselves:

class MyClass {
  MyReusedClass _reused;
  // need to expose all the methods from MyReusedClass and delegate to _reused
}

What's missing is a construct like a trait (pdf), which will bring composition to the same usability level as inheritance.

There's research about traits in C# (pdf), and it would look something like this:

class MyClass {
  uses { MyTrait; }
}

Although I'd like to see another model (that of Perl 6 roles).

UPDATE:

As a side note, the Oxygene language has a feature that lets you delegate all members of an interface to a member property that implements that interface:

type
  MyClass = class(IReusable)
  private
    property Reused : IReusable := new MyReusedClass(); readonly;
      implements public IReusable;
  end;

Here, all interface members of IReusable will be exposed through MyClass and they'll all delegate to the Reused property. There are some problems with this approach, though.

ANOTHER UPDATE:

I've begun implementing this automatic composition concept in C#: take a look at NRoles.

Jordão
  • 55,340
  • 13
  • 112
  • 144
  • I entirely understand your point, but I feel your assertion that 'composition beats inheritance' could be expanded. Can you say anything else to explain why you think so? Thanks. – David Sep 17 '10 at 15:35
  • @David: I said that composition beats inheritance for code reuse. You shouldn't have to adhere to an inheritance hierarchy for the sole reason of reusing code. The hierarchy says something about who you are, and that's a very strong relationship (and very _precious_ in a single-inheritance language). For code reuse, you really want to say something about what you do, and composition and delegation allows you to do just that. Interfaces are also good at this, but you still need to implement its members or delegate to someone that does. – Jordão Sep 17 '10 at 15:59
  • The concept of "inheritance" actually includes two orthogonal concepts: code reuse with default behaviors, and substitutability. Inheritance is appropriate when both are required; composition is better when only code reuse is required. What would be really cool would be generic support for composition of interfaces, so if II is an interface, an object could implement II in terms of a field of that type. Without a generic constraint for interfaces, this obviously won't work, but it would be very handy if Microsoft could add it sometime. – supercat Mar 17 '11 at 22:01
  • @supercat: take a look at my first update for a language that has this feature. And take a look at my second update for a feature that's better :-) – Jordão Jun 18 '11 at 15:09
  • @Jordão: I'm not totally comfortable with the idea of using post-compilers, though I'm sure people who are comfortable with them find them useful. I suppose if the makers of a primary compiler decline to supply a useful interface one must do what one must do. Still, I think it would be helpful if C#/vb.net would allow a class to "internally" inherit another class but not be considered substitutable to outsiders; the behavior should be as though the "internally inherited" class were duplicated, but hopefully without actually duplicating the code. – supercat Jun 18 '11 at 17:36
  • @Jordão: This could offer an advantage over composition in that creating an instance of the new class would only require creating one object, rather than two. Not always a huge advantage, but sometimes significant. Actually, I've sometimes wished for an ability to apply certain very limited forms of inheritance to classes that were otherwise not inheritable. No new fields, and no overrides of virtual methods, but a means of defining non-virtual methods and also optionally creating a new type in the type system. For example, it might be helpful... – supercat Jun 18 '11 at 17:39
  • ...to define a type WizbangConfigString which would "inherit" string, and define new constructors and maybe some helper methods (conceptually like extension methods, but better scoped). It would be helpful to be able to either define the WizbangConfigString as "really" being a string (implying two-way substitutability) or as being a derived type (implying one-way substitutability). Probably doesn't do too much good to daydream about such features, though. – supercat Jun 18 '11 at 17:41
  • @supercat: interesting proposals. Looks like you'd like some form or non-public inheritance in C# (what you have in C++). You could also take a look at implicit conversion operators in C#. – Jordão Jun 20 '11 at 15:07
  • @Jordão: I dislike the implementation of extension methods in vb.net/C# since they follow scoping rules totally unrelated to any others. Having extension methods apply only to variables, parameters, and fields which are declared to be of a certain extended type would allow extension methods to take priority over base methods, which would avoid the dangers of code relying upon the non-existence of certain members in the base class. As for adding new types, I've sometimes found it desirable to have a collection where each item was a string plus a tiny bit of info to say what the string was. – supercat Jun 20 '11 at 15:24
  • @Jordão: One could define one or more classes which encapsulate a string, and define implicit an widening conversion to string for those classes, but every object stored in the collection would then require the storage of two objects: the string and the object encapsulating it. Since every object has type information associated with it, it would seem one should be able to make use of that information. To be sure, if one were to go crazy using nested generics so as to store huge amounts of information in object types (theoretically generic types can hold any amount of data) that would... – supercat Jun 20 '11 at 15:28
  • @Jordão: ...severely dog the type system, but I wouldn't expect the type system to mind using an object's type to hold a bit or so worth of information. – supercat Jun 20 '11 at 15:30
3

I think this would violate the Liskov Substitution Principle.

In cases like this, I have used internal classes and prefer composition over inheritance. Is there anything about your design that prohibits containing all such functionality in your internal class, and then have your public classes contain an instance of this internal class?

Dave
  • 14,618
  • 13
  • 91
  • 145
  • How does it violate the substitution principle? I don't see what you're getting at here. – Eric Lippert Sep 02 '10 at 14:20
  • @Eric I had it backwards, I guess. You violate the rule if your derived class removes functionality provided by the base, so you wouldn't be able to substitute your base with your derived class. When I first read the question, I jumped to conclusions. That was just a thought at the time -- the main part of my answer still stands IMO -- just use composition instead of inheritance. Thanks for the correction. – Dave Sep 02 '10 at 15:05