[ACCEPTED]-Syntactic sugar in C/C++-syntactic-sugar

Accepted answer
Score: 111

Can anyone suggest a better alternative?

Yes. Don't 5 do this at all. Just use the while and if statements 4 directly.

When you're programming in C or 3 C++, program in C or C++. While until and unless might 2 be used frequently and idiomatic in some 1 languages, they are not in C or C++.

Score: 17

The way you did it seems to me the correct 40 way to do it, if you're going to do it at 39 all. Because the expansion of the macro 38 is so similar to what you'd expect[1], I think 37 it's valid to make the macro look like syntax 36 (), rather than the usually recommended 35 SCARY_UPPERCASE_MACROS() which are used 34 to show that this code doesn't follow usual 33 syntax and you should only use it carefully.

[1] The 32 only flaw being the inability to declare 31 variables, which is unlikely anyway, and 30 likely to produce an error in the right 29 place when used incorrectly, rather than 28 doing something weird.

Furthermore, even 27 small increases in readability are important, so 26 being able to say until ( instead of while (! really does 25 make it easier to read many loops. If the 24 ending condition is more easily thought 23 of as an exceptional condition (regardless 22 of whether it is or not) writing the loop 21 that way round makes it easier to read. So 20 even though it is only syntactic sugar, I 19 think there's reason to consider it.

However I don't 18 think it's worth it. The benefit is small, since 17 most programmers are used to reading if (! and 16 the cost is real: Anyone reading the code 15 will have to check whether this a macro, or 14 a custom compiler, and whether or no it 13 does what they think. And it may misleadingly 12 make you think you can do things like i=5 unless xxxx;. Such 11 little improvements, if widespread, would 10 fragment the language, so often it's best 9 to do things the standard way, and adopt 8 improvements slowly.

However, it can be done 7 well: the entirety of boost and tr1, especially 6 the stuff done with templates to look like 5 extensions to the library, involves extending 4 C++ in various ways, many of which aren't 3 adopted as they didn't seem worth it, but 2 many of which have small or very widespread 1 take-up because they made real improvements.

Score: 14

This reminded me of something I have seen 3 in someone's code:

#define R return;

Besides, making the code 2 hard to comprehend, you increase maintenance 1 costs.

Score: 8

I suggest it would be better not use them.

You 4 cannot use them in Ruby style as

`printf("hello,world") unless(a>0);`

is illegal.

And 3 it would be more difficult for C programmers 2 to understand the code. Meanwhile the extra 1 macro could be a problem.

Score: 5

If you're going to define macros, it's good 11 practise to make them look really ugly. In 10 particular, they should be all-capitals, and 9 have some kind of prefix. This is because 8 there is no namespacing and no coordination 7 with the type system or overload resolution 6 of C++.

So if your macro was called BIGYAN_UNNECESSARY_MACRO_UNTIL then 5 it would be not quite "beyond the pale".

If 4 you want to extend C++ with new looping 3 constructs, consider investigating lambdas 2 in C++0x, where you could allow:

until([&] { return finished; }, [&] 
    // do stuff

It's not 1 perfect, but it's better than macros.

Score: 5

I don't think your macros are bad in particular 8 if they are used only in your own code base. This article might 7 be interesting for you. That being said, I 6 see some downsides in your macros when we 5 use them in C++.
For example, we cannot 4 write as:

until (T* p = f(x)) ...
unless (T* p = f(x)) ...

on the other hand, we can write 3 as:

while (T* p = f(x)) ...
if (T* p = f(x)) ...

As for unless, if we define it as:

#define unless(x) if (x) {} else

then we can 2 write unless (T* p = f(x)) .... However, in this case we cannot add 1 else clause after it.

Score: 2

Look at how boost foreach is done.

The header 8 defines BOOST_FOREACH (the ugly, prefixed 7 macro). You can

#define foreach BOOST_FOREACH

in you .cpp files in order 6 to have cleaner code. You should not do 5 it in your .h files however and use the 4 ugly BOOST_FOREACH instead.

Now, here is 3 a set of “functional-programming-ish” macros 2 for “convenient” IF THEN ELSE expressions 1 (because ?: is ugly):

#define IF(x) (x) ?
#define ELSE :


int x = IF(y==0) 1
        ELSE IF(y<0) 2*y
        ELSE 3*y;

desugarises into:

int x = (y==0) ? 1 : (y<0) ? 2*y : 3*y;
Score: 2

Good syntax sugar example (IMHO):

struct Foo {
    void bar() {}
typedef std::vector<Foo*> FooVector;
typedef boost::ptr_vector<Foo> FooPtrVector;

FooVector v1;
for (FooVector::iterator it = v1.begin(); it != v1.end(); ++it)
    (*it)->bar(); // ugly

FooPtrVector v2;
for (FooPtrVector::iterator it = v2.begin(); it != v2.end(); ++it)
    it->bar(); // nice


Score: 1

As peoples said, adding those word do not 31 really offer a useful syntactic sugar, because 30 the cost to read a while ( or a if (! is 29 small, all C developers are used to, and 28 using such macro you'll scary most of the 27 C developers. Also, making a language look 26 like an other isn't a good idea.

BUT, syntactic 25 sugar matters. As already stated, in C++, boost 24 add lot's of syntactic sugar through templates, and 23 the stl also provide Somme sugar (for example, std::make_pair(a, b) is 22 a syntactic sugar for std::pair<decltype(a), decltype(b)>(a, b).

As a language improve, both 21 functionalities and syntactic sugar are 20 added to improve readability, writability, and 19 efficiency of developers. For example, with 18 the C++11 spec, the "for (elements 17 in datastructure)" was added (see below), and 16 also the "auto" keyword which 15 allow a week inference of types (I say weak 14 because you need to type a lot's of types 13 at a lots of places where the type is actually 12 'obvious' and redundant).

Also, in haskell, using 11 monads without the do notation (syntactic 10 sugar) would be a real pain, and no-one 9 would be using them1.

An example without syntactic 8 sugar:

//C++ < 11
std::vector<int> v;
for (std::vector<int>::iterator it = v.begin();
     it != v.end();
    std::cout << *it << std::endl;

And with syntactic sugar:

//C++ >= 11
std::vector<int> v {3, 7, 9, 12};

for (auto elm : v)
    std::cout << elm << std::endl;

A bit more 7 readable, no?

An haskell example for the 6 IO monad (from HaskellWiki) :

f :: IO String
f =
  ask "What's your name ?" >>= \name ->
  putStrLn "Write something." >>= \_ ->
  getLine >>= \string ->
  putStrLn ("Hello " ++ name ++ " you wrote " ++ string) >>= \_ ->
  return name

g :: IO String    
g = do
  name <- ask "What's your name ?"
  putStrLn "Write something."
  string <- getLine
  putStrLn ("Hello " ++ name ++ " you wrote " ++ string)
  return name

Here is a link to ideone 5 : http://ideone.com/v9BqiZ

1: Actually, the language is more flexible 4 than C++ and allow creating operators (for 3 example &^, +., :+:, ...), so we could 2 imagine that someone would quickly introduce 1 syntactic sugar again :).

More Related questions