Preprocessor magic: Default Arguments in C
lefteris.realintelligence.net
lefteris.realintelligence.net
Do yourself a favor, either write clean, portable, clear and concise C code, or use a real pre-processor. The only time you should be using pre processor magic anyways is in a large project that's not a library anyways. So at that point it's pretty trivial to just use a proper pre-processor.
port-linux.c
port-win32.c
port-solaris.c
myprog.c
and just compile/link port-$TARGET.c into your program. The code tends to be cleaner, and the platform knowledge is concentrated in one place.Keep the conditional compilation in the makefiles, not in the source.
Both of those are actually rather simple macros doing what seems like a mess with pointers. The difference is subtle, but most strongly expressed in that the complexity is innate to the problem, and does not require mucking much with what is entirely weird macro behavior.
#include <iostream>
#include <boost/integer.hpp>
int main()
{
// Notice these signed types are going into unsigned types!
boost::uint64_t i = -9151314442815602945;
std::cout << i << std::endl;
unsigned int j = -327681234;
std::cout << j << std::endl;
return 0;
}I am the author of the linked blog. Many nice comments in here, but may I start by a question of my own about hackernews itself. I had submitted this link myself 6 days ago after making the post. Can a link be resubmitted multiple times? The title was a bit different but the link was the same. I am new to the site and want to learn the way it works.
As for the comments by many people, it's a given that this will not appeal to all. Heck to most people especially C++ only programmers it will look ugly. The fact is that if for one reason or another you want to provide functions that have default arguments this is a neat and nice way that works for C99.
As for needing default arguments, well there might be cases where having them is just a way to spoil or even confuse the programmer. But consider an API. An API of a GUI library. Do you REALLY want to be giving all the customizations offered by the library for every single widget/element? Or do you want a TextBox of size(100,100) at position(200,50) and you are done by letting the default arguments handle all the rest?
The Google Style Guide disallows default arguments, and I find their rationale convincing enough that I never use default arguments in my own code: http://google-styleguide.googlecode.com/svn/trunk/cppguide.x...
I am surprised this is an issue at Google.
Just because they have more stringing hiring practices doesn't make their engineers some superhuman level of programmer.
It seems that many engineering decisions are made at google, to minimize the amount of damage a particular programmer can do. This suggests that while Google does/may have some very good people running the place, they also have quite a few programmers whom are mediocre at best.
These choices are about building an environment that forces a programmer to do things the right way, rather then expecting them to do such on their own.
The problem with this reasoning is contained in this:
> to force programmers to consider the API and the values they are passing for each argument rather than silently accepting defaults they may not be aware of.
All you will force poor coders to do will be to fudge the arguments until the code "works". This is actually worse than the default arguments scenario, because the defaults are more likely to be acceptable than the first value the coder stumbles upon that makes the function go.
Taking a line from the Python philosophy: "explicit is better than implicit."
I agree with mistercow: default arguments are, on the whole, a Good Thing. Think of them as a restricted form of overloading which requires (much!) less code to be written.
Obviously they can be misused, but again, that's the nature of programming (and especially of C++). Sane default argument conventions make code easier to read and write.
Your argument makes no sense; the "this" pointer is just a function parameter, and the whole point of a function is that the arguments aren't fixed until the function is called. No part of this is implicit.
> The identity of the function to be executed is hidden from the caller.
The function is named at the call site along with all input to that function (unless you use default arguments). This also is not hiding: every part of the function and its input is explicit.
Much better arguments for your case would be overloaded operators and implicit conversions, both of which happen without an explicit information at the call site. But it's no coincidence that both of these are forbidden by the Google Style Guide also.
So? I don't understand what the problem is. The very act of packaging code in a function is one that hides information about what that function does. And suppose you don't provide a default for the `strict` argument. Unless you're using a language with named function arguments (or an approximation thereof like Objective-C), you won't know that the `false` you see in the argument list means "don't use strict" anyway until you read the documentation. And once you're reading the documentation, this all becomes moot.
> There is no indication at the call site what mode it is operating in, and indeed if the default value is flipped in the header file the caller could change behavior with no code change at the call site!
Yeah, and if you reorder your function parameters, or rename your function, or change the "strict" argument to "lax", or an infinite number of other changes, you would also change behavior with no change at the call site. The solution in each case is "don't do that".
Again, the act of packaging code in a function is one that makes it so that changes in behavior can happen independent of the call site. Sometimes it works to your advantage. Sometimes it doesn't. That's just life.
"What a function does" is encapsulated in that function's name. So for example you could have:
GoToTheStore();
If you want to make a function more generic, you can make some aspects of the function's behavior depend on arguments. So an equivalent call of a more generic function could look like: Go(store);
Both of these are equally explicit; the first has its behavior fully specified by the function itself, the second has its behavior fully specified by a combination of the function name and its argument.Once you have default parameters, the behavior of the function is no longer fully explicit, because some of the function's input comes from somewhere else:
Go(); // Goes to the store by default.
This is both unnecessary (both of the previous options are very usable alternatives) and needlessly implicit. It makes program logic more difficult to follow because you need to be aware of the implicit defaults to fully understand the data flow.Also, code itself is the most reliable documentation, but looking at the implementations of the functions involved won't reveal this extra input; only cross-referencing the header files will, which requires more mental effort for your reader.
I would like to suggest that the function's name should tell you the result (going to the store) and not have anything to do with what the function does (walk, bike, drive, fly) to get that result. Parameters could restrict how the function gets the result. In which case, a default parameter of ANY means no restriction and makes perfect sense with actually less mental effort for the reader.
GoToTheStore(); /* get me to the store */
vs GoToTheStore(ANY); /* does ANY refer to any store? */
but when necessary GoToTheStore(DRIVE); /* I'm feeling lazy, and don't want to walk. */Why would it be hidden? It's a default, customizable behavior. If you don't need to customize it you don't and there's no reason to task you with putting the method in the state which is going to be needed 9 times out of 10.
> and indeed if the default value is flipped in the header file the caller could change behavior with no code change at the call site!
And if the whole implementation is replaced by formatting your hard drive, the caller could change behavior with no code change at the call site!!
> Taking a line from the Python philosophy: "explicit is better than implicit."
You're probably misapplying/misunderstanding things, since Python is one of the languages making the most use out of default values and with extremely strong first-class support for them.
The reason I would tend to use default arguments in Python and C but not in C++ would be that it can get confusing if you throw in C++'s function overloading. A function by its very nature can't help but have default behavior, and if someone realizes they need to override the defaults they'll probably end up in the documentation or function definition or some other place that will let them realize they can adjust the defaults.
#define ARG_16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,...) q
#define COUNT(...) ARG_16(x,##__VA_ARGS__,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
#define PASTE2(a,b) a ## b
#define CALLFN(name,nargs,...) PASTE2(name,nargs)(__VA_ARGS__)
#define FOO(...) CALLFN(foo,COUNT(__VA_ARGS__),__VA_ARGS__)Also it seems that you did not read the topic correctly because even if you tried to apply such a method it would fail for the no arguments case, which is a big part of the bulk of the first method.
If I don't get something please feel free to explain
Instead of calling:
foo_init(1, 'a', 1.0);
You can write: foo_init(.arg1=1, .arg3=1.0, .arg2='a');
foo_init(.arg3='c');
// etc
edit: didn't see this in the blog comments, wasn't trying to steal credit ;-P #define sum(...) \
sum_(sizeof ((int []){ __VA_ARGS__ }) / sizeof (int), (int []){ __VA_ARGS__ })
int sum_(size_t count, int values[])
{
int s = 0;
while(count--) s += values[count];
return s;
}
You'd call the macro as int s = sum(1, -32, 5);