Jump to page: 1 2
Thread overview
how to live without #define
Sep 23, 2002
Sandor Hojtsy
Sep 23, 2002
Walter
Sep 23, 2002
anderson
Sep 23, 2002
Burton Radons
Sep 24, 2002
Sandor Hojtsy
Sep 24, 2002
Walter
Sep 25, 2002
Burton Radons
Sep 25, 2002
Sandor Hojtsy
Sep 25, 2002
Mark Evans
Sep 25, 2002
Patrick Down
Sep 26, 2002
Mark Evans
Oct 02, 2002
Walter
Oct 02, 2002
Mark Evans
Sep 24, 2002
Mac Reiter
Sep 24, 2002
Sandor Hojtsy
Sep 24, 2002
Walter
Sep 24, 2002
Mark Evans
Sep 25, 2002
Walter
September 23, 2002
One of my programs have a list of boolean options. The options can be loaded from a text config file, and option values should be immediatly avaiable during execution. In C :

enum Option {
   firstOption,
   secondOption,
   ....
   lastOption,
   optionQ
};

struct OptionDesc

   bool value;
   char *name;
};

OptionDesc options[optionQ] =
{
  {false, "firstOption"},
  {false, "secondOption"},
  ...
  {false, "lastOption"},
}

And then loading can be done based on name, and values can be retrieved by indexing the options array with the enum name:

bool d = options[someOption].value;

But the evil *redundancy* is lurking here! Options are listed two times, and
because of this, you can make several errors:
- error in order of the options
- error in option names
- options missing from one of the lists

The C solution is #define-s. See:

#define OPTION_LIST  \
  OH(firstOption),           \
  OH(secondOption),      \
  ....                                 \
  OH(lastOption)

#define OH(a)  a

enum Options {
  OPTION_LIST,
  optionQ
};

struct OptionDesc

   bool value;
   char *name;
};

#undef OH
#define OH(a)  {false, #a}

OptionDesc options[optionQ] =
{
  OPTION_LIST
}

Voila! Ugly, but no redundancy in the source code.
Now how you do this in D?
Without #defines you have to maintain the consistency of the two lists by
yourself. Why can't the complier help in such a mechanical task?

What would be the ideal solution?
In this particular case: reflection. If the program could access enum value
names at runtime, it could load the options from the config file by name.

In general: we should consider all the aspects the C #define was used for, and try to provide an alternative for the yet unadressed ones.



September 23, 2002
"Sandor Hojtsy" <hojtsy@index.hu> wrote in message news:ammnbk$1gvd$1@digitaldaemon.com...
> Voila! Ugly, but no redundancy in the source code.

I thought I was the only one to use that technique!

> Now how you do this in D?
> Without #defines you have to maintain the consistency of the two lists by
> yourself. Why can't the complier help in such a mechanical task?

In this case, you can do it with named array initializers:

OptionDesc options[optionQ] =
[
    firstOption : {false, "firstOption"},
    ...
];

It's not perfect, but it gets you most of the way there.

> In general: we should consider all the aspects the C #define was used for, and try to provide an alternative for the yet unadressed ones.

You can always do some things with a text processor that can't be done reasonably with a symbolic processor, but I think D comes pretty close to having a superior solution for at least the common things done with #define's. I find the C preprocessor inadequate many times, and have turned to specialized C programs that generate C source for table building. You can see an example in idgen.c in the D front end source.



September 23, 2002
"Walter" <walter@digitalmars.com> wrote in message news:amncsh$2a3t$1@digitaldaemon.com...
>
> > Now how you do this in D?
> > Without #defines you have to maintain the consistency of the two lists
by
> > yourself. Why can't the complier help in such a mechanical task?
>
> In this case, you can do it with named array initializers:
>
> OptionDesc options[optionQ] =
> [
>     firstOption : {false, "firstOption"},
>     ...
> ];
>
> It's not perfect, but it gets you most of the way there.

I still think extentable enums would be a better solution.


September 23, 2002
Walter wrote:
> "Sandor Hojtsy" <hojtsy@index.hu> wrote in message
> news:ammnbk$1gvd$1@digitaldaemon.com...
>>In general: we should consider all the aspects the C #define was used for,
>>and try to provide an alternative for the yet unadressed ones.
> 
> You can always do some things with a text processor that can't be done
> reasonably with a symbolic processor, but I think D comes pretty close to
> having a superior solution for at least the common things done with
> #define's. I find the C preprocessor inadequate many times, and have turned
> to specialized C programs that generate C source for table building. You can
> see an example in idgen.c in the D front end source.

No, no, Sandor wasn't advocating metaprogramming or preprocessing, just a high level of introspection.  This level of introspection is in my port (I think it's the find method on the EnumInfo, wrong OS to check).  But it's had questionable value, as most enums are of the form:

    typedef int GLenum;
    enum : GLenum
    {
        GL_FALSE = (GLenum) 0,
        ....
    }

So you can't name it.  Oh, and note the cast.  Let's make it so that if you're defining an enum, an explicit cast is implied.

The good thing about using intermediaries instead of the preprocessor is that it compiles based on the output file, so you get far better debugging.  When you really need wacky code processing, the C processor is both a PITA and makes it impossible to tell what goes wrong.

September 24, 2002
"Burton Radons" <loth@users.sourceforge.net> wrote in message news:amo25r$1ga$1@digitaldaemon.com...
> Walter wrote:
> > "Sandor Hojtsy" <hojtsy@index.hu> wrote in message news:ammnbk$1gvd$1@digitaldaemon.com...
> >>In general: we should consider all the aspects the C #define was used
for,
> >>and try to provide an alternative for the yet unadressed ones.
> >
> > You can always do some things with a text processor that can't be done reasonably with a symbolic processor, but I think D comes pretty close
to
> > having a superior solution for at least the common things done with #define's. I find the C preprocessor inadequate many times, and have
turned
> > to specialized C programs that generate C source for table building. You
can
> > see an example in idgen.c in the D front end source.
>
> No, no, Sandor wasn't advocating metaprogramming or preprocessing, just a high level of introspection.

Exactly, in this particular case. I think it would be a more ellegant solution.

And Walter:
Beware! Your (named indexes) solution now include three lists! One list of
the enum value names, when defining the enum type, and the two other lists
(merged) when initializing the array. Only the possibility of the "order
error" was removed, with yet more redundancy. But what about the "missing
element error"?

> This level of introspection is in my
> port (I think it's the find method on the EnumInfo, wrong OS to check).

Wow!

>   But it's had questionable value, as most enums are of the form:
>
>      typedef int GLenum;
>      enum : GLenum
>      {
>          GL_FALSE = (GLenum) 0,
>          ....
>      }
> So you can't name it.

Interesting. That is a workaround for a feature which was considered a Good
Think (scoped enum names).
Why do we need workaround here? Because the language doesn't have native
support for non-scoped enum names, and they are still required!
If it had, you would have no problem naming the enum type.

>  Oh, and note the cast.  Let's make it so that if
> you're defining an enum, an explicit cast is implied.

I don't understand.




September 24, 2002
"Walter" <walter@digitalmars.com> wrote in message news:amncsh$2a3t$1@digitaldaemon.com...
>
> "Sandor Hojtsy" <hojtsy@index.hu> wrote in message news:ammnbk$1gvd$1@digitaldaemon.com...
> > Voila! Ugly, but no redundancy in the source code.
>
> I thought I was the only one to use that technique!
>
> > Now how you do this in D?
> > Without #defines you have to maintain the consistency of the two lists
by
> > yourself. Why can't the complier help in such a mechanical task?
>
> In this case, you can do it with named array initializers:
>

enum Option {
  firstOption,
  secondOption,
  ...
  lastOption,
  optionQ
}

> OptionDesc options[optionQ] =
> [
>     firstOption : {false, "firstOption"},
>     ...
> ];


You still need the enum type declaration. So now you have 3 lists of the same names.

Sandor


September 24, 2002
>So you can't name it.  Oh, and note the cast.  Let's make it so that if you're defining an enum, an explicit cast is implied.

I'm sorry.  The phrase "an explicit cast is implied" just struck me as extremely funny...

Mac


September 24, 2002
"Sandor Hojtsy" <hojtsy@index.hu> wrote in message news:amp0es$11ge$1@digitaldaemon.com...
> And Walter:
> Beware! Your (named indexes) solution now include three lists! One list of
> the enum value names, when defining the enum type, and the two other lists
> (merged) when initializing the array. Only the possibility of the "order
> error" was removed, with yet more redundancy. But what about the "missing
> element error"?

The missing element error is caught if the enum value isn't added but the array one is. The missing array value isn't caught, unless you have runtime checking for array values initialized to the default (which you can do in a unittest block).

P.S. I've had many subtle bugs from the "order error", so fixing that in D was important to me.


September 24, 2002
"Sandor Hojtsy" <hojtsy@index.hu> wrote in message news:amp115$123m$1@digitaldaemon.com...
> You still need the enum type declaration. So now you have 3 lists of the same names.

Yes, I know. But the redundancy does give better error checking.


September 24, 2002
>> You still need the enum type declaration. So now you have 3 lists of the same names.
>
>Yes, I know. But the redundancy does give better error checking.
>

Ugh.  I think enums should be improved, too.  C enums are just not very friendly animals.

Take a look at the meta-preprocessor stuff in this code package, http://www.codeproject.com/cpp/tcxunitconverter.asp

and ask whether there should be a better way.

I do not want to define the same things in 3 places!  The preprocessor meta-macros in the preceeding are ugly as sin, but have the virtue of localizing all definitions in one place.

I am not proposing preprocessor tricks for D, just some new-think about enums.

Mark


« First   ‹ Prev
1 2