(FAQ) C# Frequently Asked Questions Page6
FAQ: C# Frequently Asked Questions Page6
Why don't relational operators return bool as a type?
Section 10.9.2 of the language specification says:
A binary operator must take two parameters, at least one of which must have the class or struct type in which the operator is declared. Parameters of the shift operators (§7.8) are further constrained. A binary operator can return any type.
Why isn't it limited to just returning bool?
There is some weirdness here because of the C# ability to support nullable types, such as the SQL types (ie SQLInt32, SQLSingle, etc.). These type can either have a value or be null.
One of the strange features of the SQL expression syntax is if either operand in a binary operation is null, the result is null. So, when we want to write the comparison operator for SQLInt32, we have a problem if the result type is constrained to bool, since null is neither true or false.
C# therefore allows the comparison operators to return another type as long as the resulting type has operator true and operator false defined. That gives us enough support to be able to write:
SQLInt32 x = ...;
SQLInt32 y = ...;
if (x == y)
{
// x and y or equal
}
else if (x != y)
{
// x and y are not equal
}
else
{
// the result of the comparison is null
}
Which allows the full richness of SQL types to be expressed.
Why doesn't C# support #define macros?
In C++, I can define a macro such as:
#define PRODUCT(x, y, z) x * y * z
and then use it in code:
int a = PRODUCT(3, 2, 1);
C# doesn't allow you to do this. Why?
There are a few reasons why. The first is one of readability.
One of our main design goals for C# is to keep the code very readable. Having the ability to write macros gives the programmer the ability to create their own language - one that doesn't necessarily bear any relation to what the code underneath. To understand what the code does, the user must not only understand how the language works, but he must also understand all of the #define macros that are in effect at that point in time. That makes code much harder to read.
In C#, you can use methods instead of macros, and in most cases, the JIT will inline them, giving you the same performance aspect.
There's also a somewhat more subtle issue. Macros are done textually, which means if I write:
int y = PRODUCT (1 + 2, 3 + 4, 5 + 6)
I would expect to get something that gives me 3 * 7 *11 = 231, but in fact, the expansion as I've defined it gives:
int y = 1 + 2 * 3 + 4 * 5 + 6;
which gives me 33. I can get around that by a judicious application of parenthesis, but its very easy to write a macro that works in some situations and not in others.
Although C# doesn't strictly speaking have a pre-processor, it does have conditional compilation symbols which can be used to affect compilation. These can be defined within code or with parameters to the compiler. The "pre-processing" directives in C# (named solely for consistency with C/C++, despite there being no separate pre-processing step) are (text taken from the ECMA specification):
#define and #undef
Used to define and undefine conditional compilation symbols
#if, #elif, #else and #endif
Used to conditionally skip sections of source code
#line
Used to control line numbers emitted for errors and warnings.
#error and #warning
Used to issue errors and warnings.
#region and #endregion
Used to explicitly mark sections of source code.
See section 9.5 of the ECMA specification for more information on the above. Conditional compilation can also be achieved using the Conditional attribute on a method, so that calls to the method will only be compiled when the appropriate symbol is defined. See section 24.4.2 of the ECMA specifcation for more information on this.
Why don't namespace using directives import nested namespaces?
In C#, when you specify a “using” clause, such as
using System.Text;
the compiler only imports the types in System.Text into the global namespace - it doesn't do the same with any namespaces inside of System.Text. So, while that using allows me to write:
StringBuilder s = new StringBuilder();
it does not allow me to write:
RegularExpressions.Regex r = new RegularExpressions.Regex();
Why?
Well, an early version of the C# compiler had that behavior, but we found that it had a few issues:
First, it made the code harder to follow. In the above example, RegularExpressions.Regex() could be a global name, or a name based on any of my using clauses. Having to look at the top of your code to figure out what a name is is something we'd like to avoid.
The second problem had to do with collisions between namespace names, which occurred much more often with this behavior. If there was another namespace with a RegularExpressions namespace inside of it, the user wouldn't be able to have a “using” statement for both - even if they didn't actually care about that namespace.
We therefore decided to change the behavior.
Why doesn't C# have a power operator?
Some languages provide a power operator, so one can write something like:
float result = value^2;
rather than having to resort to calling. We don't have one in C#.
It would be possible to add a power operator to the language, but performing this operation is a fairly rare thing to do in most programs, and it doesn't seem justified to add an operator when calling Math.Pow() is simple.
I also worry a bit about the implementation of such operators. It seems likely that most compilers would translate my example above to:
float result = Math.Pow(value, 2.0);
That works, but has the unfortunate side effect of replacing a simple multiplication (value * value) with a complex trig function.
Why doesn't C# support multiple inheritance?
This answer is from Chris Brumme via the following post. I've copied the text in here in case the post disappears.
***
There are a number of reasons we don't implement Multiple Implementation Inheritance directly. (As you know, we support Multiple Interface Inheritance).
However, I should point out that it's possible for compilers to create MI for their types inside the CLR. There are a few rough edges if you go down this path: the result is unverifiable, there is no interop with other languages via the CLS, and in V1 and V1.1 you may run into deadlocks with the OS loader lock. (We're fixing that last problem, but the first two problems remain). The technique is to generate some VTables in RVA-based static fields. In order to deposit the addresses of managed methods (which probably haven't been JITted yet), you use the VTFixup construct. This construct is a table of triplets. The triplets consist of a token to a managed method, an address in your image that should be fixed up (in this case, a slot of the VTable you are creating in the RVA-based static), and some flags. The possible flags are described in corhdr.h and they allow you to specify 32- vs. 64-bit pointer sizes, control over virtual behavior, and whether some reverse-PInvoke behavior should be applied in the form of a thunk that eventually dispatches to the managed method. If we are performing an unmanaged->managed transition, you also have some control over which AppDomain should be selected for us to dispatch the call. However, one of these options (COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN) doesn't exist in V1. We added it in V1.1.
There are several reasons we haven't provided a baked-in, verifiable, CLS-compliant version of multiple implementation inheritance:
1. Different languages actually have different expectations for how MI works. For example, how conflicts are resolved and whether duplicate bases are merged or redundant. Before we can implement MI in the CLR, we have to do a survey of all the languages, figure out the common concepts, and decide how to express them in a language-neutral manner. We would also have to decide whether MI belongs in the CLS and what this would mean for languages that don't want this concept (presumably VB.NET, for example). Of course, that's the business we are in as a common language runtime, but we haven't got around to doing it for MI yet.
2. The number of places where MI is truly appropriate is actually quite small. In many cases, multiple interface inheritance can get the job done instead. In other cases, you may be able to use encapsulation and delegation. If we were to add a slightly different construct, like mixins, would that actually be more powerful?
3. Multiple implementation inheritance injects a lot of complexity into the implementation. This complexity impacts casting, layout, dispatch, field access, serialization, identity comparisons, verifiability, reflection, generics, and probably lots of other places.
It's not at all clear that this feature would pay for itself. It's something we are often asked about. It's something we haven't done due diligence on. But my gut tells me that, after we've done a deep examination, we'll still decide to leave the feature unimplemented.
Why doesn't C# support default parameters?
In languages such as C++, a default value can be included as part of the method declaration:
void Process(Employee employee, bool bonus = false)
This method can be called either with:
a.Process(employee, true);
or
a.Process(employee);
in the second case, the parameter bonus is set to false.
C# doesn't have this feature.
One reason we don't have this feature is related to a specific implementation of the feature. In the C++ world, when the user writes:
a.Process(employee);
the compiler generates
a.process(employee, false);
In other words, the compiler takes the default value that is specified in the method prototype and puts it into the method call - it's just as if the user wrote 'false' as the second parameter. There's no way to change that default value without forcing the user of the class to recompile, which is unfortunate.
The overloading model works better in this respect. The framework author just defines two separate methods, and the single-parameter one calls the two-parameter method. This keeps the default value in the framework, where it can be modified if necessary.
It would be possible for a compiler to take something like the C++ definition and produce the overloads, but there are a few issues with that approach.
The first one is that the correlation between the code that the user writes and the code the compiler generates is less obvious. We generally try to limit magic when possible, as it makes it harder for programmers. The second issue has to do with things like XML doc comments and intellisense. The compiler would have to have special rules for how it generates doc comments for the overloaded methods, and intellisense would need to have smarts to collapse the overloaded methods into a single method.
Writing overloads yourself is a bit less convenient, but we think it's an acceptable solution.
Ask a FAQ Question
Do you have a FAQ about:
* The C# Language or compiler
* The C# IDE
* The Visual Studio debugger
Reply to this post, and your question will be added to our list to be answered. Of course, depending on the nature of your comment, and the volume we receive, we may not get to every question.
Note that if your question is not about C# specifically (if it is, for example, a Windows Forms question or a general question about the .NET Framework), it would be better to post that question to a newsgroup or web forum. Visit http://msdn.microsoft.com/vcsharp/community/ for a listing of related resources.
- guru's blog
- Login or register to post comments

