3 ms·
Of course you can do things like macros, but it's ugly and becomes unreadable the more you add to the code. Structure initializers grow and expand more graceful
by __david__ 12y ago
Of course you can do things like macros, but it's ugly and becomes unreadable the more you add to the code. Structure initializers grow and expand more gracefully than anything c++ has.
What does this line do?
Widget *w = new Button("Press me", true, true, false, 0, 0, 0, NULL, callback, 10);
Yes, you can fix that by defining special true/false enums for each of the options, or you can do something reasonable:
struct Button b = { .title="Press Me", .enabled=true,
.visible=true, .expand=false
.x=0, .y=0, .width=10, .z_index=0,
.handler=callback };
I love the array ones, but they're most useful for static look-up tables, and those are usually size constrained:
void (*command[256])() = { ['H'] = command_help,
['S'] = command_start
['s'] = command_stop };
I like that a lot but I definitely use it less than the structure initializers.
I hear people tout default values as a real important feature, but I've worked on large projects where backward compatibility was important, and it was almost always possible to encode the value in such a way that zero meant "default". This allows you to add new members to structures easily and anyone that doesn't set them gets the default value. It may sound hokey but it works extremely well in practice. I never once wished for default values when I was doing large C99 projects.
- kazinator 12y agoAlthough the designated initializer has the value that it shows the name of each member, so that it resembles a keyword parameter list (like what is available ins ome languages: Common Lisp, Python, ...) it is terribly weak in that there is no logic for defaulting anything other than to zero. You have no way to express that, for instance, .handler is to be mandatory. Or if it is not mandatory, that it should default to "dfl_button_callback" or whatever. Another thing you can't do is distinguish whether x was initialized to zero by default, or whether it was an explicit .x = 0. With the macro we know that since x isn't defaulted, it came from the macro. Or if it is defaulted, it couldn't have come from the macro. In the keyword arguments of the Lisp language, we know whether or not a keyword argument which has a default value was explicitly passed with that same value, or whether we are getting that value by default. (In C++, which is somewhat offtopic because the subject is what is possible in C) we can do something clearer, if a bit verbose, by defining some framework for combining traits. I have done this more than once. The result looks like: Widget *w = new Button(Label("Press me") | Enabled(true) | Callback(callback) |...)); The various traits classes have an overloaded operator | which combines traits (Traits | Traits -> Traits). The Button constructor is the Button(const Traits &) one.
- __david__ 12y ago> …it is terribly weak in that there is no logic for defaulting anything other than to zero. That is the weakness I addressed. IE, it may seem terribly weak up front, but in practice it's really not a weakness at all. And, if zero is the default, then it doesn't matter if someone explicitly requested the default, or got the default by omission… It's like using 'exists' in Perl. It seems like it may be important to tell the difference between 'existing as undef' vs. not existing at all, but in practice it's just not needed (I can count the times I've legitimately used 'exists' during my almost 20 years of Perl programs on just a couple fingers).