You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The C# compiler does not allow the use of implicit method group conversion if the method only contains optional parameters:
voidMain(){Q(Y);// OkQ(Z);// CS1503 Argument 1: cannot convert from 'method group' to 'Action'// To do this, you currently need to use: // Q(() => Z());}publicvoidQ(Actiona){}publicvoidY(){}publicvoidZ(boolb=false){}
This proposal is to allow the conversion, effectively removing the CS1503 error at statement Q(Z);.
EDIT: The purpose of the proposal is to reduce keystrokes and increase readability. Q(Z) is more readable, and requires less typing, than Q(() => Z()) which is required today.
Notes
The current behavior should probably remain intact in the following scenarios.
An overload without parameters must take precedence, for backwards compatibility:
publicvoidZ(){}// resolves this overloadpublicvoidZ(boolb=false){}
The existence of more than one overload that only contains optional parameters is ambiguous and should probably not resolve:
There will be nothing "effective" about it because at best it should generate an intermediate lambda as @paulomorgado said. Default values have no effect on the declaration site, they are just additional metadata so they can be used at the call site. The thing is that when you use method group syntax or AddressOf in VB, you expect a direct delegate not an intermediate one.
Essentially, yes. It should be handled the same way as Q(Y), which is essentially the same as Q(() => Y()).
And what would it do in this case?
It would present the same error as today. As I stated in the title and description, this would only apply when all parameters are optional. Your example includes non-optional parameters.
@alrz The difference from today is overload resolution. Today overload resolution stops if there is no overload that contains zero parameters. My proposal is to continue evaluating overloads, choosing any overload which only has optional parameters (assuming there is only one).
Essentially, yes. It should be handled the same way as Q(Y), which is essentially the same as Q(() => Y()).
Why create another method? It should be just Q(new Action(Y)).
It would present the same error as today. As I stated in the title and description, this would only apply when all parameters are optional. Your example includes non-optional parameters.
What's so special about methods where all arguments are optional?
Why create another method? It should be just Q(new Action(Y)).
I never stated that it is creating another method, not sure where you got that from.
What's so special about methods where all arguments are optional?
The point of adding optional parameters to C# was to reduce the number of overloads that needed to be created in very similar cases. public void Z(bool b = false) { } used to require writing two methods:
publicvoidZ(){Z(false);}publicvoidZ(boolb){}
When written in this original way, without optional parameters, the call Q(Z) is legal. Simplifying the declaration by using an optional parameter to public void Z(bool b = false) { }should result in identical usage, but instead CS1503 is triggered now when calling Q(Z). That seems inconsistent.
This proposal is simply to allow the call Q(Z) even when using the simpler syntax.
Why create another method? It should be just Q(new Action(Y)).
I never stated that it is creating another method, not sure where you got that from.
From here:
Q(() => Z());
which is something like:
class Program
{
void Main()
{
Q(new Action(<Main>b__0_0));
}
public void Q(Action a) { }
public void Z(bool b = false) { }
private void <Main>b__0_0() { Z(); }
}
The point of adding optional parameters to C# was to reduce the number of overloads that needed to be created in very similar cases.
That's your assumption which you'll find impossible to backup with the spec. But even if that was true, that wouldn't make parameterless methods or methods with all parameters optional any special in relation to methods with parameters and methods with mandatory and optional arguments.
(...) That seems inconsistent.
Not at all. Methods with optional arguments are methods that have parameters with default values that compilers can use for arguments not specified but that do exist.
I never stated that an intermediate method is being generated. You suggested that, not me. I'm saying that the compiler generates the same IL for Q(Z) as it would for Q(() => Z()). (Or, I'm open to other mechanisms, but please don't choose one then use that as a strawman.)
that wouldn't make parameterless methods or methods with all parameters optional any special in relation to methods with parameters and methods with mandatory and optional arguments.
You're wrong, parameterless methods are treated special as they are allowed to be passed as a method group to Q whereas methods with mandatory arguments are not:
publicvoidM(){}publicvoidN(inti){}
...Q(M);// legalQ(N);// not legal
Besides, the point of it being a proposal is to do something that isn't currently possible, and I provided a reason why it is worthwhile. Do you have an argument for why it shouldn't be done?
I never stated that an intermediate method is being generated. You suggested that, not me. I'm saying that the compiler generates the same IL for Q(Z) as it would for Q(() => Z()).
In other words, by creating an intermediate method.
@gafter Sorry, I wasn't where I could check. I see now.
@paulomorgado So what is the problem then? If it's already creating an intermediate method for Q(Y) then why are you against it doing the same for Q(Z)?
@gafter I stated that wrong (meant to say Q(() => Z) instead of Q(Y)). My point remains, is there a problem with doing this by generating the intermediate method?
@paulomorgado Considering I've reworked reflection code in third party libraries that build runtime method calls in order to make them work similarly with methods that have optional arguments and those that do not, I think I do have a clue what it is about and how it works.
I know I don't know everything about the subject, so let me assume that you're right and I don't have a clue. Throw me a bone here. What you haven't told me is a straight answer why this is a bad idea, or why it can't work.
The way I understand this works is that proposals have to stand on their onw to be accepted. They are not accepted because no one is against it.
I still don't understand why methods without arguments and methods with all arguments optional are so different than others.
For some reason, optional arguments are in Visual Basic since the beginning and not in C#. My opinion is that they do more harm than good and should never be used in public APIs.
The way I understand this works is that proposals have to stand on their onw to be accepted. They are not accepted because no one is against it.
But that's not what is happening here. I made my case why it is useful. But you were pushing back without actually saying what you didn't like about it.
I still don't understand why methods without arguments and methods with all arguments optional are so different than others.
I don't understand a lot of things. I simply refrain from giving my opinion instead of fighting against it, why can't you do the same?
I want to be able to reduce Q(() => Z()) to Q(Z). This uses fewer keystrokes and is more readable.
I updated the description to include that purpose, in case that wasn't clear.
For some reason, optional arguments are in Visual Basic since the beginning and not in C#. My opinion is that they do more harm than good and should never be used in public APIs.
They can be abused, but so can arguments and overloading in general. With care, they can be useful. Even when abused, their "harm" is fairly benign in the grand scheme of things.
I would like to hear more of your thoughts on the matter. Even so, they already exist and third-party APIs use them. Regardless of whether we would declare methods with optional parameters, we may have to use them. This proposal is to make them easier to use, not easier to define.
This discussion was converted from issue #484 on September 08, 2020 20:15.
Heading
Bold
Italic
Quote
Code
Link
Numbered list
Unordered list
Task list
Attach files
Mention
Reference
Menu
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
@bondsbw commented on Fri May 06 2016
The C# compiler does not allow the use of implicit method group conversion if the method only contains optional parameters:
This proposal is to allow the conversion, effectively removing the CS1503 error at statement
Q(Z);
.EDIT: The purpose of the proposal is to reduce keystrokes and increase readability.
Q(Z)
is more readable, and requires less typing, thanQ(() => Z())
which is required today.Notes
The current behavior should probably remain intact in the following scenarios.
An overload without parameters must take precedence, for backwards compatibility:
The existence of more than one overload that only contains optional parameters is ambiguous and should probably not resolve:
@paulomorgado commented on Sat May 07 2016
@bondsbw, how do you propose that to be implemented?
Are you aware that
public void Z(bool b = false) { }
cannot be anAction
?Are you proposing that the compiler do this:
And what would it do in this case?
@alrz commented on Sat May 07 2016
There will be nothing "effective" about it because at best it should generate an intermediate lambda as @paulomorgado said. Default values have no effect on the declaration site, they are just additional metadata so they can be used at the call site. The thing is that when you use method group syntax or
AddressOf
in VB, you expect a direct delegate not an intermediate one.@bondsbw commented on Sat May 07 2016
@paulomorgado
Essentially, yes. It should be handled the same way as
Q(Y)
, which is essentially the same asQ(() => Y())
.It would present the same error as today. As I stated in the title and description, this would only apply when all parameters are optional. Your example includes non-optional parameters.
@bondsbw commented on Sat May 07 2016
@alrz The difference from today is overload resolution. Today overload resolution stops if there is no overload that contains zero parameters. My proposal is to continue evaluating overloads, choosing any overload which only has optional parameters (assuming there is only one).
@paulomorgado commented on Sat May 07 2016
@bondsbw,
Why create another method? It should be just
Q(new Action(Y))
.What's so special about methods where all arguments are optional?
@bondsbw commented on Sat May 07 2016
@paulomorgado
I never stated that it is creating another method, not sure where you got that from.
The point of adding optional parameters to C# was to reduce the number of overloads that needed to be created in very similar cases.
public void Z(bool b = false) { }
used to require writing two methods:When written in this original way, without optional parameters, the call
Q(Z)
is legal. Simplifying the declaration by using an optional parameter topublic void Z(bool b = false) { }
should result in identical usage, but instead CS1503 is triggered now when callingQ(Z)
. That seems inconsistent.This proposal is simply to allow the call
Q(Z)
even when using the simpler syntax.@paulomorgado commented on Sat May 07 2016
@bondsbw,
From here:
which is something like:
That's your assumption which you'll find impossible to backup with the spec. But even if that was true, that wouldn't make parameterless methods or methods with all parameters optional any special in relation to methods with parameters and methods with mandatory and optional arguments.
Not at all. Methods with optional arguments are methods that have parameters with default values that compilers can use for arguments not specified but that do exist.
@bondsbw commented on Sat May 07 2016
@paulomorgado
I never stated that an intermediate method is being generated. You suggested that, not me. I'm saying that the compiler generates the same IL for
Q(Z)
as it would forQ(() => Z())
. (Or, I'm open to other mechanisms, but please don't choose one then use that as a strawman.)You're wrong, parameterless methods are treated special as they are allowed to be passed as a method group to
Q
whereas methods with mandatory arguments are not:Besides, the point of it being a proposal is to do something that isn't currently possible, and I provided a reason why it is worthwhile. Do you have an argument for why it shouldn't be done?
@gafter commented on Sun May 08 2016
@bondsbw
In other words, by creating an intermediate method.
@bondsbw commented on Sun May 08 2016
@gafter Sorry, I wasn't where I could check. I see now.
@paulomorgado So what is the problem then? If it's already creating an intermediate method for
Q(Y)
then why are you against it doing the same forQ(Z)
?@gafter commented on Sun May 08 2016
@bondsbw It does not create an intermediate method for
Q(Y)
. It usesY
directly, asY
has the correct CLR signature.@bondsbw commented on Sun May 08 2016
@gafter I stated that wrong (meant to say
Q(() => Z)
instead ofQ(Y)
). My point remains, is there a problem with doing this by generating the intermediate method?@bondsbw commented on Sun May 08 2016
Or by making
new Action(Z)
work? I figure that might require a CLR change.@paulomorgado commented on Mon May 09 2016
@bondsbw, I think you still have no idea what optional arguments is all about and how it works.
Once you do, you'll understand what your proposal(s) involve.
@bondsbw commented on Mon May 09 2016
@paulomorgado Considering I've reworked reflection code in third party libraries that build runtime method calls in order to make them work similarly with methods that have optional arguments and those that do not, I think I do have a clue what it is about and how it works.
I know I don't know everything about the subject, so let me assume that you're right and I don't have a clue. Throw me a bone here. What you haven't told me is a straight answer why this is a bad idea, or why it can't work.
@paulomorgado commented on Mon May 09 2016
@bondsbw,
The way I understand this works is that proposals have to stand on their onw to be accepted. They are not accepted because no one is against it.
I still don't understand why methods without arguments and methods with all arguments optional are so different than others.
For some reason, optional arguments are in Visual Basic since the beginning and not in C#. My opinion is that they do more harm than good and should never be used in public APIs.
@bondsbw commented on Mon May 09 2016
@paulomorgado
But that's not what is happening here. I made my case why it is useful. But you were pushing back without actually saying what you didn't like about it.
I don't understand a lot of things. I simply refrain from giving my opinion instead of fighting against it, why can't you do the same?
I want to be able to reduce
Q(() => Z())
toQ(Z)
. This uses fewer keystrokes and is more readable.I updated the description to include that purpose, in case that wasn't clear.
@bondsbw commented on Mon May 09 2016
@paulomorgado
They can be abused, but so can arguments and overloading in general. With care, they can be useful. Even when abused, their "harm" is fairly benign in the grand scheme of things.
I would like to hear more of your thoughts on the matter. Even so, they already exist and third-party APIs use them. Regardless of whether we would declare methods with optional parameters, we may have to use them. This proposal is to make them easier to use, not easier to define.
Can we make lemonade out of the lemons?
Beta Was this translation helpful? Give feedback.
All reactions