January 08
Thanks for taking on the hard work of this!
January 08
On 1/5/2024 1:48 AM, Dennis wrote:
> ## Empty tuple value
> 
> ```D
> alias AliasSeq(T...) = T;
> 
> int f(int x, int y) { return 0; }
> 
> int v = f(y: AliasSeq!(), 1, 2);
> ```
> 
> Currently, the named argument y with an empty tuple will collapse into nothing, and `(1, 2)` will be assigned to `(x, y)`.
> - Should this be an error?
> - Should this assign `1` to `y`?

My intuition says that an empty tuple is nothing at all, and should just be elided from consideration. Trying to assign nothing to parameter `y` doesn't make sense, and it should error.

In fact, trying to assign a tuple to `y` that is anything other than one element should be an error.

Timon knows more about tuples than I do, so his input would be most welcome.

January 08
On 1/5/2024 1:48 AM, Dennis wrote:
> ## Overloading by name
> 
> With named arguments, you can disambiguate an overload with identical types by name:
> ```D
> string f(T)(T x) { return "x"; }
> string f(T)(T y) { return "y"; }
> static assert(f(x: 0) == "x");
> static assert(f(y: 0) == "y");
> ```
> 
> However, both template functions will end up with exactly the same types. DIP 1030 specifies parameter names aren't part of the mangling, resulting in clashing symbols at run time:
> 
> ```D
> void main()
> {
>      writeln(f(x: 1)); // x
>      writeln(f(y: 1)); // also x
> }
> 
> ```
> 
> Should the compiler, after finding a matching overload, retry all other overloads without named arguments to prevent this? Or should it instantiate it the `x` variant because it saw it first, and then refuse to instantiate `y` because the mangle has been seen before?

```
string f(T)(T x) { return "x"; }
string f(T)(T y) { return "y"; }
```

should give an error. The order should not matter. Just like:

```
string f(int x) { return "x"; }
string f(int y) { return "y"; }
```

gives this error:

Error: function `test3.f(int y)` conflicts with previous declaration at test3.d(2)

I.e. as you correctly observed, the function/template signature is not affected by the parameter names, therefore two functions/templates definitions with the same signature are an error.
January 08
On 1/5/2024 1:48 AM, Dennis wrote:
> ## Tuple parameters
> 
> You currently can't assign a tuple parameter by name:
> ```D
> alias AliasSeq(T...) = T;
> 
> int f(AliasSeq!(int, int) x) { return 0; }
> // This will expand to:
> // int f(int __param_0, int __param_1) { return 0; }
> // So this fails:
> int v = f(x: 1, 2);
> ```

It should fail, unless the AliasSeq has exactly one (unnamed) member, when it is clear what should happen.


> I can change it so it expands to
> ```D
> int f(int x, int __param_1)
> ```

We shouldn't be inventing new behavior without a valuable use case. Corner cases like this should just be an error. That leaves us open to making it work if a valuable use case emerges, rather than discovering we are stuck with wrong behavior.


> But consider that a type tuple can already have names when it came from a parameter list:
> 
> ```D
> int f(int x, int y) { return 0; }
> 
> static if (is(typeof(f) T == __parameters)) {}
> pragma(msg, T); // (int x, int y)
> int g(T) {return 0;}
> static assert(g(x: 3, y: 5) == 0); // Currently works
> 
> int h(T z) {return 0;}
> static assert(h(z: 3, 5) == 0); // Fails, should this work?
> ```
> 
> Is the first parameter named `x`, `z`, both?
> Note: making the declaration of `h()` an error would be a breaking change.

Trying to rename a parameter when the tuple element already has a parameter name should be an error.

In general, questionable corner cases should be treated as errors until a compelling use case for them is found.
January 08
On 1/5/2024 1:48 AM, Dennis wrote:
> ## Forwarding?
> 
> (This did not come up in the implementation, but was pointed out by Timon Gehr on Discord.)
> 
> Is there a way to forward named arguments? Consider:
> 
> ```D
> import std.stdio;
> 
> int f(int x, int y);
> 
> auto logAndCall(alias f, T...)(T args)
> {
>      writeln(args);
>      return f(args);
> }
> 
> logAndCall!f(y: 1, x: 0);
> ```
> 
> Are the names propagated to the `T args` parameter? If so, that wouldn't be hygienic:
> Imagine an argument named `writeln` - it would hijack the function call!

I would say no, they do not propagate to the parameter. I expect it would confuse the hell out of people.


> Perhaps we could allow access to names some other way, like `args.x`. But still, if we had another parameter `(T args, string file)` then the called function could not have a parameter named `file`.

I'd go a step further. Disallow named arguments being passed as a variadic argument list. We can always turn it on later if some compelling reason turns up.
January 08
On 1/5/2024 1:48 AM, Dennis wrote:
> ## Named value sequence?
> 
> So if we can't implicitly give a `T...` names, can we explicitly? We already saw a `__parameters` type tuple can have names, this could be expanded to value sequences:
> 
> ```D
> logAndCall!f(args: AliasSeq!(y: 1, x: 0));
> ```
> 
> This syntax is ambiguous with named template parameters however: According to DIP 1030, this should try to set template parameters `y` and `x` of the `AliasSeq` template. Is there a way to make forwarding named arguments work?

Make that an error and leave it to some future design.

January 09
On 09/01/2024 12:52 PM, Walter Bright wrote:
> My intuition says that an empty tuple is nothing at all, and should just be elided from consideration. Trying to assign nothing to parameter |y| doesn't make sense, and it should error.
> 
> In fact, trying to assign a tuple to |y| that is anything other than one element should be an error.
> 
> Timon knows more about tuples than I do, so his input would be most welcome.

In type theory a tuple can be:

1. A distinct type, it is an object, it is not a sum of its elements.
2. Is not a distinct type, it is not an object, it is the sum of its elements.
3. Can have named elements.
4. Cannot have named elements.
5. An element can be a type.

Everything boils down to tuples, they are whatever a person needs it to be when doing the analysis.

What we have now with alias sequences are not representative of tuples, although they are a subset of tuples.
January 09
On 1/9/24 00:52, Walter Bright wrote:
> On 1/5/2024 1:48 AM, Dennis wrote:
>> ## Empty tuple value
>>
>> ```D
>> alias AliasSeq(T...) = T;
>>
>> int f(int x, int y) { return 0; }
>>
>> int v = f(y: AliasSeq!(), 1, 2);
>> ```
>>
>> Currently, the named argument y with an empty tuple will collapse into nothing, and `(1, 2)` will be assigned to `(x, y)`.
>> - Should this be an error?
>> - Should this assign `1` to `y`?
> 
> My intuition says that an empty tuple is nothing at all, and should just be elided from consideration. Trying to assign nothing to parameter `y` doesn't make sense, and it should error.
> 
> In fact, trying to assign a tuple to `y` that is anything other than one element should be an error.
> 
> Timon knows more about tuples than I do, so his input would be most welcome.
> 

I fully agree with your analysis above. This should error.
January 09

On Tuesday, 9 January 2024 at 13:25:49 UTC, Timon Gehr wrote:

>

I fully agree with your analysis above. This should error.

AliasSeq!() - point A
AliasSeq!(1, 2) - interval B

Concatenate A and B, and you'll get B, but the point is still there, and it has a name, despite the fact it is "nothing".

If we make that an error, we should make AliasSeq!() x; an error too, which would be unfortunate.

January 09
On 1/9/24 16:40, Max Samukha wrote:
> On Tuesday, 9 January 2024 at 13:25:49 UTC, Timon Gehr wrote:
> 
>> I fully agree with your analysis above. This should error.
> 
> AliasSeq!() - point A
> AliasSeq!(1, 2) - interval B
> 
> Concatenate A and B, and you'll get B, but the point is still there, and it has a name, despite the fact it is "nothing".
> 
> If we make that an error, we should make `AliasSeq!() x;` an error too, which would be unfortunate.

No. In that example `y` is an `int`.