Internal Stripping
Okay, my dislike for internal is well known at this stage, I believe. What I want to talk about today is the process of stripping (ignoring) the internal keyword. As I have recently discussed, I have recently run into several situations where certain parts of the framework, marked as internal, would have been so very useful to me.
A while ago I stripped internal out of SqlCommandSet, and I have used the same technique since. It is a hack, mind you, but a very useful one.
Now, we can make use of internals in the framework if we use Reflection, but that has a perf cost to it. I found that by caching the results of the Reflection, and a bit of delegates, we can fairly easily expose the required functionality out, without paying a high price for performance. SqlCommandSet is a good example of this technique in action, and it has been wildly successful.
Another, a more advance version, but one that I don't know the ROI for, is to use Lightweight Code Generation to add accessors to the internal methods already there. I am pretty sure it is not worth the trouble.
Of course, if it is internal, you have to make sure that there are tests around it, because otherwise it could change without warning and you'll not know. There are other issues with the method, mostly around support, robustness (the internal code may make assumptions about its use), etc.
Comments
There's been various examples of this over the years, you can even do it with privates, or example:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1025231&SiteID=1#1025231
The last paragraph pretty much sums up why the "hate" of internals is irrational. I'm sure MS marked those types as internal for those exact reasons, mainly support and robustness. I'm not saying that there are no cases where the internal keyword has been abused, but I think there are several perfectly sound cases where it should be used.
All Microsoft would have to do is mark such classes with a [NotOfficiallySupportedAttribute] and be done with it. If your code used a member marked as such, you would get a compiler warning.
Well, Sun has had a doc warning about using sun.* classes for ages - but people still did.
Admittedly a compiler warning would be slightly more intrusive, but I'm sure people would still abuse it. Could Microsoft turn round and say "I told you so"? Absolutely. Would it still be bad press for them? Yup.
Hopefully some of these will eventually make it into the framework in a fully supported way, of course.
Using private or internal types/members is something that should be avoid in most of the cases. There are many reasons that a developer doesn't expose an internal implementation to the public. Just to give a few good reasons:
The object has to keep its own invariants. It can be a nightmare finding who changes or uses in a wrong way an internal part of a module/class.
The internal method has a certain "safe" ways to be used, and internally the developer knows how to use it, but a very bad side effect can be happen in a wrong usage (wrong protocol)
It's not an easy task to make something public, to make extension points (protected) and so on. You have to think a lot and you have to test it. Making it internal at first place tells that it is an implementation code for the internal dev team.
Coupling, Coupling, Coupling. A good software engineering is to reduce coupling by exposing only few interfaces. Making everything public will not help.
Maintenance and upgrading, do you want each time a hot fix, service pack or new version of .NET/Windows is installed to go over your million lines of code software and fix all your "internal" usages. O.K maybe not everything has changed, but you have to test your software again anyway.
You will not get any breaking change document about internal code, and you may not get Microsoft support if you use internal mechanism.
I think that you have got the point. I know that sometimes you will not agree with the internal/private keyword. But this is the privileges of the developer; he does not have to give you everything. And if you don’t get enough in the interface (public) don't use it at all.
Now, there are times that you may use internals API. For example sometime I use ntdll functions even though there are not documented APIs. I even implemented many FXCop custom rules when I knew that the SDK will be changed. But I am doing it with a known risk. I document it; I try to find a better way and if there is no one I take my chances. But at least I know the risks.
Alon Fliess
VC++ MVP
Hacking code like that... That's just wrong in so many ways...
Eran,
Maybe, but it is always very very useful on many occasion
Alon,
Everything you say it correct. Except, too many useful parts are locked down.
From my point of view, internal is a cop out, it lets the framework use it, sometimes extensively so, but lock other people.
Either you make it private, or you make it public. [ThereBeDragons] is there for a reason
Yes, like many other forbidden things in life. It is useful, but dangerous. internal == private for the assembly level, hence it just what you said: It is private!
Nope.
That is not what I meant.
I meant private as in private for the class. If it is accessible from outside that class, then it should be accessible externally as well.
I can't even enumerate the number of times that I have hit the wall because of the urge to slap internal on things
First of all, the original post was about types… But it does not matter, if a type exports a method as an internal method it is an interface of the type for its assembly and no other one. It may be a way to implement a cluster of classes that doing a task together. For example a collection class may give its iterator (another class) a way to see its internals. Both classes reside in the same collection assembly. In C++ we may use the friend keyword. In C# we may make the iterator an inner class, but this implies the class name as part of the iterator name. The other way to combine the two is to make them part of the same assembly and make the internal implementation members of the collection visible to the assembly by making them internal.
Yes, there are many times those other reasons that we have talked about are the real reason. But still internal==private for external code no matter what the reason is!
Comment preview