A Critique of the C# Programming Language
I managed to open and skim through the O’Reilly book “Programming C#” (2nd Ed.), by Jesse Liberty. I won’t pretend to approve of the language or the agenda that brought it into being.
I have no access to a C# compiler, so I can’t run experiments, and so, this all has to be taken with a grain of salt.
One objection to a “critique of C#” would be that you can’t talk about C# without talking about the whole “.Net experience”. However, one can approach the topic of Hitler without a complete discussion of Nationalist Socialism, so I feel justified.
The book, and Microsoft’s web site, highlight similarities between C# and C++. No independent programmer familiar with these languages would see C# as a descendant of C++, however. Plainly, C# is a Java knock-off, with many additional elements from C++ and scripting languages such as Visual Basic thrown in. I’m going to approach this primarily by comparing C# to Java.
I’ll spend time discussing the “.Net” features of the language, for two reasons. First, these are the features of C# that are most ballyhoo’ed, and second, I’m not personally very familiar with the analogs of these features in other languages.
Overview
The syntax of C# almost contains Java as a subset.
Much straight Java code would compile without alteration; almost all would
compile with a few syntactic alterations but no structural changes.
The major syntactic differences are: class declarations look like
C++ declarations, the keyword virtual
is used to label methods as
overridable in subclasses (in Java, methods are virtual by default)
and the following keyword differences
C# | Java |
---|---|
sealed class | final class |
readonly (member) | final member |
using | import (+using ?) |
is | instanceof |
Otherwise, like Java, C# has native threads, garbage collection, and
exception handling. It does not use header files. As in Java, there is
no such thing as a function outside a class in C#. As in Java, all C#
classes derive from class Object
, and primitive types
(int
, float
) have fixed bit definitions.
This language is huge—substantially bigger than C++.
The book lists 80 keywords.
(Microsoft’s site lists only 77, but it excludes get
and
set
—(why?))
The Java 1.4.1 Language Specification lists 48, a couple of which are unused.
I have seen a list of 49 for C++.
(I can’t find a list of keywords for Perl—there are so many; perhaps because
it’s difficult to distinguish a keyword from the many syntax oddities in
that language. )
language | version | keywords | notes |
---|---|---|---|
C# | 80 | according to the book | |
C++ | 49 | ||
Java | 1.4.1 | 48 | (two are unused) Java Language Specification |
C | ANSI | 32 | K & R |
Python | 2.2 | 29 | Python Reference Manual |
There are a few nice constructs in C#—even a few things I’ve missed in Java. It looks to me like a usable programming language, if you can find drugs to fight the gag reflex.
As Java runs in a certain restricted environment (a Virtual Machine, or VM) that could exist on any computer-like device, C# may be used to produce applications on any device that supports the Common Language Runtime (CLR). The CLR has one advantage over the Java VM in that it is designed to be language-independent. The Java VM presently runs on a wide range of hardware and operating systems. My guess is, the CLR will never be so widely spread—not because it couldn’t be in principle, but because such accommodation isn’t Microsoft’s style.
As in Java, there is no multiple inheritance in C#. Although the C# class declaration looks like the (relatively unsuggestive) C++ one, it is functionally identical to the Java declaration. You extend from no more than one class, but can implement multiple interfaces.
As in Java, C# types are divided into two main genera, value types
and reference types; value types being types such as
int
, float
, and so forth, and reference types being
objects. Value types are passed to functions by value, reference types by
reference.
The implementation of polymorphism (method overloading) differs between
Java, C++ and C#. Here, C# has a small advantage of providing greater
specificity (although it takes more code and more keywords to achieve it).
You have to explicitly mark methods as virtual (as in C++) but then you have
to also mark subclass methods as overrides. This might eliminate certain
annoying situations that happen in C++ and Java, such as shadowing.
To create a subclass method with the same signature of a superclass method,
but which doesn’t override the superclass method, you mark it with the
keyword new
.
C# also allows member data to override inherited data, using the
new
modifier. I can’t imagine how this is a good thing.
The primary inadequacy the Java language as a large-scale applications
programming language is that absence of a convenient means of controlling
responsibility for altering an object. This is done in C++ with
const
.
This crucial feature is also lacking in C#. (As near as I can tell,
the keyword const
in C# is a synonym for readonly
,
just a modifier for member data. So you can’t say which methods of a
const
object can be called, etc.). I know of no other feature
of C# that fills this role,
so I have to pass the same judgment on C# as I have with Java: not
appropriate for large-scale applications programming. This isn’t a
blanket condemnation—not all applications programming is so large-scale,
and in particular, most Web-delivered applications shouldn’t be.
.Net
MetaData
.Net programs can contain metadata, which is information that can be read in a standardized way from outside. This is reminiscent of the Mac “resource fork”.
C# provides a means of inserting metadata directly into the code. Here, it can double as a comment, or affect how the code is compiled. This is done using attributes, which coded as text between square brackets.
Common uses of attributes:
[Serializable]
— makes following class savable to disk
[WebObject]
— makes following code visible by .Net apps
Reflection
Reflection is the capacity of an object to investigate its class information: its parent class, its class hierarchy, its methods and their signatures. In C# can also look at metadata.
C# reflection is similar to that provided by the Java reflection library.
C# Reflection Emit allows dynamic creation of new types. This is completely absent in Java (although it is rumored to be planned for Java 1.5.1). In C++, templates serve part of this role. This sounds useful to me. If the syntax is nicer than C++ template syntax, it’s going to be a good thing.
As near as I can tell, this permits C# code to be constructed, compiled into a module, which is loaded and run, on the fly, from a running program. Holy moley! Is that a good idea? The book has a concocted example of how it can provide more efficient code in specific cases, but the overhead of doing the emit would typically be prohibitive.
Webobjects
By tagging a method with the [WebObject]
attribute, you make it
so that a web application can see and call that method.
You can then write another application that runs remotely, but which
is aware of the WebObject method, and can call it and get return values.
Communication can use the old CGI get
and post
calls,
or the more modern XML protocol SOAP, which has much better type support.
Assemblies
A module is the CLR analog of a library. If saved individually to disk, they are saved as DLL’s.
An assembly is the CLR analog of an application. Assemblies consist of modules. On the disk, assemblies are saved as Portable Executable (PE) files.
Each assembly has exactly one entry point: WinMain
for
Windows apps, Main
for DOS apps, DLLMain
for DLL’s.
CLR assemblies and modules contain a standardized version and manifest.
The version is a number which is shared by all parts of the assembly. All parts of the assembly must be updated together. You can’t have a higher version number in one module in the assembly than in another. The book sneers at the idea of shared libraries, saying they are nice in theory, not in practice, and denies that backward-compatibility can really work.
The manifest lists all the parts of the assembly, describing methods and data. It is described as metadata in the assembly.
Syntactic debts
From C/C++
-
enum
s -
struct
s -
unsigned
types - preprocessor instructions
-
goto
-
do…while
- “destructor” syntax looks like C++ but acts like Java finalizer
- operator overloading
- pointers and pointer arithmetic
- have to declare unsafe mode—only for native libraries and code
From scripting languages
-
switch
on string -
foreach
-
as
(same asis
plus a cast) - dynamically add elements to arrays
Reminiscent of Simula
-
argument modifiers
ref
andout
for pass-by-ref and initialize-by-ref
Maybe unique to C#
-
internal
access modifier -
Restricts access to the current program (
protected internal
limits access to subclasses in this program. - boxing
-
Conversion of value type to reference type.
int i = 48; object obj = i; // boxing is implicit int j = (int)obj; // un-boxing must be explicit
- delegates
-
Like C++ function pointers, but type-safe.
delegate void D( int x ); class A { public static void F( int i ); } class B { void foo() { D myF = new D( A.F ); } }
- properties
-
Allows private member access to look like public access, but really
calls accessors of a contained class.
To do it, create a private member variable, then create a public
contained class, say,
Foo
, with two methods,get
andset
, which access the member variable. Then can useFoo
as though it were a member variable:obj.Foo = 1
. Is this a good thing? -
override
;virtual
is root of polymorphism -
The last
virtual
method with a given name in a class is the root of polymorphism for that method. To override the functionality in a subclass, must explicitly mark asoverride
. (Isvirtual override
possible?) - variable-length arg list
-
void foo( params int[] val )
- virtual member fields
- reflection emit
- see below
C++ features not in C#
- templates
- there is some talk about including this in a future release
- multiple inheritance
- functions and variables outside of classes
- const-ness
-
The
const
keyword is part of C#, just not discussed in this book (as near as I can tell). At the MS site, the examples only have it a a sort of synonym forreadonly
. - bit fields
- method parameter default values
-
fall-through in
switch
- initialization lists
- Neither C# nor Java require C++ constructor initialization lists. They each provide a special mechanism for initializing the parent class with a particular constructor, though.
Comparison of inheritance and polymorphism
C++
class A { public: A( int x ) { } virtual ~A() {} virtual void amethod(){} // virtual methods must be so marked }; class B { // C++ doesn't have interfaces per se protected: B() {} public: virtual void bmethod(); }; class C : public A, public B { public: const int y; // const and reference members must be // initialized in constructor initialization list C( int x, int y0 ) : A( x ), // parent class constructor y( y0 ) { } virtual ~C() {} void amethod(){} void bmethod(){} };
C#
class A { public A( int x ) { } virtual void amethod(){} // virtual methods must be so marked } interface B { void bmethod(); } class C : A, B { // note everything after comma must be an interface readonly int y; public C( int x, int y ) : base( x ) { // parent class constructor // readonly member initialization required by // syntax in every constructor this.y = y; } public override void amethod(){} // explicitly mark overrides virtual void bmethod(); }
Java
class A { public A( int x ) { } public void amethod(){} // methods virtual unless 'final' } interface B { void bmethod(); } class C extends A implements B { final int y; public C( int x, int y ) { super( x ); // parent class constructor // final member initialization required by // syntax in every constructor this.y = y; } public void amethod(){} public void bmethod(){} }
About the book
The index is useless. For instance, the only reference given in the index to many C# keywords points to the keywords appendix, which provides a brief description, but doesn’t give further references.
It is apparent that C# is a language that needs a whole shelf of books to describe with precision. Besides that, the book should serve as an adequate introduction.
References
I did some web searches for other critiques of C#. By far the most common result was a glowing recommendation, typically on the basis of the superiority of C# over Visual Basic. (“It’s so much better than Visual Basic—it’s got objects and everything!”)