7

I'm sure I'll get 20 people saying "why would you want to do that anyways"... but, I'm going to ask my question none-the-less because it's somewhat academic in nature.

I'd like to use C macros to redefine [ClassName new] into something like: new(ClassName), and I'm wondering how to do this. I'm not super comfortable with C macros to begin with (I know - embarrassing - I should be) - and I'm definitely not comfortable mixing them in with my Objective-C code. So, on with the question...

First, being it's a preprocessor thing, can I do a simple substitution like such:

#define new(x) [x new]

or, for whatever reason, do I need to drop down to the objective-c runtime, and do something more akin to:

#define new(x) objc_msgSend(class_createInstance(x, 0), sel_registerName("init"))

What are the downfalls of doing something like this?

Is this kind of thing used often by others, or, would someone look at it and say "what the heck are you doing there"? (and should I care)

Thanks

EDIT:

It occurred to me after posting this, that I have, in fact, see this kind of thing before - in the Three20 lib, where they do things like this:

#define TT_RELEASE_SAFELY(__POINTER) { [__POINTER release]; __POINTER = nil; }
#define TT_INVALIDATE_TIMER(__TIMER) { [__TIMER invalidate]; __TIMER = nil; }

// Release a CoreFoundation object safely.
#define TT_RELEASE_CF_SAFELY(__REF) { if (nil != (__REF)) { CFRelease(__REF); __REF = nil; } }

So probably my question becomes simply; What are the downfalls of doing this, and is it a relatively accepted practice, or something that's going to get me into more trouble than it's worth?

Steve
  • 31,144
  • 19
  • 99
  • 122
  • Regarding how it would be recieved... well, C programmers [don't like `#define begin {`](http://stackoverflow.com/questions/652788/what-is-the-worst-real-world-macros-pre-processor-abuse-youve-ever-come-across/652820#652820) (and there are more examples in that thread), so they probably won't like this either. And I have sympathy. –  Oct 28 '11 at 20:12
  • @delnan - Thanks for the link! I do feel like my specific example is more in keeping with the intent of macros than some of the examples cited in that thread... and I've seen macros used like this for release (see Three20 which uses that wacky `TT_RELEASE_SAFELY` or whatever it's called). – Steve Oct 28 '11 at 20:23

3 Answers3

3

C macros are guaranteed

  • not to be recursive
  • not to expand functionlike macros that are not followed by ()

so your first variant would be ok for the C preprocessor. The only identifiers that are reserved (so you couldn't use for macro names) are keywords and identifiers starting with underscore. new is neither keyword (for C) nor starting with an underscore, so this is fine for the C preprocessor.

I don't know if the objective-C imposes other restrictions, you'd have to look that up.

And yes I am definitively the guy who asks "why would you want to do that anyways?". Don't do that, don't even think of doing that, if on the other hand you feel the need to ask your question.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
3

Macros are processed first, and they are operating on the plain text source code. So yes, you can have your new macro generate Objective-C syntax or plain C syntax or even invalid syntax if you like.

The downfalls of using a macro in general is that, because it is parsed and processed in a separate step, it's possible to write macros that don't behave how you expect even when everything looks fine.

For example, this macro:

#define MAX(x,y) x > y ? x : y

Looks OK, but say you used it like this:

z = MAX(a,MAX(b,c));

It would be expanded by the preprocessor into something like this:

z = a > b > c ? b : c ? a : b > c ? b : c;

Which won't actually give you the max of the three arguments. To solve this you need to liberally sprinkle parenthesis in your macro definition, even where you don't think it is needed:

#define MAX(x,y) ((x) > (y) ? (x) : (y));

That fixes it, except I added a semicolon to the end, which is an understandable habit from writing a lot of C code, except now our macro expands to:

z = ((a) > (((b) > (c) ? (b) : (c));) ? (a) : (((b) > (c) ? (b) : (c));));;

Syntax errors!

If you look at how MAX is actually defined in Objective-C, it's pretty mess, but that's what you have to do to write macros safely. And you also need to consider that:

z = MAX(expensiveComputation(), reallyExpensiveComputation())

Will, unlike a function, actually execute one of those functions twice, unless you use a trick in your macro to basically emulate parameter passing.

So, to answer your question, yes it is totally possible, but writing safe macros is really hard. And you're doing this so you can pretend your Objective-C code is actually code in another language... Why would you want to do that, anyways?

benzado
  • 82,288
  • 22
  • 110
  • 138
1

Assuming you are using a recent GCC (that is a 4.6 version), you might consider making a GCC plugin, or preferably a GCC MELT extension, for such a task. MELT is a high-level domain specific language to easily extend GCC.

For instance, your new macro would be

#define new(X) _mybuiltin_new_(X)

and then your MELT extension would add a new GCC builtin _mybuiltin_new_ which would be transformed into some simpler Gimple (the internal representation used by GCC). However, these kind of things take some time (a week at least, not hours) to be developed.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547