-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Do not use optional arguments on public APIs #13995
Comments
Parameters are what the method specified as being required. I have no problem with optional parameter on Public APIs, since VB.net has them for like forever :) That section of
Note: I also reorder one of the guards so if the If the constructor of Imagine that the original API used optional arguments and there was only one Save method. How would you keep that and now add an CancellationToken parameter? It would be a new method |
@paulomorgado I'd be curious to know your reasons for being so strongly against optional parameters on public methods. I know in the past .NET has had a similar policy, but I don't know if that's being carried into CoreCLR or not -- it seems like an old school restriction IMO. Your proposal that object initializers can effectively emulate optional parameters is insufficient when the object you're constructing is immutable, which is becoming increasingly popular. But optional parameters work really well in these cases from what I've observed. |
We've been playing around with a proposal from the Roslyn guys around how to version methods with optional parameters, this was the last thing that was preventing us from using them. Imagine we shipped V1 with the following:
V2 comes along and we want to add CancellationToken parameter so that the operation can be cancelled. You first make the original overload non-optional (binaries built against it will continue to run):
Then you introduce a second overload is that optional:
This covers the recompile case and dynamic binding cases. They pick up the new overload, but we would guarantee that the behavior was the same. |
@AdamSpeight2008, @AdamSpeight2008, @AArnott, @davkean, I'm sure you know that the default argument will be hardcoded on the caller and, without recompilation, the callee cannot change it. Also, for all intents and purposes, all arguments must be passed. Am I the only one that finds ridiculous that the solution to versioning not using overloads is using overloads? Why not stick with them in the first place? If you really are thinking to follow this path, you must be dead sure about what you're doing and that the defaults will never change. Because it might not be possible to recompile all the code using those libraries. And, also, only use optional arguments when it's default value is the default value for its type:
By the way, @AArnott, I could argue that using optional arguments is "old school" for those that lived too much time in languages that do not have overloads think that optional arguments is just the same thing done different. @AArnott, I'm sorry but I don't understand what mutability or immutability has to do with this. And what comes next? Publicly accessible field constants? |
Paulo, Yes, we would never change defaults for optional arguments. We already avoid changing defaults values for overloads - turns out people rely on them. :) Dave |
VB has lacked |
@paulomorgado Object initializers only work when objects are mutable. If the object is immutable, an object initializer doesn't work because you have no settable properties or fields. Therefore, to initialize the object either the number of constructor/factory method overloads you have either grows exponentially with the number of fields, or you have fewer overloads than some will find helpful, or... you use optional parameters on just a very few overloads. Publicly accessible field constants? We already have those, too. I was surprised just a few months ago by this as well, but evidently when you have a singleton pattern, it is sometimes acceptable to make a public static readonly field on a type rather than a private static readonly field with a public static property getter. One reason for this is the JIT actually can do better with fields than properties (I know that's against some of the claims, but it's sadly true). I don't mean to defend the policy, I'm just saying it's not next because it's already here. :-| |
@AArnott, the compiler doesn't handle Take these sample classes:
This code:
will be compiled to:
If you later change That's the same with Optional arguments behave the same way as const fields, not static readonly fields. What on the framework is already being exposed as a public const field? And I don't by into this immutability fundamentalism. Immutability is good when it's good for the good reasons. The settings objects that I'm talking about are just DTOs or messages. If you look at the reference implementations I mentioned, you'll see that the code, although using these objects, doesn't old on to them - and it could be better. |
I'm well aware of that. I try not to and sometimes I prefer to call the big overload with all the documented defaults, just in case you change them without my authorization. 😄 Let's get back to the example of
And later we decide to add a cancellation token. Using the mentioned pattern, we remove the default argument value of the old method and put it in the new:
Either using proper overloads or optional arguments, seems obvious that the behavior of first method is the same as the behavior of the second. So, we just call the second from the first with the default value:
Plain old school traditional overloading techniques. Except that we are now writing the default value in two places. I'm not totally against optional arguments. I'm pretty fine with them when there's no way to change them without the callers also being recompiled. Like this:
|
Are XmlReader and XmlWriter part of CoreFX? |
Found this on a quick search. I haven't found the code for But, does it really matter, @AdamSpeight2008? |
I spotted a couple of places where we could remove an unnecessary object initialisation. A small perf improvement. Planned to do a pull request but couldn't locate XmlReader. |
XmlReader/XmlWriter are not published yet but they are on our list, no ETA yet however. |
Can this issue be closed now? Is there an action associated with this at this point? |
I'm curious on what the final decision was. Using optional arguments? Ho about versioning? |
Since this was bumped...
|
We do not recommend using optional args. Closing this thread as there is no actions expected. |
👍 |
As part of the discussion around adding async document/element loading for XLINQ (#110) it was mentioned using optional arguments (commonly called optional parameters).
PLEASE, DON'T USE IT ON PUBLIC APIS!!!
Before there were optional arguments the problem of a large number of possible parameters for an API already existed. And since we are talking about XML, look at how
XmlReader
andXmlWritter
solved it:Taking advantage of object initialization, calling it looks like optional arguments:
(I'm going to propose more type inference for cases like this: Do not require type specification for constructors when the type is known dotnet/runtime#13855)
It's extensible. Another setting can always be added with proper defaults and without breaking existing code.
And those settings also become something that can be passed around.
Imagine that the original API used optional arguments and there was only one
Save
method. How would you keep that and now add anCancellationToken
parameter?The text was updated successfully, but these errors were encountered: