52

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.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Andrew Garrison
  • 6,977
  • 11
  • 50
  • 77
  • 27
    I can answer in three words (plus a trademark): Macros Are Evil™ – Randolpho Sep 02 '09 at 19:52
  • 2
    Yeah, honestly, there is little reason to use macros these days in most C++ code. – Ed S. Sep 02 '09 at 19:56
  • 3
    Lots of good answers there, so just an aside--C# is not derived from C or C++, it was derived from Java. Java was only loosely based on C/C++ and tried to eliminate many of the bad parts (of which macros and the entire pre-processor are possibly the biggest). The naming seems to mislead people--and also the fact that the language has added features at a much quicker pace than Java... – Bill K Sep 02 '09 at 20:29
  • 14
    Macros are great! The flexibility they allow is awesome. Sure they allow you to shoot yourself in the foot, but abhorring them completely is a mistake in my opinion. – Andrew Garrison Sep 02 '09 at 20:33
  • 1
    @Andrew: Perhaps you could show us an example of a situation where macros are a good solution? Otherwise, it seems like you're very much in the minority. Every other C++ developer hates macros. I personally can't remember the last time I even considered using a macro in C++. There are just always better solutions. Which is why other languages don't add macros. – jalf Sep 02 '09 at 20:50
  • @jalf: When are macros a good solution? This has already been asked and answered: http://stackoverflow.com/questions/96196/when-are-c-macros-beneficial – Andrew Garrison Sep 02 '09 at 22:30
  • 1
    @Andrew: Most of those don't apply *at all* to C#. In my 10+ years of industry coding, the "flexibility" of the C/C++ preprocessor is the single largest source of illegible code. C# got it right with directives 1) strictly used for conditional compilation 2) only allowing `#define` as the first item in a file and 3) not "leaking" directives across files. – Sam Harwell Sep 03 '09 at 01:41
  • See: Extension Methods. The 'gist' of the C# team I get is they try to reach parity, but in type safe and predictable ways (just look at generics, not as versatile as templates, but much 'nicer'). Extension methods seem like a macro stop-gap to me. – Jonathan Dickinson Jul 18 '11 at 14:32
  • 1. Judging macros by languages like C++ isn't really fair, take a look at macros in LISP. 2. C# has Expression trees, dynamic types, and run-time proxies, that allow you to reinterpret code at run-time. 3. DSL's are a very powerful tool... not sure if a good one though... – AK_ Jun 05 '12 at 12:39
  • 1
    Macros indeed are great for some stuff, it's a shame C# doesn't have them. For example they allow you to easily write a code that gets it into the binary only with certain compiler flags and is completely stripped out for production builds, thus enhances the flexibility and performance, but that is something (performance) what C# as well as java generally suck in. Perhaps lack of macros is one of reasons for that. (C# allows you to do similar stuff, but you need to wrap such code with #if on all places instead of being able to write 1 line code which eventually expand to something) – Petr Jul 29 '14 at 15:43
  • Those familiar with Unity have often encountered code like `gameObject.GetComponent().Play(Anim.Opening);`. Now I'd have wanted to just type `animator.Play(Anim.Opening)` in the script of the current `GameObject` instance and everybody would know which `Animator` it's all about. This is just one example of many. And here you cannot use a method. Generally code abbreviation is a basic useful feature. It's destructive to deny an arguably useful feature just because some reckless people use it in the wrong way. This would mean that knives and other dangerous tools be ceased to be made. – mireazma Feb 04 '16 at 22:51
  • Macros are a powerful way to generate repetitive code. C# projects are often riddled with boilerplate, or have it generated by external code generators which complicate the build and are basically macro systems. – David Jeske Jun 15 '16 at 02:42

11 Answers11

72

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
  • 1,216
  • 9
  • 12
  • 1
    Thanks Hank, was wondering why it didn't look like what I had copied and pasted. – DouglasH Sep 02 '09 at 19:58
  • 2
    I thank the Lord every day that I don't have to debug a program with copious quantities of obscure macros. Is there any reason to use them for which simple good-programming-practices wouldn't suffice? – weberc2 Oct 25 '12 at 20:41
  • 4
    Here's one: WinError.h . If I want to be able to determine what a WIN32 error means in C#, I have to go find a copy of WinError.h somewhere, hack it into a C# class with literally thousands of constants (or find such an already-hacked class,) and deal with the fact that my output assembly just grew from 45k to 180k because of something that would have added exactly 0k in a language with a preprocessor. Furthermore, if this code gets built in the future for a newer (or otherwise different) version of Windows, I have to go find its WinError.h and hack it similarly with a similar code size jump. – reirab Sep 25 '13 at 20:02
  • 5
    it's very funny that c# forbids c like macros because they are evil, but a very CIL interpretor, written in c uses them in source code... what a hypocracy – Petr Jul 30 '14 at 17:46
  • Forgive my blasphemy but I find accessories just as evil as macros; you think you merely access a field. So you go using this mindlessly. Then you find out that in fact there's tens times more worth of computation stuff going on in the getter/setter. And this is sometimes justified exclusively by "good practice". – mireazma Feb 07 '16 at 11:26
  • 1
    I think the designers of C# broke their readability rule by reflection. XAML bindings can be extremely difficult to "read". – Sam Hobbs Dec 01 '16 at 20:42
44

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
  • 457
  • 4
  • 2
28

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
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 3
    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 Sep 02 '09 at 19:56
  • 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 Sep 02 '09 at 20:05
  • 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 Sep 02 '09 at 20:10
  • 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 Sep 02 '09 at 20:56
  • 1
    Macros enable or support certain tricks in c / c++ but they are really just a sign of the developer wants something supported by the compiler which currently is not – Blair Davidson May 14 '13 at 12:18
  • 1
    @BobbyCannon There are plenty of good uses of #define in the Linux Kernel, OpenCV, etc. For example, in OpenCV, if you want to add a test case, you use the macro TEST and define a function for the test. I can see your preference is without macros, but there are definitely good uses for it in my opinion. – user1132959 Mar 12 '14 at 15:47
  • @BlairDavidson: I agree, but that is precisely the point with macros. You can't expect the compiler to support everything you may want in advance. – Dolda2000 Aug 23 '14 at 02:49
  • @BlairDavidson Actually macros are something the language and compiler supports in C/C++ so the develop is just sensibly using tools they have available. Macros are part of those languages, not a kludge bolted on. – StephenG - Help Ukraine May 14 '18 at 10:32
  • Well, in Java we use preprocessor tags for compiler fun with things like Lombok. If instructing the compiler was officially supported, Lombok could do all its magic hackery much easier, and you could do it too in a simple manner. – Haakon Løtveit Oct 08 '18 at 11:27
  • C/C++ macros are a souped-up text replace. Lisp-style macros are a replace on the AST, doable w/ Roslyn. But to realize the full power of Lisp-macros, you may have to enable a temp. override of C# syntax, & also enable the full language at macro-time. This is the difference between a language that is more static to begin with, & a language meant to be extended in just about any way, enabling much easier DSL creation and code-as-data, which is what we want to do with macros. But I want to be able to turn that paradigm on or off at will per file & use that great code-gen power in a Spartan way. – MicroservicesOnDDD Oct 08 '20 at 22:47
11

C# is aimed at wider audience (or in other term, consumer base) than C++, C or ASM. The only way of achieving this goal is reaching programmers considerably less skilled. Therefore, all the powerful but dangerous tools are taken away. I.e. macros, multiple inheritance, control over object lifetime or type-agnostic programming.

In a very same way matches, knives and nailguns are useful and necessary, but they have to be kept out of reach of children. (sadly, arsons, murders, memory leaks and unreadable code still do happen).

And before accusing me of not thinking C#, how many times have you wrote that:

protected int _PropOne;
public int PropOne
{
    get
    {
        return _PropOne;
    }
    set
    {
        if(value == _PropOne) { return; }
        NotifyPropertyChanging("PropOne");
        _PropOne = value;
        NotifyPropertyChanged("PropOne");
    }
}

With macros, every time those 16 lines would look like that:

DECLARE_PROPERTY(int, PropOne)
DECLARE_PROPERTY(string, PropTwo)
DECLARE_PROPERTY(BitmapImage, PropThree)
David Jeske
  • 2,306
  • 24
  • 29
Agent_L
  • 4,960
  • 28
  • 30
  • it seems your definition of "skilled" implies not making mistakes. If that's the case, a "skilled" programmer wouldn't leverage high level programming constructs, and would be working with raw addresses rather than variables. While the code you provided is certainly simpler, it will defeat most debugging tools. Please note that your final point hinges upon writing the macro "properly" in the first place. If we're capable of writing "proper" code all the time, then we wouldn't make a mistake for a "proper" macro to catch. At least without macros, we can quickly debug. – weberc2 Oct 26 '12 at 16:37
  • 1
    @weberc2 Not at all. "Skilled" in my dictionary means "capable of writing readable code", including bug-free macros and knowing when to use them and when not. The "skill" of writing a macro is to write the code, debug it and then extract it into a macro. Macros are for extracting code that is 100% dependable and need not to be debugged. I assure you that macros are not a problem when debugging, unless specifically targeted at making code unreadable. And you're wrong: debugging mistaken property name in string NotifyPropertyChanging is difficult. This is a real world example. – Agent_L Oct 26 '12 at 17:44
  • Code readability is for novices, not just macro-using experts. Macros literally insert one language into another language, and to make matters worse, the two aren't easily distinguishable. Moreover, even a skilled programmer makes mistakes, meaning your macros may still need to be debugged (even if your macro doesn't contain the mistake, we often don't know that until it's been examined). Given that macros are difficult to difficult to debug. Even in your example, it's easier to read and debug the C# code (as the debugger can access it) than your macro (which a debugger can't access). – weberc2 Oct 29 '12 at 21:46
  • furthermore, it looks like the C# code in your example can be simplified by putting the contents of the set{} into a static method that encapsulates the checking. Then you don't have to deal with tedious macros and everyone looking at the code can still easily understand what's going on. Using macros is almost always more costly than beneficial, although I'm sure there are dozen of examples where this isn't the case. – weberc2 Oct 29 '12 at 21:50
  • @weberc2 It seems that we just calculate costs differently. If you know ANY method of simplifying NofityPropertyChanged (other than VS code generating templates) please do tell me, because this overhead is killing me and everybody else I work with. I'm sorry but your suggestion about static method is nonsense. The problem lies in tying string containing property name with the name of property itself. As far as my knowledge goes, that's not possible without macros. – Agent_L Oct 31 '12 at 14:01
  • 2
    @weberc2 Sorry, mate, but you've just proven yourself to be antimacro fanatic who denies it's value even when hit with it in the face. I can't argue with someone who claims that debugging a macro is harder than debugging a string - which is not possible at all, as far as I know. – Agent_L Oct 31 '12 at 14:03
  • I'm not particularly familiar with NotifyPropertyChanged; however, since it uses a string to identify a property, I would think there must be a better way of providing said notification. If I'm right, the macro is still just another instance of using bad practice to try to compensate for bad practice. – weberc2 Oct 31 '12 at 15:57
  • I'm sorry, you're still incorrect. Macros are still just another shortcut feature that do more harm than good. When you're using them to skirt the quality-enforcing constraints of a language, you're doing it wrong. Providing for macros sabotages the reliability of those constraints. If you're going to invest the time into developing a macro to add safety to a poorly-designed function, you're better off redesigning/writing the function. – weberc2 Oct 31 '12 at 16:20
  • There are a handful of scenarios (e.g. conditional compilation) for which default language features can't be the answer, and for which I don't know of better solutions than macros (i.e., I haven't spent any time trying to think of better alternatives), but in 99.9% of use cases, macros are the wrong tool, and it's astronomically better that they aren't provided for in the first place. For the other 0.01% of scenarios, you can always write in the macro and use a preprocessor. – weberc2 Oct 31 '12 at 16:21
  • 1
    @weberc2 I am talking about INotifyPropertyChanged interface and its PropertyChangedEventArgs which has defined PropertyName as string by Microsoft. It's absolute basics, required in any app with dynamic user interface written with Forms (or Linq2SQL). Since you're not familiar with it, then why are you participating in a discussion on a topic you have no idea about? What you don't know is that there are hundreds of such blocks in most applications, and slightest error in "PropNameOne" generates elusive and absolutely undebuggable problem. – Agent_L Oct 31 '12 at 17:20
  • @weberc2 There you go: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged%28v=vs.90%29.aspx – Agent_L Oct 31 '12 at 17:20
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/18871/discussion-between-weberc2-and-agent-l) – weberc2 Oct 31 '12 at 17:27
6

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
  • 45,033
  • 10
  • 85
  • 120
2

As a long time C# programmer who went off to learn C++ for a while, I now miss rich support for metaprogramming C#. At least, I now have a more expansive appreciation for what metaprogramming can mean.

I would really like to see the kind of macro support that's instilled in Nemerle in C#. It seems to add a very natural and powerful extension capability to the language. If you haven't looked at it, I really recommend doing so.

There are some great examples on Wikipedia.

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
1

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.

Community
  • 1
  • 1
Motti
  • 110,860
  • 49
  • 189
  • 262
1

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
  • 13,144
  • 12
  • 92
  • 130
0

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
  • 18,086
  • 12
  • 58
  • 77
0

Anyone who agrees with the idea that macros are bad should read the book, "With Folded Hands." http://en.wikipedia.org/wiki/With_Folded_Hands It tells a story about how we can keep people from doing stupid things all the way to the point of preventing them from doing very wise things.

While I like C#, I do really hate that it contributes to the stupidification of actual software engineers. So, yes, leave macros to the professionals. While we're at it, leave the naming of variables to professionals, too. That can make for some really unreadable code. To follow the full statement of "code must be ultimately readable" all variables should be named A-Z, followed by a-z (or some other arbitrary construct like only nouns). Because some unskilled person may name their variable "SomethingUsefulButNotAllowedByTheCompilerBecauseSomeUsersMayDoDumbThings".

-1

You can do some thing you do with macros like PropertyChanged with ways like this

If thats better than macros ? Thats a question YOU must decide :)

Vidya Sagar
  • 1,699
  • 3
  • 17
  • 28
Chaka
  • 377
  • 1
  • 9