views:

250

answers:

5

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.

+12  A: 

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
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
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
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
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
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
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
+1  A: 

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
How does it violate the substitution principle? I don't see what you're getting at here.
Eric Lippert
@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
+1  A: 

I think the closest thing you can do is prevent other assemblies creating the abstract class by making it's 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.

Sam
Interesting ideas, thank you.
David
+10  A: 

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
"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
@Erik: I intended to type "prefer composition" and accidentally typed "prefer encapsulation". A rather large typo!
Eric Lippert
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
@Eric - Ah, okay. Glad I'm not totally missing something, lol =) Thanks for clearing it up.
Erik Forbes
@Eric: Can these design notes be published? Or would that be a violation of MS policy?
James Dunne
@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
@Eric, do you guys also the labor day over there for this Monday?
Joan Venge
@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
@Anthony: Good point, I forgot to mention that. Yes, an interface may effectively be a implementation detail of a class.
Eric Lippert
A: 

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.

Jordão
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
@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