Avoiding evil macros

  • Thread starter Cephalobus_alienus
  • Start date
C

Cephalobus_alienus

Hello,

I know that macros are evil, but I recently came across a problem
that I couldn't figure out how to solve with templates.

I wanted to create a set of singleton event objects, and wrote the
following macro:

#define GET_SINGLETON_EVENT_FUNCTION(FUNCTION_NAME,MANUAL_RESET,\
INITIAL_STATE,EVENT_NAME) \
HANDLE FUNCTION_NAME() \
{ \
static HANDLE Event; \
if (0 == Event) \
{ \
Event = CreateEvent(NULL, MANUAL_RESET, INITIAL_STATE, \
EVENT_NAME); \
} \
return Event; \
}

This allowed me to generate the singleton code via macro calls:
GET_SINGLETON_EVENT_FUNCTION(BitBltLock, FALSE, TRUE, "BitBltLock" )
GET_SINGLETON_EVENT_FUNCTION(BlockOnBitBlt, FALSE, TRUE,
"BlockOnBitBlt" )
etc. etc.

Please help me to be less evil! };>

Thanks,
Jerry
 
V

Victor Bazarov

I know that macros are evil, but I recently came across a problem
that I couldn't figure out how to solve with templates.

I wanted to create a set of singleton event objects, and wrote the
following macro:

#define GET_SINGLETON_EVENT_FUNCTION(FUNCTION_NAME,MANUAL_RESET,\
INITIAL_STATE,EVENT_NAME) \
HANDLE FUNCTION_NAME() \
{ \
static HANDLE Event; \
if (0 == Event) \
{ \
Event = CreateEvent(NULL, MANUAL_RESET, INITIAL_STATE, \
EVENT_NAME); \
} \

Testing is totally unnecessary. Just initialise your 'Event' with
this expression and the sheer fact that 'Event' is static provides
that the initialisation is going to be done only once (provided
that the initialisation does not fail).
return Event; \
}

This allowed me to generate the singleton code via macro calls:
GET_SINGLETON_EVENT_FUNCTION(BitBltLock, FALSE, TRUE, "BitBltLock" )
GET_SINGLETON_EVENT_FUNCTION(BlockOnBitBlt, FALSE, TRUE,
"BlockOnBitBlt" )
etc. etc.

Please help me to be less evil! };>

Macros are tools for code generation like what you wrote here. How
would you use templates to generate a function and give it a name
different from the name of the function template?

V
 
C

Cephalobus_alienus

Victor said:
Testing is totally unnecessary. Just initialise your 'Event' with
this expression and the sheer fact that 'Event' is static provides
that the initialisation is going to be done only once (provided
that the initialisation does not fail).

My code is running alongside other applications that are leaky
resource hogs, and every few hours, CreateEvent fails resulting in
my application throwing an exception. CreateSemaphore and CreateMutex
also periodically fail.

It is quite true, that if a named synchronization object already
exists, that CreateEvent, etc. are -supposed- to return a handle to
the already existing object.

In the environment that I'm running under, however, this just isn't
true. I want to limit myself to a fixed maximum number of handles,
and the code, once running, should run forever despite the presence
of other, ill-behaved applications.
Macros are tools for code generation like what you wrote here. How
would you use templates to generate a function and give it a name
different from the name of the function template?

I couldn't figure out any way. So you're saying there isn't any.

Thanks,
Jerry
 
P

Phlip

Cephalobus_alienus said:
This allowed me to generate the singleton code via macro calls: ....
Please help me to be less evil! };>

Don't use singletons. They are not just a hallowed form of Global!
 
V

Victor Bazarov

I couldn't figure out any way. So you're saying there isn't any.

Function templates have their names already. Variations are possible
if you vary the types or the values (like addresses of objects with
external linkage or integral values or enums). If you wanted to insert
members with particular names into your classes so that later those
members could be called by some other code, perhaps you should look at
policies (and programming with policies). You would need to pre-define
all those names and values of course, but you already do that, I guess,
when you design your event mechanism.

Something like

template<BOOL manual_reset, BOOL initial_state>
struct BitBltLock {
HANDLE getBitBltLock () {
static HANDLE E = CreateEvent(NULL, manual_reset,
initial_state, "BitBltLock");
return E;
}
};

template<BOOL manual_reset, BOOL initial_state>
struct BlockOnBitBlt{
HANDLE getBlockOnBitBlt() {
static HANDLE E = CreateEvent(NULL, manual_reset,
initial_state, "BlockOnBitBlt");
return E;
}
};

....
class MyClass : public BitBltLock<FALSE,TRUE>,
public BlockOnBitBlt<FALSE,TRUE> /* other bases */ {
...

And you'd use it like this:

MyClass myObject;
..
.. myObject.getBitBltLock() ..
..
.. myObject.getBlockOnBitBlt() ..

Now, whether it's better or not, I don't know. You can also use macros
to generate the templates themselves, of course...

V
 
P

Phlip

Cephalobus_alienus said:
I have some special circumstances that need to be taken
into account.

Okay. Just make them private to a module, and don't call them "singletons".

Use macros for...

- conditional compilation
- built-in macros like __LINE__
- stringerization
- token pasting

If you need those, you need macros. You might still pull lines out of the
macro, so it calls non-macro things. But that's hardly a victory.
 
N

Noah Roberts

Hello,

I know that macros are evil, but I recently came across a problem
that I couldn't figure out how to solve with templates.
Please help me to be less evil! };>

I'll never understand why people feel that macros are so bad that they
will work so hard at comming up with some convoluted template mess to
replace them just because they don't like them for some reason. Yes,
there are times when using a macro is to be avoided. We no longer use
them to create inline functions, as we have those already, and we no
longer use them to define magic numbers because constant values are
safer. That is a far cry from saying they must never be used no matter
how difficult it is to accomplish tasks without them. Just look at how
much they are used in template metaprogramming tasks.

Avoiding macros because of reasoning like this is like trying to come
up with some way to do X task in Perl just because you like the
language...even if task X would be more easily accomplished in some
other language. There is nothing rational behind it.
 
G

Gianni Mariani

Hello,

I know that macros are evil, but I recently came across a problem
that I couldn't figure out how to solve with templates.

I wanted to create a set of singleton event objects, and wrote the
following macro:

#define GET_SINGLETON_EVENT_FUNCTION(FUNCTION_NAME,MANUAL_RESET,\
INITIAL_STATE,EVENT_NAME) \
HANDLE FUNCTION_NAME() \
{ \
static HANDLE Event; \
if (0 == Event) \
{ \
Event = CreateEvent(NULL, MANUAL_RESET, INITIAL_STATE, \
EVENT_NAME); \
} \
return Event; \
}

This allowed me to generate the singleton code via macro calls:
GET_SINGLETON_EVENT_FUNCTION(BitBltLock, FALSE, TRUE, "BitBltLock" )
GET_SINGLETON_EVENT_FUNCTION(BlockOnBitBlt, FALSE, TRUE,
"BlockOnBitBlt" )
etc. etc.

Please help me to be less evil! };>

You could remove one parameter:

#define GET_SINGLETON_EVENT_FUNCTION(FUNCTION_NAME,MANUAL_RESET,\
INITIAL_STATE) \
HANDLE FUNCTION_NAME() \
{ \
static HANDLE Event; \
if (0 == Event) \
{ \
Event = CreateEvent(NULL, MANUAL_RESET, INITIAL_STATE, \
#FUNCTION_NAME); \
} \
return Event; \
}

Now - you cannot do the "#" thing without a macro, however there is an
equivalent thing for types, "typeid".

However, these are not really singletons. They're simply "events". All
it seems you're trying to do is to get handles to all the events used
in your code. If this really is a problem, I'd suggest getting all the
events worked out at the beginning of the program.

If you don't use them before main(), you could do this. This could
definitely be improved but it gives you an idea.

#include <typeinfo>

template <typename w_Derived, bool w_ManualReset, bool w_Initial_state>
struct EventHolder
{
static const HANDLE s_event;

static HANDLE MakeEvent()
{
HANDLE l_event = CREATE_EVENT( NULL, w_ManualReset,
w_Initial_state, typeid( EventHolder ).name() );

if ( ! l_event )
{
EventGenFailed = typeid( EventHolder ).name();
}
}
};

// pre run time initialization.
template <typename w_Derived, bool w_ManualReset, bool w_Initial_state>
const HANDLE EventHolder<w_Derived, w_ManualReset,
w_Initial_state>::s_event =
EventHolder<w_Derived, w_ManualReset, w_Initial_state>::MakeEvent();


// define the events you want.
struct BitBltLock : EventHolder<BitBltLock, false, true> {};
struct BLocOnBitset : EventHolder<BLocOnBitset, false, true> {};


// in the main startup
#include <iostream>
const char * EventGenFailed;

int main()
{
if ( EventGenFailed )
{
// failed to create event - notify the world
std::cerr << "FAILED TO CREATE ALL EVENTS : " << EventGenFailed
<< "\n";
return 1;
}
HANDLE X = BLocOnBitset::s_event;
HANDLE Y = BitBltLock::s_event;
}
 
C

Cephalobus_alienus

Noah said:
I'll never understand why people feel that macros are so bad that they
will work so hard at comming up with some convoluted template mess to
replace them just because they don't like them for some reason. Yes,
there are times when using a macro is to be avoided. We no longer use
them to create inline functions, as we have those already, and we no
longer use them to define magic numbers because constant values are
safer. That is a far cry from saying they must never be used no matter
how difficult it is to accomplish tasks without them. Just look at how
much they are used in template metaprogramming tasks.

Avoiding macros because of reasoning like this is like trying to come
up with some way to do X task in Perl just because you like the
language...even if task X would be more easily accomplished in some
other language. There is nothing rational behind it.

Since my template skills are rather underdeveloped, it made sense to
me to join a newsgroup where people considerably more knowledgeable
and skilled than I am in these matters could give me advice. What is
irrational about wanting to learn? Now, it turns out that there just
isn't a template solution to the problem as I defined it, and I've
added something significant to my store of knowledge.

Jerry
 
G

Gianni Mariani

Phlip said:
Okay. Just make them private to a module, and don't call them "singletons".

Use macros for...

- conditional compilation

EEK - try not to - really. You can do much of this with templates too.
 
A

Alf P. Steinbach

* (e-mail address removed):
I know that macros are evil,

Good, starting on the right foot.


Bad. ;-)

I recently came across a problem
that I couldn't figure out how to solve with templates.

I wanted to create a set of singleton event objects, and wrote the
following macro:

#define GET_SINGLETON_EVENT_FUNCTION(FUNCTION_NAME,MANUAL_RESET,\
INITIAL_STATE,EVENT_NAME) \
HANDLE FUNCTION_NAME() \
{ \
static HANDLE Event; \
if (0 == Event) \
{ \
Event = CreateEvent(NULL, MANUAL_RESET, INITIAL_STATE, \
EVENT_NAME); \
} \
return Event; \
}

Well, it seems all you've done is define a function with a name and some
values to be used in an ensured initialization -- the singleton aspect
doesn't seem to be relevant.

Wrapping some data and ensuring initialization is what classes are for.

You don't even need to use templates.

bool throwX( char const s[] ) { throw std::runtime_error( s ); }

class Event
{
public:
typedef EVENT OsEventHandle;

private:
OsEventHandle myEvent;

public:
Event(
std::string const& eventName,
bool useManualReset = false,
bool initiallySet = true
)
: myEvent( ::CreateEvent(
NULL, useManualReset, initiallySet, eventName.c_str()
) )
{
myEvent != 0 || ::throwX( "Dang! CreateEvent failed!" );
}

~EventHolder()
{
::DestroyEvent( myEvent );
}

OsEventHandle handle() const { return myEvent; }

// Appropriate event operations here.
};

See, now there's also ensured destruction!

And, can be used as singleton, global, local, dynamically allocated,
whatever you want.

This allowed me to generate the singleton code via macro calls:
GET_SINGLETON_EVENT_FUNCTION(BitBltLock, FALSE, TRUE, "BitBltLock" )
GET_SINGLETON_EVENT_FUNCTION(BlockOnBitBlt, FALSE, TRUE,
"BlockOnBitBlt" )

Event const bitBltLock( "BitBltLock" );
Event const blockOnBitBlt( "BlockOnBitBlt" );

etc. etc.

Please help me to be less evil! };>

No problem. ;-)
 
G

Gianni Mariani

Noah said:
I'll never understand why people feel that macros are so bad that they
will work so hard at comming up with some convoluted template mess to
replace them just because they don't like them for some reason. Yes,
there are times when using a macro is to be avoided. We no longer use
them to create inline functions, as we have those already, and we no
longer use them to define magic numbers because constant values are
safer. That is a far cry from saying they must never be used no matter
how difficult it is to accomplish tasks without them. Just look at how
much they are used in template metaprogramming tasks.

Avoiding macros because of reasoning like this is like trying to come
up with some way to do X task in Perl just because you like the
language...even if task X would be more easily accomplished in some
other language. There is nothing rational behind it.

I think there is a little justification here.

Cons for macros:
a) Debugging is harder because the compiler does not locate errors very
easily.
b) They pollute all namespaces
c) They don't behave like expected when using expressions with side effects
d) They don't honour template parameters i.e. MACRO( foo<a,b> ) does not
always do what you expect.


Pros:
a) In some cases they are more flexible than templates.
b) It can make some messy looking code much easier to read.
c) They're great for include guards !


It's safe to say thet if I have a problem I can solve with templates
where I don't need the Pros listed, then templates would be better.

Use templates where you can and if you find yourself going beyond the
threshold of usability, drop into macros.
 
H

Howard

Alf P. Steinbach said:
* (e-mail address removed):
myEvent != 0 || ::throwX( "Dang! CreateEvent failed!" );

That's kind of obscure. Why not just use an if statement?

if (!myEvent)
::throwX("...");

Everyone can see what that means without blinking twice.

Just my opinion, of course...

-Howard
 
A

Alf P. Steinbach

* Howard:
That's kind of obscure. Why not just use an if statement?

if (!myEvent)
::throwX("...");

Everyone can see what that means without blinking twice.

That's kind of obscure. Why not just use a logical OR?

myEvent != 0 || ::throwX( "Dang! CreateEvent failed!" );

Everyone can see what that means without blinking twice, and besides, it
reads better (try it), is less to write, is much more easily recognized
via the human brain's pattern recognition, has less constrained
formatting options, is an established idiom in many languages, etc.
 
C

Cephalobus_alienus

Alf said:
* (e-mail address removed):

Good, starting on the right foot.



Bad. ;-)



Well, it seems all you've done is define a function with a name and some
values to be used in an ensured initialization -- the singleton aspect
doesn't seem to be relevant.

As I wrote to Victor, in message
http://groups.google.com/group/comp.lang.c++/msg/cf8acaef3fa652f7
the really important aspect is that I call CreateEvent only once
during initialization, since the presence of concurrently running
resource hogs means that I can't rely on further calls to CreateEvent
returning a handle to the existing event object. I've seen it fail
too many times. So you're right - the singleton aspect isn't the
important one.
Wrapping some data and ensuring initialization is what classes are for.

You don't even need to use templates.

bool throwX( char const s[] ) { throw std::runtime_error( s ); }

class Event
{
public:
typedef EVENT OsEventHandle;

private:
OsEventHandle myEvent;

public:
Event(
std::string const& eventName,
bool useManualReset = false,
bool initiallySet = true
)
: myEvent( ::CreateEvent(
NULL, useManualReset, initiallySet, eventName.c_str()
) )
{
myEvent != 0 || ::throwX( "Dang! CreateEvent failed!" );
}

~EventHolder()
{
::DestroyEvent( myEvent );
}

OsEventHandle handle() const { return myEvent; }

// Appropriate event operations here.
};

See, now there's also ensured destruction!

And, can be used as singleton, global, local, dynamically allocated,
whatever you want.

This allowed me to generate the singleton code via macro calls:
GET_SINGLETON_EVENT_FUNCTION(BitBltLock, FALSE, TRUE, "BitBltLock" )
GET_SINGLETON_EVENT_FUNCTION(BlockOnBitBlt, FALSE, TRUE,
"BlockOnBitBlt" )

Event const bitBltLock( "BitBltLock" );
Event const blockOnBitBlt( "BlockOnBitBlt" );

Nice! I like your solution!
No problem. ;-)

Thanks!
Jerry
 
D

Dave Branton

Similar to an above example, but requring no class statics, and
probably being
more suited to your environment of restricted resources in which the
function
CreateEvent failing may not mean that it will fail the next time you
call it.

This can be accomplished with templates like so:

template<class _tag, int _manual, int _initialstate>
struct Event
{
static HANDLE GetEvent()
{
static HANDLE Event = 0;
if (0 == Event)
{
Event = CreateEvent(NULL, _manual, _initalstate,
typeid(_tag).name());
}
return Event;
}
} ;

And then used like so:

struct BlockOnBitBlt: public Event<BlockOnBitBlt, TRUE, FALSE> {};
struct BitBltLock: public Event<BitBltLock, TRUE, FALSE> {};

So that you can always say, at any time, anywhere in your code.

BlockOnBitBlt::GetEvent();

And get an event handle.

This should solve your problems using templates, because you are right,
macros are evil and I've
yet to come across a problem that can't be solved using templates
instead.

-dave
 
H

Howard

Alf P. Steinbach said:
* Howard:

That's kind of obscure.

Oh, come one. Was this a joke?

How in the world is "if !a then b" obscure???
Why not just use a logical OR?

Because there's no reason to use an OR if you don't need to evaluate two
boolean expressions.
myEvent != 0 || ::throwX( "Dang! CreateEvent failed!" );

Everyone can see what that means without blinking twice, and besides, it
reads better (try it), is less to write,

In what way is it less to write? Try counting the characters (after making
the quoted strings match, of course).

And in what way does it "read better"? "If myEvent doesn't exist then
throwX" versus "MyEvent exists OR throw"? Personally, I find it easier to
read sentences with a subject and verb. It's like comparing "It is not dark
OR I run into things." with "If it is dark, then I run into things." I find
the second one much easier to comprehend.
is much more easily recognized via the human brain's pattern recognition,

What? You have trouble recognizing "if !a then b", but not "a != 0 OR b"?
The idea is to specify an action, given a condition. Yours accomplishes
that, but it masks the action as a condition of its own. Mine states it
exactly as it is meant.
has less constrained formatting options,

You mean you can choose to have parentheses or not? Is that supposed to be
a benefit?
is an established idiom in many languages, etc.
Only ones where short-circuit evaluation is the default, and where you can
ignore the results of a boolean expression. (I have no idea which specific
languages fall into or out of that category, however.)


I totally disagree with you.

1) Your method requires that you know and quickly recognize that
short-circuit evaluation is going to take place. That's not true of all
languages, or even of all older implementations of C or C++.
2) Your statement is a boolean conditional expression, but it's value is
never used. Fine, that's legal, but it's also useless.
3) Likewise, the second part of the statement is intended to specify an
action, but it's being used as a conditional expression, also with the
result ignored.
4) Your statement as a whole basically says "evaluate: (there is a myEvent)
OR (throwX)", which doesn't make much sense as an English statement. It
certainly doesn't convey in any obvious manner that what you really MEAN is:
"if there is no myEvent then throwX". Why not write what you mean?

I've seen some code obfuscation contests before, and your statement is a
good example of how to take something obvious and turn it into something
obscure.

-Howard
 
A

Alf P. Steinbach

* Howard:
In what way is it less to write? Try counting the characters (after making
the quoted strings match, of course).

Assuming any half-decent coding standard:

if(!)nl{nl nl} 9
||; 3

And in what way does it "read better"? "If myEvent doesn't exist then
throwX" versus "MyEvent exists OR throw"?

Yes. :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,431
Messages
2,571,677
Members
48,796
Latest member
Greg L.

Latest Threads

Top