tags:

views:

759

answers:

7

When learning C# for the first time, I was astonished that they had no support for macros in the same capacity that exists in C/C++. I realize that the #define keyword exists in C#, but it is greatly lacking compared to what I grew to love in C/C++. Does anyone know why real macros are missing from C#?

I apologize if this question is already asked in some form or another - I promise I spent a solid 5 minutes looking for duplicates before posting.

+20  A: 

C++-style macros add a huge amount of complexity without corresponding benefit, in my experience. I certainly haven't missed them either in C# or Java. (I rarely use preprocessor symbols at all in C#, but I'm occasionally glad they're there.)

Now various people have called for Lisp-style macros, which I know little about but certainly sound rather more pleasant than C++-style ones.

What do you particularly want to do with macros? We may be able to help you think in a more idiomatically C# way...

Jon Skeet
I hate #define macros. I am soooooo glad C# doesn't support such macros. I actually have never seen a good use of #define.
Bobby Cannon
There are plenty of good (or at least necessary) uses of #define in C. In C++, they're primarily useful to support conditional compilation, and any other use is probably a bad idea.
David Thornley
Jon, a fully working code gen built into the language, what a novel concept:) hopefully one that is not designed to output exactly C# as the Codedom is now. +1
DouglasH
I voted up, but I'm going to point a minor contradiction - "I used C 12 years ago but it had no affect me".
Chris S
@Chris: Could you elaborate?
Jon Skeet
+29  A: 

from the C# faq.

http://blogs.msdn.com/CSharpFAQ/archive/2004/03/09/86979.aspx

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.

Author: Eric Gunnerson

DouglasH
Word of God is always good in a question like this. +1
Randolpho
You may want to escape some of that formatting: \#
Henk Holterman
Thanks Hank, was wondering why it didn't look like what I had copied and pasted.
DouglasH
thanks for the format. removed the \ that escaped earlier.
DouglasH
+3  A: 

Macros in C / C++ were used to define constants, produce small inline functions, and for various things directly related to compiling the code (#ifdef).

In C#, you have strongly typed constants, a smart enough compiler to inline functions when necessary, and knows how to compile stuff the right way (no precompiled header nonsense).

But there's no particular reason why you couldn't run your CS file through the C preprocessor first if you really wanted to :)

Seth
Good point. Nothing is stopping using the C preprocessor if you really want.
Matthew Lock
+1  A: 

Macros are overused in C++ but they still have their uses, however most of these uses are not relevant in C# due to reflection and the better integrated use of exceptions for error reporting.

Motti
A: 

Macros are a tool for the days when most programmers were smarter than the compiler. In C/C++, there are still some cases where this is true.

Nowdays, most programmers aren't as smart as the C# compiler/runtime.

Imagist
so are compilers getting smarter, or programmers getting dumber?
Jeff Atwood
+1  A: 

This article compares perl and lisp macros but the point is still the same: Text level macros (perl/c++) cause massive problems compared to source level macros (lisp)

http://lists.warhead.org.uk/pipermail/iwe/2005-July/000130.html

Braver people than me have rolled their own macro like system in c# http://www.codeproject.com/KB/recipes/prepro.aspx

Matthew Lock
+1  A: 

So that you can have fun typing THIS over and over and over again.

// Windows presetation foundation dependency property.
public class MyStateControl : ButtonBase
{
  public MyStateControl() : base() { }
  public Boolean State
  {
    get { return (Boolean)this.GetValue(StateProperty); }
    set { this.SetValue(StateProperty, value); } 
  }
  public static readonly DependencyProperty StateProperty = DependencyProperty.Register(
    "State", typeof(Boolean), typeof(MyStateControl),new PropertyMetadata(false));
}

Obviously the designers of C# and .NET never actually use any of the libraries or frameworks they create. If they did, they would realize that some form of hygenic syntactic macro system is definitely in order.

Don't let the shortcomings of C and C++'s lame macros sour you on the power of compile time resolved code. Compile time resolution and code generation allows you to more effectively express the MEANING and INTENT of code without having to spell out all of the niggling details of the source code. For example, what if you could replace the above with this:

public class MyStateControl : ButtonBase
{
  public MyStateControl() : base() { }

  [DependencyProperty(DefaultValue=true)] 
  bool State { get; set; }
}

Boo has them, OcamML (at least Meta ML) has them, and C and C++ has them (in a nasty form, but better than not having them at all). C# doesn't.

bencooley