C++ Logo

std-proposals

Advanced search

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

From: Tony V E <tvaneerd_at_[hidden]>
Date: Sun, 19 Jul 2020 17:32:25 -0400
the actual thing is a couple of hundred lines.

Herein lies the real problem.

If those hundreds of lines were broken into smaller functions, then draw(param) and draw(param, mode) could make calls to the shared functions (and skipping the unneeded calls, similar to what you are doing with #ifdef)

int draw(int param)
{
   a(param);
   c();
}
int draw‎(int param, int mode)
{
   a(param);
   b(mode);
   c();
}

In those hundreds of lines, is there a comment like:
// step 1 
or
// first, do blah...

that's your first‎ candidate for a subfunction.


Sent from my BlackBerry portable Babbage Device
From: Hyper Nova via Std-Proposals
Sent: Sunday, July 19, 2020 12:44 PM
To: Arthur O'Dwyer; Std-Proposals
Reply To: std-proposals_at_[hidden]
Cc: Hyper Nova
Subject: Re: [std-proposals] Proposal: template function solution to Pythonic optional function arguments

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]> 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:

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 16:35:45