Jump to page: 1 25  
Page
Thread overview
DIP 88: Simple form of named parameters
Jan 23, 2016
Jacob Carlborg
Jan 23, 2016
Marc Schütz
Jan 23, 2016
Jacob Carlborg
Jan 23, 2016
Marc Schütz
Jan 23, 2016
tcak
Jan 23, 2016
Mint
Jan 23, 2016
Jacob Carlborg
Jan 23, 2016
Mathias Lang
Jan 23, 2016
Jacob Carlborg
Jan 23, 2016
Chris Wright
Jan 24, 2016
Jacob Carlborg
Jan 24, 2016
Chris Wright
Jan 25, 2016
Jacob Carlborg
Jan 25, 2016
arturg
Jan 25, 2016
Chris Wright
Jan 25, 2016
arturg
Jan 25, 2016
jmh530
Jan 23, 2016
Dejan Lekic
Jan 24, 2016
Jonathan M Davis
Jan 24, 2016
default0
Jan 24, 2016
Jonathan M Davis
Jan 24, 2016
Andrej Mitrovic
Jan 24, 2016
default0
Jan 24, 2016
Jacob Carlborg
Jan 24, 2016
Chris Wright
May 27, 2016
Vladimir Panteleev
Oct 25, 2017
Bastiaan Veelo
Jan 24, 2016
jmh530
Jan 24, 2016
Gary Willoughby
Jan 24, 2016
default0
Jan 24, 2016
Jacob Carlborg
Jan 24, 2016
Chris Wright
Jan 24, 2016
Michel Fortin
Jan 24, 2016
Jacob Carlborg
Jan 24, 2016
Chris Wright
Jan 24, 2016
Michel Fortin
Jan 24, 2016
Jacob Carlborg
Jan 26, 2016
xenon325
Jan 26, 2016
xenon325
Jan 28, 2016
Timon Gehr
Jan 28, 2016
xenon325
Jan 25, 2016
HaraldZealot
Jan 25, 2016
arturg
Jan 25, 2016
HaraldZealot
Jan 25, 2016
arturg
Jan 25, 2016
Nick Treleaven
January 23, 2016
This is mostly to prevent ugly hacks like Flag [1].

http://wiki.dlang.org/DIP88

[1] https://dlang.org/phobos/std_typecons.html#.Flag

-- 
/Jacob Carlborg
January 23, 2016
On Saturday, 23 January 2016 at 14:19:03 UTC, Jacob Carlborg wrote:
> This is mostly to prevent ugly hacks like Flag [1].
>
> http://wiki.dlang.org/DIP88
>
> [1] https://dlang.org/phobos/std_typecons.html#.Flag

Some comments:

1) Default values

You should specify how to use both the `:` syntax and a default parameter value, including an example. They are often going to be used together, and it needs to be clear how they interact.

2) Argument order

I think your rule no. 4 is not really necessary, and actually diminishes the usability a lot if there are many name flags. Argument reordering can be done as an independent step before overload resolution (of course this still needs to be aware of all the candidates).

But you should add a note that overloading on parameter names alone is illegal (i.e. `void foo(int a:)` vs `void foo(int b:)`). That way, they don't need to affect name mangling.

3) Variadic parameters

Is this legal: `void foo(int[] param: ...)`? Or this: `void bar(Args...)(Args args:)`? If yes, what would the calling syntax look like?

Also, opDispatch is often used for forwarding arguments. Can parameter names be forwarded, too? If yes, variadic template parameters could capture the names, too, and apply them during expansion as appropriate.

4) Traits

Are there going to be traits to inspect the parameter names of a function? Of a TypeTuple/AliasTuple/AliasSeq?
January 23, 2016
On Saturday, 23 January 2016 at 14:19:03 UTC, Jacob Carlborg wrote:
> This is mostly to prevent ugly hacks like Flag [1].
>
> http://wiki.dlang.org/DIP88
>
> [1] https://dlang.org/phobos/std_typecons.html#.Flag

Without making things any complex, the simplest thought of mine is:

Keep everything same. But allow caller to put name of parameter front its value wherever desired.

Let's say,

Rect createRect(int x, int y, int width, int height);

So you could call it like:

createRect( 10, 20, width: 200, height: 500 );

January 23, 2016
On Saturday, 23 January 2016 at 15:34:00 UTC, tcak wrote:
> On Saturday, 23 January 2016 at 14:19:03 UTC, Jacob Carlborg wrote:
>> This is mostly to prevent ugly hacks like Flag [1].
>>
>> http://wiki.dlang.org/DIP88
>>
>> [1] https://dlang.org/phobos/std_typecons.html#.Flag
>
> Without making things any complex, the simplest thought of mine is:
>
> Keep everything same. But allow caller to put name of parameter front its value wherever desired.
>
> Let's say,
>
> Rect createRect(int x, int y, int width, int height);
>
> So you could call it like:
>
> createRect( 10, 20, width: 200, height: 500 );

I concur, the additional syntax for declaring functions that take named parameters is entirely extraneous. For the most part, it just complicates implementing the feature by adding additional considerations in regards to how tuples would represent the set of types,

ie. ParameterTypeTuple!foo where foo(int a:, int b:)

For the most part, I wouldn't be opposed to all functions accepting this syntax, although there still is the consideration of how the call is handled. Notably, is the named-parameter an expression of it's own that is only valid (or only meaningful) in the context of a function or constructor call? Otherwise, we still have the problem of how named-parameters are stored in alias sequences.

Also as a minor note, I don't really understand the case for parameter reordering. Typically speaking, the use case for named parameters is to allow calling a function (or constructing and object) without knowledge or concerns for what order the parameters are expected in. Otherwise, the syntax is largely just irrelevant. It simply adds additional cruft without any gain from doing so.
January 23, 2016
On 2016-01-23 16:34, tcak wrote:

> Without making things any complex, the simplest thought of mine is:
>
> Keep everything same. But allow caller to put name of parameter front
> its value wherever desired.
>
> Let's say,
>
> Rect createRect(int x, int y, int width, int height);
>
> So you could call it like:
>
> createRect( 10, 20, width: 200, height: 500 );

I think that the DIP clearly states why it doesn't work like the above. One of the big objections of previous proposals was that the parameters of existing functions would be come part of the API. That is, it would not be possible to rename a parameter without breaking the API.

-- 
/Jacob Carlborg
January 23, 2016
2016-01-23 15:19 GMT+01:00 Jacob Carlborg via Digitalmars-d < digitalmars-d@puremagic.com>:

> This is mostly to prevent ugly hacks like Flag [1].
>
> http://wiki.dlang.org/DIP88
>
> [1] https://dlang.org/phobos/std_typecons.html#.Flag
>
> --
> /Jacob Carlborg
>


About the rationale:
> Supporting named parameters directly in the language prevents the need to
add workarounds with weird looking syntax like Flag

That's going the opposite way of the current trend, which is shift as much feature to library as possible.

> When interfacing with Objective-C it might be desirable to have a method
calling syntax which resembles the syntax used in Objective-C and Swift.

Implementing cosmetic features from a language because it appeals to its user doesn't sound that useful to me.

The `createReq` example is a bit artificial, as you would usually replace it with a struct.

About the design:
As mentioned earlier, forcing users to say which arguments can be named and
which cannot seems like an unnecessary limit. We'll just end up with
everyone using ':' after parameter names (which is very weird looking IMO)
in order to be able to use that syntax at the call site, if necessary.
Also, bear in mind that a lot of code one will use is not under one's
direct control. So if we want to use named parameter with a framework which
doesn't define this syntax, you cannot.
Since changing the order of parameter is not allowed, it sounds better to
just allow this syntax at the call site.
Also, one point which was not covered, should the compiler enforce that the
name used matches ? E.g. if I use `heigh` instead of `height`, should the
compiler tell me "change name `heigh` to `height`" ?

Overall, I'm not found of it. It looks like a lot of complication for little to no benefit.


January 23, 2016
On 2016-01-23 15:54, Marc Schütz wrote:

> Some comments:
>
> 1) Default values
>
> You should specify how to use both the `:` syntax and a default
> parameter value, including an example. They are often going to be used
> together, and it needs to be clear how they interact.

I can add an example.

> 2) Argument order
>
> I think your rule no. 4 is not really necessary, and actually diminishes
> the usability a lot if there are many name flags. Argument reordering
> can be done as an independent step before overload resolution (of course
> this still needs to be aware of all the candidates).

Take this for example:

void foo(int a, string b);
void foo(string b, int a);

void main()
{
    foo(3, "asd");
    foo("asd", 3);
}

The above is legal today. The same example with named arguments:

void foo(int a:, string b:);
void foo(string b:, int a:);

void main()
{
    foo(a: 3, b: "asd");
}

What should happen in the above example? Error or which function should be called?

> 3) Variadic parameters
>
> Is this legal: `void foo(int[] param: ...)`? Or this: `void
> bar(Args...)(Args args:)`? If yes, what would the calling syntax look like?

I haven't really though of that. My initial though would be to not allow that for simplicity. I want to keep it fairly simple to have a chance for the proposal to be accepted.

> Also, opDispatch is often used for forwarding arguments. Can parameter
> names be forwarded, too? If yes, variadic template parameters could
> capture the names, too, and apply them during expansion as appropriate.
>
> 4) Traits
>
> Are there going to be traits to inspect the parameter names of a
> function? Of a TypeTuple/AliasTuple/AliasSeq?

We already have ParameterIdentifierTuple [1]. Are you thinking of something else?

I'm not seeing how AliasSeq is related but this PR [2] adds template parameter introspection traits.

[1] http://dlang.org/phobos/std_traits.html#ParameterIdentifierTuple
[2] https://github.com/D-Programming-Language/dmd/pull/5201

-- 
/Jacob Carlborg
January 23, 2016
On Saturday, 23 January 2016 at 16:38:13 UTC, Jacob Carlborg wrote:
> void foo(int a:, string b:);
> void foo(string b:, int a:);
>
> void main()
> {
>     foo(a: 3, b: "asd");
> }
>
> What should happen in the above example? Error or which function should be called?

I hadn't take this into consideration; indeed it would change the way overload resolution works, although it is still possible to handle this (in this case with an error, because it's ambiguous).

My thought is that for flags (which was your justification for this feature), you really wouldn't want to care about order, you just want to specify the flags you are interested in and let the others assume their default values.

For an example, consider this overload of `spawnProcess` [3]:

@trusted Pid spawnProcess(
    in char[][] args,
    File stdin = std.stdio.stdin,
    File stdout = std.stdio.stdout,
    File stderr = std.stdio.stderr,
    const string[string] env = null,
    Config config = Config.none,
    in char[] workDir = null
);

Let's say you want to specify the workdir, stdout and a config flag:

auto pid = spawnProcess(
    ["/usr/bin/grep", "-r.", "some string"],
    workDir: "~/Documents",
    stdout: fd,
    config: Config.retainStderr
);

If the arguments all must be specified in the right order, it's very hard to get them right without looking them up in the documentation. Besides, if I understand the proposal correctly, you'd actually have to specify all arguments up to the last one used, even though they already have default values.

> We already have ParameterIdentifierTuple [1]. Are you thinking of something else?

ParameterIdentifierTuple doesn't distinguish between parameters that allow your syntax and those that don't.

>
> I'm not seeing how AliasSeq is related but this PR [2] adds template parameter introspection traits.
>
> [1] http://dlang.org/phobos/std_traits.html#ParameterIdentifierTuple
> [2] https://github.com/D-Programming-Language/dmd/pull/5201

This was part of my thoughts for variadic template params. Basically, the following should work:

int foo(int a:, int b:);
int bar(Args...)(Args args:) {
    return bar(args);
}
bar(b: 2, a: 1);

Currently, `args` is `(2, 1)`. With name parameters, it would become `(b: 2, a: 1)`, i.e. each tuple members gets an (optional) name. There would then need to be a trait for reading these names.

[3] http://dlang.org/phobos/std_process.html#.spawnProcess
January 23, 2016
On 2016-01-23 17:35, Mathias Lang via Digitalmars-d wrote:

> About the rationale:
>  > Supporting named parameters directly in the language prevents the
> need to add workarounds with weird looking syntax like Flag
>
> That's going the opposite way of the current trend, which is shift as
> much feature to library as possible.

Yeah, I know. But I think this is worth adding and that Flag is hurting more than it's helping. Just because something is possible to do in the library doesn't mean it's a good idea.

There's been a lot of C++ related features which purely is about mangling. This could be handled in library code together with pragma(mangle). Yet these where added anyway. Yeah, I know everyone will complain that's not the same thing.

>  > When interfacing with Objective-C it might be desirable to have a
> method calling syntax which resembles the syntax used in Objective-C and
> Swift.
>
> Implementing cosmetic features from a language because it appeals to its
> user doesn't sound that useful to me.

This was not part of my initial idea. It was added as a bonus. I can remove it from the rational if it's preferred.

> The `createReq` example is a bit artificial, as you would usually
> replace it with a struct.

Yes.

> About the design:
> As mentioned earlier, forcing users to say which arguments can be named
> and which cannot seems like an unnecessary limit. We'll just end up with
> everyone using ':' after parameter names (which is very weird looking
> IMO) in order to be able to use that syntax at the call site, if
> necessary. Also, bear in mind that a lot of code one will use is not
> under one's direct control. So if we want to use named parameter with a
> framework which doesn't define this syntax, you cannot.
> Since changing the order of parameter is not allowed, it sounds better
> to just allow this syntax at the call site.

I think the DIP clearly states why this is the case. There have been several proposals for named parameters before, they have all been shot down because of this (and the ordering of the parameters). I'm not out to create the most ideal and perfect proposal. I'm trying to provide a proposal that has a chance of being accepted.

> Also, one point which was not covered, should the compiler enforce that
> the name used matches ? E.g. if I use `heigh` instead of `height`,
> should the compiler tell me "change name `heigh` to `height`" ?

Hmm. That's kind of interesting. My idea was that the compiler should enforce that. But if the names don't need to match the only thing that is necessary is a syntax for adding names at the call site. The syntax for declaring the named parameters would not be required.

> Overall, I'm not found of it. It looks like a lot of complication for
> little to no benefit.

How is it complicated? I think it's very simple. The feature could be summarized with this example:

Rect createRect(int x:, int y:, int width:, int height:);
createRect(x: 0, y: 0, width: 200, height: 200);

Just because I described how the feature work in detail doesn't mean it's complicated.

-- 
/Jacob Carlborg
January 23, 2016
On Sat, 23 Jan 2016 15:19:03 +0100, Jacob Carlborg wrote:

> This is mostly to prevent ugly hacks like Flag [1].
> 
> http://wiki.dlang.org/DIP88

Please add proposals to http://wiki.dlang.org/List_of_DIP in the future. (I just did it for you.) There's a DIP category, but nobody includes a descriptive title in their wiki page names, so the auto-generated category name is kind of useless.

> [1] https://dlang.org/phobos/std_typecons.html#.Flag

"Rational" should be "Rationale".

One huge usecase for this is methods with many optional parameters. You've missed that. For instance, I wrote a method with six optional parameters recently. It's unusable without named parameters. I switched to a parameter struct, but it's still not that great.

I'd also add that this proposal doesn't affect UFCS.

What about overloading based on parameter names? The proposal doesn't even mention the idea, so there's no guessing whether you considered and rejected it or just didn't consider it.

> Any parameter that is supposed to be nameable at the call site needs to be explicitly declared as such. This is required because otherwise the parameters of all exist functions would become part of the API

I'll note that parameter names are already part of documentation, and they're already the only parameter documentation you're guaranteed to have.

The Dart devs decided that named parameters must be explicitly set out as named, and they cited the same reason. The C# devs, on the other hand, made every parameter a named parameter. I haven't heard of any explosions in C# land, and it's been five years.

Your proposal is closer to C#'s version than Dart's. In Dart, a named parameter cannot be called positionally:

  foo({a, b}) {}
  main() {
    // This works:
    foo(b: 1, a: 2);

    // Error: 0 positional arguments expected, 2 found
    foo(2, 1);
  }

In C#, a named parameter is only about the call site and has nothing to do with the function being called. A function you wrote for C# 1.1 and never modified can be called with named parameters in C# 4.0. You can still call these functions with positional-style parameters.

> Changing the order when using the named parameter syntax is not legal:

Why not?

Let's look at languages with named parameters. Python: reorderable. C#: reorderable. Dart: reorderable. Scala: reorderable. Ada: reorderable.

Given this trend, people will be confused if they can't reorder named parameters. The main benefit of not letting people reorder things is reducing the amount of work *you* need to do when creating this DIP (and the amount others need to do when implementing it).

To sum up, your proposal is approximately the same as adding a comment by each parameter saying which parameter it is. A bit nicer because it's got lighter syntax, a lot less usable because the function has to opt in.

Document how it's supposed to handle optional parameters and allow reordering, and then we're getting somewhere.
« First   ‹ Prev
1 2 3 4 5