C++ Logo

std-proposals

Advanced search

Re: Proposal: template function solution to Pythonic optional function arguments

From: Hyper Nova <hyper-nova_at_[hidden]>
Date: Sun, 19 Jul 2020 16:43:40 +0000
> But we already have function overloading, which gives you the same thing with a much simpler syntax.
Your example code could be (in C++98 and later)

Ok, I should have clarified that point. The issue with this is the programmer has to copy / paste and then maintain two different functions. It just so happened with the example I was working with this is less convenient than having the different behavior internal to a single function rather than maintained externally via overloading and calling two different functions. Of course, overloading is a perfectly valid solution, just more work in this case. It often will not always be this way.

> Notice that in your specific case, `mode` has only two meaningful values — "1" and "not 1" — and so it should probably be a `bool`, not an `int`.

Ok, it's just the case for the limited small example I copied here, this isn't the complete function, the actual thing is a couple of hundred lines.

> Even better for your rapid-prototyping work:

    int draw(int param);
    int draw_with_mode(int param, int mode);

    draw_with_mode(1, -1);

This is a good point, but consider the case of more than just a single optional argument. For M optional arguments, the number of function calls goes like 2^M... probably... I haven't given it much thought. Or is it factorial(M). Probably the latter.

Best Regards

________________________________
From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Sent: Sunday, July 19, 2020 16:34
To: Std-Proposals <std-proposals_at_[hidden]>
Cc: Ed Bird <HYPER-NOVA_at_[hidden]>
Subject: Re: [std-proposals] Proposal: template function solution to Pythonic optional function arguments

On Sun, Jul 19, 2020 at 11:45 AM Ed Bird via Std-Proposals <std-proposals_at_[hidden]<mailto:std-proposals_at_[hidden]>> wrote:
Hi,

I am not sure if this is the correct email address to which I should direct this enquiry

It is (I mean I don't know a better place, except for /r/cpp or the Cpplang Slack or I think there's a Discord now).

[...] In my view, if a function has an optional argument, then it should be treated similarly to how template classes are treated. In other words, this is an example of a case where one block of code should produce multiple blocks of executable code when compiled.

But we already have function overloading, which gives you the same thing with a much simpler syntax.
Your example code could be (in C++98 and later)

void draw(int parameter) {
    do_draw(parameter);
}
void draw(int parameter, int mode) {
    do_draw(mode == 1 ? -1 : parameter);
}

We also have default function arguments, although I recommend against their use:
https://quuxplusone.github.io/blog/2020/04/18/default-function-arguments-are-the-devil/

void draw(int parameter, int mode = 42) {
    do_draw(mode == 1 ? -1 : parameter);
}

Notice that in your specific case, `mode` has only two meaningful values — "1" and "not 1" — and so it should probably be a `bool`, not an `int`.

I don't personally like the syntax of using `#if` to achieve the anticipated result, but this is just my personal opinion

Indeed, you can't use preprocessor macros for this, because the C preprocessor doesn't know anything about functions or variables or anything like that. That's also why C++ templates use the dedicated `template` keyword, instead of some weird code-duplicating macro magic.

I actually introduced a bug due to the fact that I had a long list of default parameters, and missed one when calling the function. An implicit cast from int to bool was responsible for the function behaving differently to how I expected. I fixed this by putting in the missing arguments, of course.

Indeed. Default function arguments are the devil.

But it wouldn't have happened if I could have done `draw(1, mode=-1);`

Even better for your rapid-prototyping work:

    int draw(int param);
    int draw_with_mode(int param, int mode);

    draw_with_mode(1, -1);

with no default function arguments at all. This way you can't accidentally forget the mode; if you try to call `draw_with_mode(1)` you get a compiler error.
Of course I can't stop you from spelling it `draw2` instead of `draw_with_mode`. ;)

HTH,
Arthur

Received on 2020-07-19 11:47:00