Please bear with me, this is not (quite!) a duplicate of any of these SO answers:
Conflicting overloaded methods with optional parameters
Overload Resolution and Optional Parameters in C# 4
Call overload method with default parameters
When trying to "influence" what overload the compiler will choose given conflicts arising from optional parameters, answers in the above posts reference the C# Programming Guide, which indicates the overload resolution (OR) heuristics at play here:
If two candidates are judged to be equally good, preference goes to a candidate that does not have optional parameters for which arguments were omitted in the call.
Fair enough. My question is, why doesn't (or why can't) the Obsolete attribute (or some other markup) influence the OR decision on judging two candidates to be equally good? For example, consider the following overloads:
[Obsolete(“This method is deprecated.”)]
[EditorBrowsable(EditorBrowsableState.Never)]]
bool foo() { return true; }
bool foo(bool optional = false) { return optional; }
It seems OR should not judge these overloads to be equally good--the non-deprecated overload with an optional parameter should win. If this were the case in this over-simplified example, code previously compiled for foo() would be backwards compatible and happily continue to return true. Future code compiled for this library could also call foo(), but that resolved overload would return false.
Is this a valuable/possible feature we are missing from the language? Or is there any other way to make this wish of mine work? Thanks for any insights,
-Mike
Overload resolution is a very tricky thing to get right, and language designers think long and hard about exactly what the rules should be. The more different considerations and special cases you add, the likely language users are to run into obscure gotchas where it doesn't quite work the way they'd expect. I don't believe adding this new condition to overload resolution would be a valuable addition to the language.
If OR did prefer the method without the ObsoluteAttribute, then the only way to invoke the obsolete method without reflection would be something like this:
((Action)obj.foo)();
And if this were a generic method, there would be no way to call it with an anonymous type parameter. This would definitely be surprising behavior (at least to me).
The ObsoleteAttribute (declared with IsError = false) is a way for you to provide a hint for your consumers to update their code without completely removing the previous capabilities. Typically you want to do this if you plan to remove the feature in a future version. If you want to prohibit them from calling this method entirely, you can either:
Set IsError = true with [Obsolete("This method is deprecated.", true)] so that if the code is re-compiled, it generates an error rather than a warning. It could still be called via reflection.
Remove the deprecated function entirely. It cannot be called via reflection.
It's an interesting question. Still, I prefer it the way it is for the following reasons:
Simplicity
OR depends on method signature compiled to module and it is intuitive at that. Depending on any attributes would change the dependency scope to a wider "thing" and start snowballing - should you consider maybe another attribute? Or attributes on arguments, etc..
Change management
Method signatures & OR are different concern than the deprecation marker attribute. The latter is metadata and if it started to affect OR from one point on, then it would possibly break many existing applications. Especially libraries where deprecation cycle is longer for a reason.
I would be very annoyed if a functionally tested code started to behave different after a soft decision that a certain part of code will be phased out in "undetermined future".
All in all having code like this ...
[Obsolete(“This method is deprecated.”)]
bool foo() { return true; }
bool foo(bool optional = false) { return optional; }
stinks. The compiler will apply an algorithm to select the right method when you call foo() but any developer looking at the code will need to know (and to apply) that algorithm to understand what the code does so maintainability of the code will decrease a lot.
Simply remove the optional in this case as it hurts more than anything else.
The following line has the error Default argument is not allowed.
public ref class SPlayerObj{
private:
void k(int s = 0){ //ERROR
}
}
Why C++ has no default argument on managed types ?
I would like to know if there is a way to fix this.
It does have optional arguments, they just don't look the same way as the C++ syntax. Optional arguments are a language interop problem. It must be implemented by the language that makes the call, it generates the code that actually uses the default argument. Which is a tricky problem in a language that was designed to make interop easy, like C++/CLI, you of course don't know what language is going to make the call. Or if it even has syntax for optional arguments. The C# language didn't until version 4 for example.
And if the language does support it, how that compiler knows what the default value is. Notable is that VB.NET and C# v4 chose different strategies, VB.NET uses an attribute, C# uses a modopt.
You can use the [DefaultParameterValue] attribute in C++/CLI. But you shouldn't, the outcome is not predictable.
In addition to the precise answer from Hans Passant, the answer to the second part on how to fix this, you are able to use multiple methods with the same name to simulate the default argument case.
public ref class SPlayerObj {
private:
void k(int s){ // Do something useful...
}
void k() { // Call the other with a default value
k(0);
}
}
An alternative solution is to use the [OptionalAttribute] along side a Nullable<int> typed parameter. If the parameter is not specified by the caller it will be a nullptr.
void k([OptionalAttribute]Nullable<int>^ s)
{
if(s == nullptr)
{
// s was not provided
}
else if(s->HasValue)
{
// s was provided and has a value
int theValue = s->Value;
}
}
// call with no parameter
k();
// call with a parameter value
k(100);
I've recently had a strange issue with one of my APIs reported. Essentially for some reason when used with VB code the VB compiler does not do implicit casts to Object when trying to invoke the ToString() method.
The following is a minimal code example firstly in C# and secondly in VB:
Graph g = new Graph();
g.LoadFromEmbeddedResource("VDS.RDF.Configuration.configuration.ttl");
foreach (Triple t in g.Triples)
{
Console.WriteLine(t.Subject.ToString());
}
The above compiles and runs fine while the below does not:
Dim g As Graph = New Graph()
g.LoadFromEmbeddedResource("VDS.RDF.Configuration.configuration.ttl")
For Each t As Triple In g.Triples
Console.WriteLine(t.Subject.ToString())
Next
The second VB example gives the following compiler exception:
Overload resolution failed because no
accessible 'ToString' accepts this
number of arguments.
This appears to be due to the fact that the type of the property t.Subject that I am trying to write to the console has explicitly defined ToString() methods which take parameters. The VB compiler appears to expect one of these to be used and does not seem to implicitly cast to Object and use the standard Object.ToString() method whereas the C# compiler does.
Is there any way around this e.g. a VB compiler option or is it best just to ensure that the type of the property (which is an interface in this example) explicitly defines an unparameterized ToString() method to ensure compatability with VB?
Edit
Here are the additional details requested by Lucian
Graph is an implementation of an interface but that is actually irrelevant since it is the INode interface which is the type that t.Subject returns which is the issue.
INode defines two overloads for ToString() both of which take parameters
Yes it is a compile time error
No I do not use hide-by-name, the API is all written in C# so I couldn't generate that kind of API if I wanted to
Note that I've since added an explicit unparameterized ToString() overload to the interface which has fixed the issue for VB users.
RobV, I'm the VB spec lead, so I should be able to answer your question, but I'll need some clarification please...
What are the overloads defined on "Graph"? It'd help if you could make a self-contained repro. It's hard to explain overloading behavior without knowing the overload candidates :)
You said it failed with a "compiler exception". That doesn't really exist. Do you mean a "compile-time error"? Or a "run-time exception"?
Something to check is whether you're relying on any kind of "hide-by-name" vs "hide-by-sig" behavior. C# compiler only ever emits "hide-by-sig" APIs; VB compiler can emit either depending on whether you use the "Shadows" keyword.
C# overload algorithm is to walk up the inheritance hierarchy level by level until it finds a possible match; VB overload algorithm is to look at all levels of the inheritance hierarchy simultaneously to see which has the best match. This is all a bit theoretical, but with a small self-contained repro of your problem I could explain what it means in practice.
Hans, I don't think your explanation is the right one. Your code gives compile-time error "BC30455: Argument not specified for parameter 'mumble' of ToString". But RobV had experienced "Overload resolution failed because no accessible 'ToString' accepts this number of arguments".
Here's a repro of this behavior. It also shows you the workaround, cast with CObj():
Module Module1
Sub Main()
Dim itf As IFoo = New CFoo()
Console.WriteLine(itf.ToString()) '' Error BC30455
Console.WriteLine(CObj(itf).ToString()) '' Okay
End Sub
End Module
Interface IFoo
Function ToString(ByVal mumble As Integer) As String
End Interface
Class CFoo
Implements IFoo
Function ToString1(ByVal mumble As Integer) As String Implements IFoo.ToString
Return "foo"
End Function
End Class
I think this is annotated in the VB.NET Language Specification, chapter 11.8.1 "Overloaded method resolution":
The justification for this rule is
that if a program is loosely-typed
(that is, most or all variables are
declared as Object), overload
resolution can be difficult because
all conversions from Object are
narrowing. Rather than have the
overload resolution fail in many
situations (requiring strong typing of
the arguments to the method call),
resolution the appropriate overloaded
method to call is deferred until run
time. This allows the loosely-typed
call to succeed without additional
casts.
An unfortunate side-effect of this,
however, is that performing the
late-bound call requires casting the
call target to Object. In the case of
a structure value, this means that the
value must be boxed to a temporary. If
the method eventually called tries to
change a field of the structure, this
change will be lost once the method
returns.
Interfaces are excluded from this
special rule because late binding
always resolves against the members of
the runtime class or structure type,
which may have different names than
the members of the interfaces they
implement.
Not sure. I'd transliterate it as: VB.NET is a loosely typed language where many object references are commonly late bound. This makes method overload resolution perilous.
I use Stylecop for Resharper and whenever I call something in my class, Stylecop tells me to use the this keyword. But the IDE says this is redundant code (which it sure is), so why should I use the this keyword?
Does redundant code mean its not needed (obviously) and the compiler won't even do anything with the this keyword? So I assume the this keyword is just for clarity.
Also, with the CLR, do things like this fall consistently across languages? So if the answer is that the compiler doesn't even touch the this keyword and it is just for presentation and clarity, then the same is true for VB.NET? I assume it is all for clarity as stylecop keeps an eye on this and Fxcop (which I will use later on) keeps an eye on my code's quality from a technical point of view.
Thanks
It's for clarity and to prevent any ambiguity between a class member and a local variable or parameter with the same name.
The IL it compiles to will not be any different.
Most of the time is just for clarity but some times it is required.
using System;
class Foo
{
String bar;
public Foo(String bar)
{
this.bar = bar;
}
}
Here you will need this as it serves to disambiguate between the field bar and the constructor parameter bar. Obviously changing the name of the parameter or field could accomplish the same thing.
In all cases, there is no performance difference with/without the this - the compiler still does it implicitly, injecting a ldarg.0 into the IL.
Just for completeness, there is one other mandatory use of this (excluding disambiguation, ctor-chaining, and passing this to other methods): extension methods. To call an extension method on the current instance, you must qualify with this (even though for a regular method it would be implicit).
Of course, in most cases, you would simply add a regular instance method to the class or a base-class...
class Foo {
void Test() {
this.Bar(); // fine
Bar(); // compiler error
}
}
static class FooExt {
public static void Bar(this Foo foo) { }
}
In C# this is a reference to the current instance of the class (it's me in VB.NET). It's used generally to fully qualify a class member. For example, consider this C# class:
public class MyClass
{
int rate;
private void testMethod()
{
int x;
x = this.rate;
}
}
this isn't required in the code above, but adds instant clarity when reading the code that rate belongs to the class rather than the method (search SO, you'll find lots of opinions about the use of this). It's semantic behavior is the same in VB--and its use doesn't impose a performance penalty.
Apart from the clarity examples provided the only other valid usage of the "this" keyword is to pass the current instance of an object as a paremeter.
It is just for clarity, and one can argue about what is better. Python doesn't support omitting the "self" identifier at all.
Also, with the CLR, do things like this fall consistently across languages? So if the answer is that the compiler doesn't even touch the this keyword and it is just for presentation and clarity, then the same is true for VB.NET?
In JVM for sure (and also for CLR, I'm almost sure) the code for the "this" keyword is always generated, even if that is omitted from the source - so it's like if the this keyword is always added. So, I don't think that any .NET compiler could generate different output, so there can't be a performance penalty.
Then, it depends on the language. For instance JScript (and even JScript.NET) does not allow to omit "this", like Python, because there are functions (so "this.a()" is a method invocation, "a()" is a function invocation), and because the compiler does not know the members of any types - they're only known at runtime (well, this is not an impossible problem to solve indeed, the other issue is more relevant).
I was watching Anders' talk about C# 4.0 and sneak preview of C# 5.0, and it got me thinking about when optional parameters are available in C# what is going to be the recommended way to declare methods that do not need all parameters specified?
For example something like the FileStream class has about fifteen different constructors which can be divided into logical 'families' e.g. the ones below from a string, the ones from an IntPtr and the ones from a SafeFileHandle.
FileStream(string,FileMode);
FileStream(string,FileMode,FileAccess);
FileStream(string,FileMode,FileAccess,FileShare);
FileStream(string,FileMode,FileAccess,FileShare,int);
FileStream(string,FileMode,FileAccess,FileShare,int,bool);
It seems to me that this type of pattern could be simplified by having three constructors instead, and using optional parameters for the ones that can be defaulted, which would make the different families of constructors more distinct [note: I know this change will not be made in the BCL, I'm talking hypothetically for this type of situation].
What do you think? From C# 4.0 will it make more sense to make closely related groups of constructors and methods a single method with optional parameters, or is there a good reason to stick with the traditional many-overload mechanism?
I'd consider the following:
Do you need your code to be used from languages which don't support optional parameters? If so, consider including the overloads.
Do you have any members on your team who violently oppose optional parameters? (Sometimes it's easier to live with a decision you don't like than to argue the case.)
Are you confident that your defaults won't change between builds of your code, or if they might, will your callers be okay with that?
I haven't checked how the defaults are going to work, but I'd assume that the default values will be baked into the calling code, much the same as references to const fields. That's usually okay - changes to a default value are pretty significant anyway - but those are the things to consider.
When a method overload normally performs the same thing with a different number of arguments then defaults will be used.
When a method overload performs a function differently based on its parameters then overloading will continue to be used.
I used optional back in my VB6 days and have since missed it, it will reduce a lot of XML comment duplication in C#.
I've been using Delphi with optional parameters forever. I've switched to using overloads instead.
Because when you go to create more overloads, you'll invariably conflict with an optional parameter form, and then you'll have to convert them to non-optional anyway.
And I like the notion that there's generally one super method, and the rest are simpler wrappers around that one.
I will definitely be using the optional parameters feature of 4.0. It gets rid of the ridiculous ...
public void M1( string foo, string bar )
{
// do that thang
}
public void M1( string foo )
{
M1( foo, "bar default" ); // I have always hated this line of code specifically
}
... and puts the values right where the caller can see them ...
public void M1( string foo, string bar = "bar default" )
{
// do that thang
}
Much more simple and much less error prone. I've actually seen this as a bug in the overload case ...
public void M1( string foo )
{
M2( foo, "bar default" ); // oops! I meant M1!
}
I have not played with the 4.0 complier yet, but I would not be shocked to learn that the complier simply emits the overloads for you.
Optional parameters are essentially a piece of metadata which directs a compiler that's processing a method call to insert appropriate defaults at the call site. By contrast, overloads provide a means by which a compiler can select one of a number of methods, some of which might supply default values themselves. Note that if one tries to call a method that specifies optional parameters from code written in a language which doesn't support them, the compiler will require that the "optional" parameters be specified, but since calling a method without specifying an optional parameter is equivalent to calling it with a parameter equal to the default value, there's no obstacle to such languages calling such methods.
A significant consequence of binding of optional parameters at the call site is that they will be assigned values based upon the version of the target code which is available to the compiler. If an assembly Foo has a method Boo(int) with a default value of 5, and assembly Bar contains a call to Foo.Boo(), the compiler will process that as a Foo.Boo(5). If the default value is changed to 6 and assembly Foo is recompiled, Bar will continue to call Foo.Boo(5) unless or until it is recompiled with that new version of Foo. One should thus avoid using optional parameters for things that might change.
It can be argued whether optional arguments or overloads should be used or not, but most importantly, each have their own area where they are irreplaceable.
Optional arguments, when used in combination with named arguments, are extremely useful when combined with some long-argument-lists-with-all-optionals of COM calls.
Overloads are extremely useful when method is able to operate on many different argument types (just one of examples), and does castings internally, for instance; you just feed it with any data type that makes sense (that is accepted by some existing overload). Can't beat that with optional arguments.
In many cases optional parameters are used to switch execution. For example:
decimal GetPrice(string productName, decimal discountPercentage = 0)
{
decimal basePrice = CalculateBasePrice(productName);
if (discountPercentage > 0)
return basePrice * (1 - discountPercentage / 100);
else
return basePrice;
}
Discount parameter here is used to feed the if-then-else statement. There is the polymorphism that wasn't recognized, and then it was implemented as an if-then-else statement. In such cases, it is much better to split the two control flows into two independent methods:
decimal GetPrice(string productName)
{
decimal basePrice = CalculateBasePrice(productName);
return basePrice;
}
decimal GetPrice(string productName, decimal discountPercentage)
{
if (discountPercentage <= 0)
throw new ArgumentException();
decimal basePrice = GetPrice(productName);
decimal discountedPrice = basePrice * (1 - discountPercentage / 100);
return discountedPrice;
}
In this way, we have even protected the class from receiving a call with zero discount. That call would mean that the caller thinks that there is the discount, but in fact there is no discount at all. Such misunderstanding can easily cause a bug.
In cases like this, I prefer not to have optional parameters, but to force the caller explicitly select the execution scenario that suits its current situation.
The situation is very similar to having parameters that can be null. That is equally bad idea when implementation boils to statements like if (x == null).
You can find detailed analysis on these links: Avoiding Optional Parameters and Avoiding Null Parameters
One caveat of optional parameters is versioning, where a refactor has unintended consequences. An example:
Initial code
public string HandleError(string message, bool silent=true, bool isCritical=true)
{
...
}
Assume this is one of many callers of the above method:
HandleError("Disk is full", false);
Here the event is not silent and is treated as critical.
Now let's say after a refactor we find that all errors prompt the user anyway, so we no longer need the silent flag. So we remove it.
After refactor
The former call still compiles, and let's say it slips through the refactor unchanged:
public string HandleError(string message, /*bool silent=true,*/ bool isCritical=true)
{
...
}
...
// Some other distant code file:
HandleError("Disk is full", false);
Now false will have an unintended effect, the event will no longer be treated as critical.
This could result in a subtle defect, since there will be no compile or runtime error (unlike some other caveats of optionals, such as this or this).
Note that there are many forms of this same problem. One other form is outlined here.
Note also that strictly using named parameters when calling the method will avoid the issue, such as like this: HandleError("Disk is full", silent:false). However, it may not be practical to assume that all other developers (or users of a public API) will do so.
For these reasons I would avoid using optional parameters in a public API (or even a public method if it might be used widely) unless there are other compelling considerations.
One of my favourites aspects of optional parameters is that you see what happens to your parameters if you do not provide them, even without going to the method definition. Visual Studio will simply show you the default value for the parameter when you type the method name. With an overload method you are stuck with either reading the documentation (if even available) or with directly navigating to the method's definition (if available) and to the method that the overload wraps.
In particular: the documentation effort may increase rapidly with the amount of overloads, and you will probably end up copying already existing comments from the existing overloads. This is quite annoying, as it does not produce any value and breaks the DRY-principle). On the other hand, with an optional parameter there's exactly one place where all the parameters are documented and you see their meaning as well as their default values while typing.
Last but not least, if you are the consumer of an API you may not even have the option of inspecting the implementation details (if you don't have the source code) and therefore have no chance to see to which super method the overloaded ones are wrapping. Thus you're stuck with reading the doc and hoping that all default values are listed there, but this is not always the case.
Of course, this is not an answer that handles all aspects, but I think it adds one which has not be covered so far.
I'm looking forward to optional parameters because it keeps what the defaults are closer to the method. So instead of dozens of lines for the overloads that just call the "expanded" method, you just define the method once and you can see what the optional parameters default to in the method signature. I'd rather look at:
public Rectangle (Point start = Point.Zero, int width, int height)
{
Start = start;
Width = width;
Height = height;
}
Instead of this:
public Rectangle (Point start, int width, int height)
{
Start = start;
Width = width;
Height = height;
}
public Rectangle (int width, int height) :
this (Point.Zero, width, height)
{
}
Obviously this example is really simple but the case in the OP with 5 overloads, things can get crowded real quick.
While they are (supposedly?) two conceptually equivalent ways available for you to model your API from scratch, they unfortunately have some subtle difference when you need to consider runtime backward compatibility for your old clients in the wild. My colleague (thanks Brent!) pointed me to this wonderful post: Versioning issues with optional arguments. Some quote from it:
The reason that optional parameters were introduced to C# 4 in the
first place was to support COM interop. That’s it. And now, we’re
learning about the full implications of this fact. If you have a
method with optional parameters, you can never add an overload with
additional optional parameters out of fear of causing a compile-time
breaking change. And you can never remove an existing overload, as
this has always been a runtime breaking change. You pretty much need
to treat it like an interface. Your only recourse in this case is to
write a new method with a new name. So be aware of this if you plan to
use optional arguments in your APIs.
To add a no-brainer when to use an overload instead of optionals:
Whenever you have a number of parameters that only make sense together, do not introduce optionals on them.
Or more generally, whenever your method signatures enable usage patterns which don't make sense, restrict the number of permutations of possible calls. E.g., by using overloads instead of optionals (this rule also holds true when you have several parameters of the same datatype, by the way; here, devices like factory methods or custom data types can help).
Example:
enum Match {
Regex,
Wildcard,
ContainsString,
}
// Don't: This way, Enumerate() can be called in a way
// which does not make sense:
IEnumerable<string> Enumerate(string searchPattern = null,
Match match = Match.Regex,
SearchOption searchOption = SearchOption.TopDirectoryOnly);
// Better: Provide only overloads which cannot be mis-used:
IEnumerable<string> Enumerate(SearchOption searchOption = SearchOption.TopDirectoryOnly);
IEnumerable<string> Enumerate(string searchPattern, Match match,
SearchOption searchOption = SearchOption.TopDirectoryOnly);
Both Optional parameter , Method overload have there own advantage or disadvantage.it depends on your preference to choose between them.
Optional Parameter:
available only in .Net 4.0.
optional parameter reduce your code size.
You can't define out and ref parameter
overloaded methods:
You can Define Out and ref parameters.
Code size will increase but overloaded method's are easy to understand.