views:

405

answers:

9

I’ve been pondering about the C# and CIL type system today and I’ve started to wonder why static classes are considered classes. There are many ways in which they are not really classes:

  • A “normal” class can contain non-static members, a static class can’t. In this respect, a class is more similar to a struct than it is to a static class, and yet structs have a separate name.
  • You can have a reference to an instance of a “normal” class, but not a static class (despite it being considered a “reference type”). In this respect, a class is more similar to an interface than it is to a static class, and yet interfaces have a separate name.
  • The name of a static class can never be used in any place where a type name would normally fit: you can’t declare a variable of this type, you can’t use it as a base type, and you can’t use it as a generic type parameter. In this respect, static classes are somewhat more like namespaces.
  • A “normal” class can implement interfaces. Once again, that makes classes more similar to structs than to static classes.
  • A “normal” class can inherit from another class.

It is also bizarre that static classes are considered to derive from System.Object. Although this allows them to “inherit” the static methods Equals and ReferenceEquals, the purpose of that inheritance is questionable as you would call those methods on object anyway. C# even allows you to specify that useless inheritance explicitly on static classes, but not on interfaces or structs, where the implicit derivation from object and System.ValueType, respectively, actually has a purpose.

Regarding the subset-of-features argument: Static classes have a subset of the features of classes, but they also have a subset of the features of structs. All of the things that make a class distinct from the other kinds of type, do not seem to apply to static classes.

Regarding the typeof argument: Making a static class into a new and different kind of type does not preclude it from being used in typeof.

Given the sheer oddity of static classes, and the scarcity of similarities between them and “normal” classes, shouldn’t they have been made into a separate kind of type instead of a special kind of class?

+6  A: 

It's a class as far as the CLR is concerned. It's just syntactic sugar in the C# compiler, basically.

I don't think there would be any benefit in adding a different name here - they behave mostly like classes which just have static methods and can't be constructed, which is usually the kind of class which became a static class when we moved from C# 1 to C# 2.

Bear in mind that if you want to create a new name for it, that probably means a new keyword too...

Jon Skeet
VB.Net has this - a Module.
Graham Clark
Yes, but modules really suck, because developers are allowed to call their methods without the class name. This is write time convenience, that really makes reading VB code painful.
Steven
+3  A: 

I don't know if this qualifies as an answer, but I would point out that "static classes" are more of a language concept and less of a CLR concept. From the point of view of the CLR, they are just classes, like any other. It's up to the language to enforce all the rules you described.

As such, one advantage of the current implementation is that it does not add further complexity to the CLR, which all CLR-targeting languages would have to understand and model.

Daniel Pratt
A: 

Good point, it's probably because of historic reasons, i.e. they didn't want to invent something new as static classes already existed.

C++, Pascal (Delphi) and Java all have static classes, and those are what C# is based on.

Guffa
however, it's good to note that neither C++, Delphi nor Java actually use the term or keyword 'static class'. They simply permit a class to have static functionality with no instance functionality.
Stefan Monov
+5  A: 

Your question is "why do I have to type the words static class X rather than foobar X". The answer is, because programmers already associate the word 'class' with 'a bundle of tightly packed encapsulated functionality someone wrote for me'. Which, coincidentally, fits perfectly with the definition of static classes.

They could've used namespaces instead, yes. That's what happens in C++. But the term 'static class' has an advantage here: it implies a smaller and much more tightly coupled group of functionality. For example, you can have a namespace called Qt or boost::asio but a static class called StringUtils or KWindowSystem (to borrow one from KDE).

Stefan Monov
Surely the same argument applies to all the others. Instead of *struct*, *interface*, etc. they could have been called *value classes*, *interface classes*, etc.
Timwi
To me, those have different names because they aren't "bundles of functionality". A struct is usually just a dumb bundle of data. An interface does not *provide* functionality, it promises functionality.
Stefan Monov
@Timwi: You mean like C++/CLI does? http://msdn.microsoft.com/en-us/library/xey702bw(VS.80).aspx
Ben Voigt
@Stefan: Many value types provide functionality and aren't just "dumb bundles of data". Consider `DateTime.IsDaylightSavingTime` or `DateTime.ToLocalTime`.
Ben Voigt
I stand corrected. In that case naming structs "value classes" could have made sense.
Stefan Monov
+1  A: 

Yes, they are very odd. They do have some class-like behavior, like being able to have (static) member variables, and restricting access to members using public/private.

I almost typed "public/protected/private" there, but obviously protected doesn't make sense, because there is no method inheritance of static classes. I think the main reason for this is that because there are no instances, you can't have polymorphism, but that is not really the only reason for inheritance. Polymorphism is great, but sometimes you just want to borrow most of the functionality of the base class and add a few things of your own. Because of this, sometimes you'll see static classes switched to use singleton patterns, just so that it can leverage the some functions from base set of classes. In my opinion this is a hacky attempt to close that gap, and it gets confusing and introduces a lot of unnatural complexity. The other option is aggregation, where the child class methods just pass calls through to the parent class methods, but this is requires a lot of code to stich it all together and isn't really a perfect solution either.

These days, static classes are usually just used as a replacement for global methods, i.e. methods that just provide functionality without being bound to an instance of anything. The OO purists hate any concept of a free/global anything floating around, but you also don't want to have to have an unnecessary instance and object floating around if you just need functionality, so a static "class" provides a middle-ground compromise that both sides can sort of agree with.

So yes, static classes are weird. Ideally, it would be nice if they could be broken into their own concept that provided the flexibility and lightweight ease-of-use that you get from methods that don't need to be bound to an instance (which we have now with static classes), and also group those methods into containers (which we also have now), but also provide the ability to define a base entity from which it will inherit methods (this is the part that is missing now). Also, it would be great it was a seperate concept from classes, for exactly the reasons you raise, it just gets confusing because people naturally expect classes to be instances with properties and methods that can be created and destroyed.

Mike Mooney
Accessibility modifiers work just fine in value types (`struct`).
Ben Voigt
A: 

In my opinion, static classes are considered so because they can embed private fields, public properties and methods, though they are static, and have a fixed address location where each call to the singleton method or property will have its reference.

A structure is more likely a value type as when you write:

var struct1 = new Struct1();
var struct2 = struct1;

each of the properties will have been copied into a new memory location. Furthermore, with a structure, you will be able to change struct2.Property1 value without having it changed within struct1.Property1.

Per opposition, classes are in my understanding reference types, as when you write:

var class1 = new Class1();
var class2 = class1;

Here, the reference is copied. This means that when you change class2.Property1, this same property will also change in class1.Property1. This is because both classes points to the same memory address.

As for static classes, they are considered as reference types as when you change a StaticClass.Property value within a method, this change will get populated everywhere you reference this class. It has only one memory address and can't be copied, so that when another method or property call will occur, this new value will prevail over the old one. Static classes are meant to be shareable accross an entire application, so only one reference for it exists within your application. Therefore making them behave like a class.

A static class, even though singleton pattern is not, I guess, encouraged except for absolute purpose, could represent a real-life object just like a class or an instance of a class. However, since unique-in-the-world-objects seem to be rare enough, we don't really need them to represent a practical object, but merely some logical ones instead, such as tools and so forth, or some other costy-to-instiate objects.

EDIT In fact, a static class is so similar to a class that in Visual Basic, there is no static class, but only a class with static (Shared in Visual Basic) members. The only point to consider is to make this class NotInheritable (sealed in C#). So, C# provides a more implicit functionality by allowing to declare a class static, instead of making it sealed, with an empty default constructor, etc. This is some kind of a shortcut, or syntaxic sugar, like we like to say.

In conclusion, I don't think there would be any benefit or gain having a new keyword for it.

Will Marcouiller
Most of what you said talks about *static fields* and has nothing to do with *static classes*. Static fields can be declared on non-static classes and structs and behave no differently there than in a static class.
Timwi
You're right, after rereading myself. What I meant is that a static class behaves like a class having static methods and/or properties. So why adding a new keyword, when in my point of view it is a kind of class? I would consider a static class instantiating itself upon a method call or a property access through the "default" empty constructor. This somehow imitates the structure behaviour. However, an static class behaves and have more things in common with a class than a structure. (Thanks for enlighten me with your comment.)
Will Marcouiller
A: 

Static classes and "normal" classes (and structs) are containers for executable code (members fields, properties, methods) and they declare a Type. If they had a separate word for this then we would ask the opposite ("if they are so similar, why did you not use the kayword class?"). I'd suggest "CLR via C#", where it's well explained how type resolving, method calling, etc occurs. It works in the same way for "both" classes, just instance members have additional parameter passed in for the instance object.

Classes are not like namespaces because they are only for naming and referencing. They do not affect the functionality of the class.

Classes are also different from interfaces, because interfaces are merely compile-time verification tools and do not have functionality of their own.

ImreP
By that argument, since static classes and non-static structs are so similar, why did we not use the keyword *struct*?
Timwi
Because struct is not the same as class, they are handled differently in memory and when passed as parameters. For giving developers possibility to intentionally control that behavior, there has to be syntactic difference. But structs and all classes are still containers of functionality. It does not matter much what name you give them as lonog as you can tell the difference.
ImreP
A: 

What about static constructors? I think this is another important aspect to consider in your comparison. Classes and structs support them but interfaces and namespaces do not.

Construction implies instantiation. While the implementation may not actually create an "instance" of a static class, you could view static classes as a singleton instance of a class, to which there can only ever be one reference (the typename itself). If you could inherit static classes, you would break the singleton notion. If you could declare variables of the type, you might expect them to be cleaned up by the garbage collector when they are no longer referenced.

Why are they classes instead of structs? When I think of structs (value types), I think about values on the stack. Their existence is (typically) very short and they are copied frequently. This again breaks the single reference singleton notion above.

Michael Petito
A static class is no more a “singleton instance” than the set of static fields on a non-static class or struct. (Also, unrelatedly, your view of structs is inaccurate and implementation-specific.)
Timwi
@Timwi: A singleton by definition is a restriction to one instance. Static members of any class are members common to all instances; static classes have only one "instance". So having static members is not sufficient to say your class is singleton. Having a static class is sufficient (but not necessary). As for my views on structs: "Structs are value types and do not require heap allocation." http://msdn.microsoft.com/en-us/library/aa664465(v=VS.71).aspx Yes, you can have structs living as members of classes in the heap, but when you access them they are (often) copied to the stack.
Michael Petito
+2  A: 

Sure, they could have been made into a separate kind of thing.

But that would have required additional work in the CLR, the BCL, and across the language teams, and I that would have left other, more important things undone.

From a purely aesthetic point of view, I might agree with you.

Eric Gunnerson