I've been thinking about named arguments support in C++ with a simple, non-intrusive syntax. I've posted a formatted version of the idea here https://github.com/berkus/cpp_named_argsI would like to hear what do you think is wrong with this approach and why would it not work, before I jump to patch up LLVM to support this feature?
Can you point as to the previous proposal for named arguments?
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
Shame that's only useful for objects, not free functions, and seems like another hack to use as an excuse for not
making language levels changes to the standard.
I've seen a mention on the boost mailing list a long while ago about a desire for this to be proposed by Dave Abrahams, I can't find a proposal anywhere though.Ville: There is a multitude of problems with that named parameter idiom (which I've never used, so I'm mentioning these problems just based on a quick glance at the url):
Drawbacks of named parameter idiom:* This idiom implies that all parameters not passed directly to the constructor all have defaultvalues as equivalent to being 'T variable = value' inside the constructor parameter list.This is most often not the intended behaviour when defining a constructor.
* As all the member variables having been initialised by a default value due to the problemin 1, they will be twice initialised when having their value set via a named member function.This is often unacceptable.
* It's not possible to have a named parameter that is required to have a value passed to it.As per 1, they're all defaulted whether that is your intention or not. You also can't guaranteethat the user is going to call the named method and this isn't enforceable at compile time.
* I still don't see how this is usable for free functions.
@Berkus: What's the reason for requiring a colon in the parameter definition? I think this feature would be much more useful if it was allowed for any function call.
On Mon, Oct 7, 2013 at 2:28 PM, Bengt Gustafsson <bengt.gu...@beamways.com> wrote:@Berkus: What's the reason for requiring a colon in the parameter definition? I think this feature would be much more useful if it was allowed for any function call.Please no. If you allow existing parameter names to gain semantics like this, then renaming parameters becomes an ABI breaking change. Functions should be required to opt into their parameter names having meaning.
about removing the requirement for naming the a
write_datagram(buf, size, is_reliable: true);
write_datagram(buf, size, is_reliable=true);
I like the idea of named arguments and find them very useful in other languages. One thing I use a bit in python is perfect forwarding with named args. It would be worth spending some time to think if this proposal could work with perfect forwarding.On 8 October 2013 04:32, Berkus Infinitus <ber...@gmail.com> wrote:
about removing the requirement for naming the a
A final note about the syntax. I like the use of the colon in the function declaration, that turns the argument name into a label; but on function calls I would prefer the equal sign; it makes the purpose clearer:write_datagram(buf, size, is_reliable: true);vswrite_datagram(buf, size, is_reliable=true);
As far as I can tell, there are two different use cases for named arguments:1. Documentation of call parameters. This could easily be faked by adding comments, as in: write_datagram(buf, size, /* is_reliable */ true) ugly as ****, but works.2. Skipping over optional arguments.This is what I propose:a) For the documentation problem: If an argument name in a function declaration is immediately followed by a colon, the argument name must be present also in all calls. No reordering of arguments is allowed here; named arguments must stay in the same place as they are in the function signature. This would reduce the problem as a parsing one: The compiler should issue an error (maybe a warning) if no name is given for a named arg, but can forget about the parameter labeling from then on.b) Skipping over optional arguments. I would follow here the same rules as for optional args:- In a function declaration, if an optional argument name is followed by a colon, that turns it into a named argument. As with optional args, all arguments following it must also be named arguments.- In a function call, if a named optional argument is labelled, all arguments from then on must also be labelled. As in case a), arguments must also be in the same order as in the function declaration.In both cases, the rule that parameters must keep the same order as in the function declaration preserves the signature, so no newambiguities are introduced. In fact, the function definition must not know about named args, just as it doesn't know about default values.
Funny. I'd expectvoid f(int x : 0, int y : 0, int z : 0);to be callable as
f(y : 42); // 'unordered' call, use default args for x and z
so I don't quite grasp what the same-order requirement buys. Furthermore, I'd expect
it to be callable as
f(42); // 'ordered' call, use default args for y and z
and
f(42, 666); // 'ordered' call, use default args for zWhat is the interesting question is whether to allow mixing, likef(666, z : 5); // ' x=666, y=0, z=5The idea is that you can call f( y : 42 ) or f ( y :42, z : 666 ), but not f( z: 666, y: 42 ). This would preserve the function signature after filling the gaps.
Say you have void g ( int a : 0, float b: 0, bool c : true )g( b:1, c:false ) is void ()( int, float, bool )g( c:true, b:2 ) is void ()( int, bool, float )
Regarding mixing, I'm not sure what could be better. My idea was that for optional arguments, after you start labeling, you must keep labeling; i.e.: f( 5, y:42, z:666 ), but not f( 5, y:42, 666 ) , but on second thought there is no real need for that; the next argument after y must be z .
On Tue, Oct 8, 2013 at 9:34 AM, Ville VoutilainenI hope order call is not supported on named arguments at all. Python 2
<ville.vo...@gmail.com> wrote:
> Funny. I'd expect
>
> void f(int x : 0, int y : 0, int z : 0);
>
> to be callable as
> f(y : 42); // 'unordered' call, use default args for x and z
>
> so I don't quite grasp what the same-order requirement buys. Furthermore,
> I'd expect
> it to be callable as
> f(42); // 'ordered' call, use default args for y and z
> and
> f(42, 666); // 'ordered' call, use default args for z
has it, but caused lots of problems, especially when a signature is
changed, the old problem may still run but runtime behavior is silently
changed, which is really horrible, and finally people added "keyword-
only argument" in Python 3.
On Tue, Oct 8, 2013 at 10:29 AM, Ville Voutilainen?? I guess you miss understood.
<ville.vo...@gmail.com> wrote:
>> I hope order call is not supported on named arguments at all. Python 2
>> has it, but caused lots of problems, especially when a signature is
>> changed, the old problem may still run but runtime behavior is silently
>> changed, which is really horrible, and finally people added "keyword-
>> only argument" in Python 3.
>>
>>
>
> It doesn't cause any problem that wasn't always present with functions
> ever since c++98. If a user is concerned about that, he should use
> named arguments in his calls, but I see no reason to prevent
> unnamed arguments for those who wish to use them.
What I mean is, if an argument is declared as named argument:
void f(int x, int y:); // y in this example
Call the function with the named argument named works:
f(3, y: 4);
But with the named argument unnamed should not:
f(3, 4); // no!!!
I understood it just fine, and YES, I want that call to work.
The idea is that you can call f( y : 42 ) or f ( y :42, z : 666 ), but not f( z: 666, y: 42 ). This would preserve the function signature after filling the gaps.
On terça-feira, 8 de outubro de 2013 17:50:34, Berkus wrote:What happens if you call f(z: w(), y: h())? What is called first, w() or h()?
> > The idea is that you can call f( y : 42 ) or f ( y :42, z : 666 ), but
> > not f( z: 666, y: 42 ). This would preserve the function signature after
> > filling the gaps.>
> >
>
> I’d say f(z:666, y:42) is fine, since compiler knows the order, it can fill
> the gaps.
Now a couple points to consider:What if a library writer wants to define an argument to be mandatory but wants to provide a label for it? That would mean that the user must name that and all remaining parameters for the function.f( int a, bool b:, int c = 0, int d = 0 );This would be invalid, since there is no way you could name c or d. So the library writer must declare the function as:
f( int a, bool b:, int c: = 0, int d: = 0 );
And, if a user wants to name the boolean, she must write:f( 12, b:true, c:1, d:2 );
which may be cumbersome if the function has a lot of arguments, all of them with long, descriptive names; this would probably lead the user to completely drop the label.
Another point I would like considered is: would this seamlessly extend into template parameters?
This is the second time you mention Python. Could you please ellaborate on what kind of problems have they found? We can always learn from other's mistakes.
This is the second time you mention Python. Could you please ellaborate on what kind of problems have they found? We can always learn from other's mistakes.
--
On Tue, Oct 8, 2013 at 3:31 PM, Diego Sánchez <dsd...@gmail.com> wrote:Python2 's arguments look like this:
> This is the second time you mention Python. Could you please ellaborate on
> what kind of problems have they found? We can always learn from other's
> mistakes.
def f(x, y):
you can call it through
f(3, 4)
f(3, y=4)
f(y=4, x=3)
When the argument list grows, this become unmaintainable because
you must do not break existing code (which may always uses
sequential calls). For example, if you have an argument list like this:
connect(database, timeout, detect_types, isolation_level,
check_same_thread, factory, cached_statements)
Then you can only extend the list by appending.
So there was a trick around, which captures all named arguments
passed in by a dict (with **kwargs) and forwards then to an internal
function, so that those parameters are "keyword-only".
But obviously it makes the implementation ugly,
so Python 3 added
keyword-only arguments directly:
http://www.python.org/dev/peps/pep-3102/
So that
def f(a, b, *, c):
All parameters after the special '*' can only be called with names.
Another problem is that parameter names are unnecessarily
exposed.
If I got it right, all those problems steem from the fact that in Python function definition is declaration.
In c++ the names of the arguments are not part of the signature, so you are free to define different names for them in your include files; even different default values in different compilation units.
I've been thinking about named arguments support in C++ with a simple, non-intrusive syntax. I've posted a formatted version of the idea here https://github.com/berkus/cpp_named_argsI would like to hear what do you think is wrong with this approach and why would it not work, before I jump to patch up LLVM to support this feature?
Yes, sorry, I meant API, not ABI. But depending on the exact rules, it could be both. For instance, the parameter names might need to be included in some mangled names, because they could affect which overload is selected. And in some corner cases, it will be an ABI break no matter what else we decide:
// libraryint f(int a); // #1double f(double d);// user codevoid g(decltype(f(d:0)) x);
On Tue, Oct 8, 2013 at 4:26 PM, Philipp Stephani <p.ste...@gmail.com> wrote:Lua uses this approach. And they even has a syntax
> Often a dedicated options type (e.g. a namedtuple) is better
> than a large number of keyword arguments.
sugar to use func{ <table> } call instead of
func({ <table> }). I'm not particularly in favor of this;
sometimes a language extension makes things cleaner.
(And we don't have such convenient struct in C++ I guess).