Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Wednesday, December 31, 2008

Namespace visibility in C#

Java has package scoping. It allows an element to be visible only within the same namespace. It's a wonderful thing.

Here's how it works in Java:


package com.pc-doctor.mynamespace;
package class Foo { ... }


The class Foo is only visibile within mynamespace.

Even though I'm not a Java programmer, this immediately strikes me as extremely useful. Frequently, helper classes are only needed by code that lives close by.

There are two reasons to want namespace visibility to be enforced by your compiler:

  1. If you can make those classes invisible outside the namespace, it will make life a lot easier for clients of that namespace. Having only the useful classes appear in Intelisense is a big win.
  2. Having helper classes be invisible also helps construction of the component that is in the namespace. If the compiler doesn't let anyone make calls to the helper classes, then we can make much stronger assumptions about how our clients use the code.
C# does not offer any support for namespace visibility. However, there are three ways to accomplish it. None of them are perfect, and one of them is a bit bizarre.

The Microsoft Way



Microsoft expects you to make the classes internal. This prevents anyone outside of the assembly from using the class.

However, you have to make a separate assembly for each namespace that you want to do this with.

Frankly, that's painful enough that few people do it.

The C++ Way



C++ also lacks namespace visibility. The folks over at Boost use a separate namespace underneath the main namespace for helper classes (and functions). They've standardized on the name "detail" for this namespace, and it works fine for problem #1. It doesn't do anything for #2, though.

This is an easy thing to do, but it doesn't do much in C#. C# programmers use a lot more using directives than C++ programmers should. The only place to put a using directive in C# is at the top of the file. This means that, if a single function needs a namespace, then the whole file will get it.

The end result is that a lot of detail namespaces will be visible. This means that you'll have to make a using directive for the detail namespace that you really want, and you'll have to avoid typing "detail" to get to an element.

Even with those problems, it's probably worth doing in C#. Create a detail namespace under each namespace and put things that you'd like to have package scope in there.

Getting the C# Compiler to Enforce Namespace Visibility


C# does have a feature that can be used to emulate namespace visibility. This solution is a bit weird.

I should point out that it uses a feature of C# that wasn't designed for what we're going to use it for. In C++, this kind of behavior is encouraged and well supported. In C# (and Java), you're not supposed to deviate from the party line.

I'm sure Microsoft doesn't have any tests written for this behavior; I've already found one bug in the compiler from this technique.

What is a namespace? It allows many classes to be placed in the same scope even when they're stored in different files.

A partial class does the same thing, and this can be used to emulate a namespace. Partial classes were designed to allow Microsoft's code generators to create part of a class and put those portions of the code in a separate file. C#'s designer tool makes heavy use of this.

It's also very close to a namespace!

If you use a partial class as a namespace, then you can put multiple classes in different files and have some of them be invisible outside of the "namespace".

A private class inside the "namespace" is visible to other classes in the namespace, but it is not visible outside of the namespace. Likewise, a public class is visible outside of the partial class.

All of this is enforced by the compiler, too. We get both of the benefits of namespace visibility with this technique.

Unfortunately, it doesn't work perfectly.

For example, using declarations don't work for a partial class. If you're not in the namespace, you will always have to use the partial class's name to access public members of the namespace. This may be annoying in some cases, but, if you limit this technique's use to cases where there isn't a lot of access to the namespace from outside of it, then it's not serious.

It also looks wrong in the IDE. The IDE has no idea that your class is really a namespace, so it gets colored incorrectly. The severity of this problem is a matter of opinion. It doesn't bother me.

This is all awkward enough to prevent me from completely replacing namespaces. Instead, I use this when I want to expose an extremely simple API and perhaps a type or two. It's really only worth the trouble if you get to hide a lot by using this.

The syntax is also verbose:

namespace pcdoctor {
  partial public class fakeNamespace {
    private class NamespaceVisibilityClass {}
  }
}

There's actually a hidden benefit of this technique. It's possible to make a "free function" in the fake namespace. A static member function behaves a lot like a free function. It's accessible from any of the classes in the namespace. If it's public, then it's accessible from outside the namespace.

I mentioned that I found a bug in the compiler. Unfortunately, I didn't track down exactly what the bug was. Instead, I just found a solution and moved on.

However, if you find that some of your code gets executed more than once when the fakeNamespace type is instantiated, then you might want to find another solution.

Good luck! Just remember that the central authority that controls C# programmers doesn't want you to do this. You're on your own here.

Tuesday, February 5, 2008

Interfaces, Friends, and the .NET Framework

The .NET Framework has a lot of really great things in it. I've just started playing with a few corners of it, and I love the amount of stuff that it's got in it. Some things really irritate me, though, and it's a lot more satisfying to talk about that stuff!

C# and the CLR make it really hard to hide information. First of all, the .NET framework is built around inheritance. Everything is inherited from something else, and if you want to extend an object, then you're going to inherit, too. Inheritance hides almost nothing, but you already knew that, and, presumably, you don't use it as much as the programmers in Redmond.

That's not what I want to talk about here. I'm going to complain about the member access rights that C# and the CLR support.

In C#, there are four different member access rights. The usual private, protected, and public member access rights are supported. They also support "internal", which is the same as not exporting a function from your DLL in C++. The CLR supports one additional one called "Family and Assembly" which is the same as a protected member that is not exported from the DLL.

It's missing two extremely useful access rights, however. Java's package level scope and C++'s friendship. Both of these allow a programmer to grant access to a limited number of functions and classes. Java's package level scope is the optimal one, in my opinion. This allows a programmer to give limited access to a limited number of classes. Friendship allows complete access to individual classes and functions.

In the C# world, you're expected to grant public access to functions that should only be used by one other function outside your class. You're supposed to be happy about it, too!

This originally appeared on the PC-Doctor blog.

Monday, January 14, 2008

Exception Safety in C#

C# vs. C++


C# tries to perform resource management through finally clauses and the garbage collector. This is radically different from C++'s approach. C++ executes destructors (which do all of the resource cleanup in modern C++) in a deterministic order.

While exception safety is certainly possible in C#, it is potentially error-prone. It frequently relies on the user of a class putting the correct code in a finally block. (This is code that the compiler frequently figures out in C++/CLI, so it's not a problem with the CLR.) C++, on the other hand, relies on the author of a class to put the correct code in the constructor and destructor.

C# requires that resource management be done every time a programmer uses a class. C++ requires that it be done once. This lies at the heart of my complaint with C#, but it gets worse, as we'll see.

To be fair, C# does handle one resource automatically. Memory management doesn't require any work since it's all cleaned up by the garbage collector. All other resources require some extra effort on the part of the programmer. C++ requires that programmers put all memory resources inside an appropriate smart pointer.

The conventional C# approach


Code that allocates a non-memory resource in C# is supposed to look like this:

// Declare all variables that may require cleanup at the top of your function.
// Also include enough state information that you'll know how to undo
// partial changes that were made.
try {
  // Use the variables.
} catch( Exception ) {
  // Roll back any changes that were made.
} finally {
  // Call Dispose on all of the objects created that implement Dispose.
}

Needless to say, this sucks. It requires that you know which objects require disposal. It forces you to declare all of your variables at the top of the function and move them away from where they are used. It's also a lot of extra text that makes it harder to figure out what the function is actually doing.

However, assuming that the programmer didn't screw up, it will work.

What happens when someone screws up?


Unfortunately, the burden of cleaning up resources is placed on the user of the resource rather than the implementor of the class that handles the resource. This means that you can't be sure that Dispose will be called every time that it has to be called. Furthermore, it means that resource cleanup has to be performed correctly more than once per class.

The CLR has anticipated this problem to some extent. It allows a class to declare a finalize function which gets called by the GC right before it gets destroyed. You won't know when this function will be called, but at least your resource will get cleaned up eventually if you use this.

Is Finalize enough?


Unfortunately, Finalize has some serious problems. Because the garbage collector destroys the objects in a non-deterministic order, some of the member variables of the object being finalized might have been destroyed already.

The CLR provides some information about the order in which objects are destroyed, however. The following assumptions can be used:
1. Objects that derive from CriticalFinalizerObject and have a finalization method can use references to objects without a finalization method.

2. Objects that do not derive from CriticalFinalizerObject can use references to objects that do derive from CriticalFinalizerObject and also objects that do not have finalization methods.

Microsoft strongly recommends that you don't derive anything from CriticalFinalizerObject. However, this is the only mechanism they give you to order the finalization methods. If you have one object that must finalize before another, then you either have to use this, or you have to do what Microsoft did for System.IO.StreamWriter. This class does not flush its buffer during finalization because it may contain a FileStream object that must be closed after the StreamWriter flushes its buffer. In other words, the StreamWriter simply doesn't work unless it is Disposed correctly.

Of course, if you have three objects who's finalization order must be determined ahead of time, then even deriving from CriticalFinalizerObject won't work. In other words, even if you didn't care exactly when a resource was cleaned up, finalize isn't enough to make all classes safe to use. Sometimes you must rely on the user of your class to make it safe in C#. The fact that it works a lot of the time is only going to make the users careless.

Personally, I find this scary.

This originally appeared on the PC-Doctor blog.

Monday, September 10, 2007

C++/CLI vs. C#

We're thinking about writing a new application in .NET. I tend to believe that there's not much difference between any of the languages that Microsoft has created for .NET. VB is essentially C# with different keywords and punctuation, for example. You're certainly not going to change the design of your code because you had to write end instead of }, so, for a long time, it seemed irrelevant to discuss anything but C#.

Then Microsoft fixed their C++ implementation with C++/CLI. This is actually a different language from C#. It tries pretty hard to be C++ with access to the .NET runtime and some extra pointer syntax. In particular, you can still have deterministic destructors, free functions, and generic programming. You'll write a different program with C++/CLI than you would with C#, so it's worth thinking about which language you'd choose.

Deterministic Destructors


Actually, you just have destructors. There is a way to create the whole IDispose mess in a C++/CLI class, but it's largely irrelevant since the destructor actually works. This blog explains how to do it, if you're curious.

With real destructors, you can use the resource acquisition is initialization (RAII) idiom to make your code exception safe and easy to read at the same time. C# supports exceptions, but it relies on some quirky syntax to make them safe to use. If the programmer forgets to use the quirky syntax in a few places, then the code can do some really weird things. (No, there aren't any memory leaks. People like to claim that that's a serious problem with C++. Releasing resources is a more general problem that garbage collection does not solve. RAII solves the whole problem rather than a corner case.)

Anyway, I've gotten lazy as a C++ programmer, and I'm not sure I'm willing to go back to a world where exception safety is something you have to work hard to achieve, and releasing resources correctly is not something that the compiler does automatically for you.

To me, this is enough to make me not want to touch a complex application in C#, but let's keep going.

Free functions


C# does not have free functions. Every function is a member of a class. This sort of restriction really irritates programmers like me. Why does the compiler writer get to decide what the right solution to a problem is? Why can't I use the tool that's right for my problem?

In C#'s defense, I think they're using theory that it's harder to kill yourself with a blunt knife. There are a lot of bad programmers out there in the world. Some of them don't know when to use a free function and when to use a static member function. The designers of C# decided that in a fully OO application, there shouldn't be much need for free functions. In the majority of the cases, free functions are, therefore, a bad idea. If you don't let programmers use them at all, then programmers who don't want to worry about getting things right have one less decision to make. C#'s solution is, therefore, ideal for them.

It's annoying for me.

For some reason, I picked on free functions. I'm a fan of them, but there are other things missing from C#: multiple inheritance, a preprocessor, etc. It's all the same story.

Generic Programming


Some people are violently against this stuff, so I won't try to argue that it's got its place. I'd certainly miss it, but I doubt I'd use much of it here at PC-Doctor.

Refactoring Tools


C++ is a frighteningly complex language. Creating a C++ complier is an enormous amount of work. Generally, by the time companies are done with the C++ compiler, they've run out of time and budget.

Refactoring tools never seems to get put in the budget. Of course, changing the name of a type and having to figure out where all the instances that need to be changed are can be both difficult and occasionally impossible in C++.

C#, on the other hand, has some great refactoring tools. This makes some things a heck of a lot easier.

Conclusion


C++ and, by extension, C++/CLI has a lot of features. There are a lot of things in there that are dangerous to use in the wrong circumstances. However, if you spend all your time doing something, you want to have all the tools available to you. You're willing to learn the extra parts that aren't useful every day. I want to have enough tools to hurt myself.

The refactoring tools will be missed, and I hope that someone will get around to making some good ones for C++ eventually.

This originally appeared on PC-Doctor's blog.