Comment #0 by dlang-bugzilla — 2021-05-13T05:04:45Z
This should work:
////////// test.d /////////
void fun(T)(T value = "hi")
{
}
void main()
{
fun(); // OK
fun("hello"); // OK
fun(42); // Error
}
///////////////////////////
The reason for why it should work is that e.g. we can't pass a range as a `fun` argument. A workaround is to declare an overload, but that doesn't scale well with the number of parameters.
Comment #1 by dlang-bugzilla — 2021-05-13T05:59:22Z
Comment #2 by dlang-bugzilla — 2021-05-13T06:00:55Z
(In reply to Vladimir Panteleev from comment #1)
> Indeed, the example above works if modified simply by adding an overload:
>
> void fun()(float a) {}
Oops, never mind that, the compiler just casts int to float.
Comment #3 by dkorpel — 2024-10-23T10:20:56Z
*** Issue 24828 has been marked as a duplicate of this issue. ***
Comment #4 by maxsamukha — 2024-10-23T10:48:09Z
Why is this marked as enhancement with a low priority? It's a fundumental that doesn't work.
Comment #5 by maxsamukha — 2024-10-23T10:48:46Z
(In reply to Max Samukha from comment #4)
> Why is this marked as enhancement with a low priority? It's a fundumental
> that doesn't work.
*fundamental
Comment #6 by nick — 2024-10-23T11:07:02Z
> Looks like there is code to do this when resolving overloads:
I think that's now in templatesem.d, matchWithInstance:
// Shouldn't run semantic on default arguments and return type.
foreach (ref param; *tf.parameterList.parameters)
param.defaultArg = null;
Comment #7 by dkorpel — 2024-10-23T11:36:59Z
(In reply to Max Samukha from comment #4)
> Why is this marked as enhancement with a low priority? It's a fundumental
> that doesn't work.
A bug would be if the behavior doesn't follow the spec. The spec says:
> Default parameters are resolved and semantically checked in the context of the function declaration.
After template substitution, this issue's function looks like this:
```
void fun(int value = "hi")
```
In the context of that function, the compiler is correctly issuing an error, so changing the behavior would be an enhancement.
The lower priority could have been assigned because there's a workaround for it, I'm not sure. I wouldn't worry too much about it, issues are rarely sorted by bugzilla priority. The best way to get an issue fixed is to champion it, raise attention to it, or to work out the fix as detailed as possible so it's easy to implement.
In this case, one fix would be to lazily evaluate default arguments at the call site instead of the function declaration site, but that would break semantics of existing code.
Another fix would be to strip default arguments with semantic errors after template instantiation. That doesn't look like a breaking change:
```
void foo(T)(T x) {}
void foo(T)(T x = 3) {}
void main()
{
foo("a");
}
```
This gives an error "foo called with argument types `(string)` matches both ...", showing that default arguments are not considered for overload resolution.
Comment #8 by maxsamukha — 2024-10-23T14:01:06Z
(In reply to Dennis from comment #7)
>
> This gives an error "foo called with argument types `(string)` matches both
> ...", showing that default arguments are not considered for overload
> resolution.
Thank you for the explanation! The current semantics makes sense to me now. The fix that strips default arguments doesn't seem the right way to go.
What's the reason for this error:
void foo(T)(T a = T.init); // Error: undefined identifier `T`
void main()
{
foo(0);
foo("x");
foo();
}
?
It works with a default argument for the type parameter:
void foo(T = int)(T a = T.init); // ok
I'd be absolutely happy if this were fixed.
Comment #9 by maxsamukha — 2024-10-23T14:12:30Z
(In reply to Max Samukha from comment #8)
>
> What's the reason for this error:
>
See it now. Never mind. All seems good.
Comment #10 by maxsamukha — 2024-10-23T15:56:49Z
(In reply to Max Samukha from comment #9)
> All seems good.
Unfortunately, no. This compiles ok:
void foo(T = int)(T a = T.init)
{
}
void main()
{
foo();
foo("x");
}
But if there's another template parameter, the compiler tries to reuse the previous instantiation and fails:
void foo(U, T = int)(T a = T.init)
{
}
void main()
{
foo!bool(0);
foo!bool("x");
}
Is this a bug?
Comment #11 by maxsamukha — 2024-10-23T15:58:29Z
(In reply to Max Samukha from comment #10)
> void foo(U, T = int)(T a = T.init)
> {
> }
>
> void main()
> {
> foo!bool(0);
> foo!bool("x");
> }
>
Error: function `foo` is not callable using argument types `(string)`
Comment #12 by robert.schadek — 2024-12-13T19:16:23Z