Thread overview | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
September 23, 2002 how to live without #define | ||||
---|---|---|---|---|
| ||||
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 Re: how to live without #define | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sandor Hojtsy | "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 Re: how to live without #define | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter | "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 Re: how to live without #define | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter | 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 Re: how to live without #define | ||||
---|---|---|---|---|
| ||||
Posted in reply to Burton Radons | "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 Re: how to live without #define | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter | "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 Re: how to live without #define | ||||
---|---|---|---|---|
| ||||
Posted in reply to Burton Radons | >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 Re: how to live without #define | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sandor Hojtsy | "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 Re: how to live without #define | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sandor Hojtsy | "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 Re: how to live without #define | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter | >> 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 |
Copyright © 1999-2021 by the D Language Foundation