Optional parameter in abstract class overriding derived [duplicate] - c#

This question already has answers here:
Why are C# 4 optional parameters defined on interface not enforced on implementing class?
(7 answers)
Closed 9 years ago.
In an abstract class
public abstract class base
{
abstract public int Func(bool flag = true);
}
I made a change in the derived version:
public class derived : base
{
public override int Func(bool flag = false){}
}
Debugging shows the compiler uses true as default. I expected otherwise, why does it behave thus?

This behavior is stated in the C# language specification at §7.5.1.1 (Corresponding Parameters, emphasis mine):
For each argument in an argument list there has to be a corresponding
parameter in the function member or delegate being invoked. The
parameter list used in the following is determined as follows:
For virtual methods and indexers defined in classes, the parameter list is
picked from the most specific declaration or override of the function
member, starting with the static type of the receiver, and searching
through its base classes
During binding (the process of associating the method to call to an invocation) the compiler finds a list of arguments using the rules stated above then a set of candidate methods conforming to that argument list. Among these the best one is picked and bound to the invocation.
Take this code:
BaseClass b = new DerivedClass( );
b.Func( );
During binding the argument list used is the one declared in BaseClass.Func (because that is the static type of b) and the set of candidate methods is BaseClass.Func and DerivedClass.Func (they are said to be applicable, because both argument list correspond to the one chosen). Then DerivedClass.Func is decided to be the best candidate, as expected, and therefore bound to the call using the parameter list of BaseClass.Func, thus using flag = true.
You can find more details in §7.5.3 (Overload resolution). Finally, in case you wonder, abstract methods are considered virtual, as noted in §10.6.6 (Abstract methods):
An abstract method declaration introduces a new virtual method but does not provide
an implementation of that method.

I've created a sample that mimics your situation. Long story short: which default value is used depends on whether you access the instance by a variable of the type of the base class or the derived class. So the compiler detects the default value of the optional parameter based on the type of variable. This makes sense as you could store any instance of a derived class in the variable (polymorphism). It might not even be clear at compile time, which the type if instance is (e.g. if you configure your system to use a specific type). All the compiler knows is the type of the variable and that any instance that you put into it in a type-safe manner offers the same interface.
using System;
public abstract class MyBase
{
public abstract bool GetValue(bool value = true);
}
public class MyDerived : MyBase
{
public override bool GetValue(bool value = false)
{
return value;
}
}
public class Test
{
public static void Main()
{
var derived = new MyDerived();
Console.WriteLine("Value = {0}", derived.GetValue());
MyBase myBase = derived;
Console.WriteLine("Value = {0}", myBase.GetValue());
}
}
I assume that you call the method on a variable of the type of the base class which would explain the behavior.
Basically, this resembles the behavior if you don't override the method but shadow it. It is a situation you will want to avoid in almost all circumstances because the risk that the code will not behave in the way you expect it is relatively high. Therefore I'd suggest to get rid of the optional parameters and make them required ones (and maybe create an overload without the parameter). Having to type less and being able to change the default value later is not worth the risk of having a unexpected behavior of your code. The behavior might be transparent to you now, but I doubt that it will be some months later or to coworkers of yours that have to maintain the code.

Related

Why can't C# infer generic class types based on constructor arguments? [duplicate]

Why is type inference not supported for constructors the way it is for generic methods?
public class MyType<T>
{
private readonly T field;
public MyType(T value) { field = value; }
}
var obj = new MyType(42); // why can't type inference work out that I want a MyType<int>?
Though you could get around this with a factory class,
public class MyTypeFactory
{
public static MyType<T> Create<T>(T value)
{
return new MyType<T>(value);
}
}
var myObj = MyTypeFactory.Create(42);
Is there a practical or philosophical reason why the constructor can't support type inference?
Is there a philosophical reason why the constructor can't support type inference?
No. When you have
new Foo(bar)
then we could identify all types called Foo in scope regardless of generic arity, and then do overload resolution on each using a modified method type inference algorithm. We'd then have to create a 'betterness' algorithm that determines which of two applicable constructors in two types that have the same name but different generic arity is the better constructor. In order to maintain backwards compatibility a ctor on a non-generic type must always win.
Is there a practical reason why the constructor can't support type inference?
Yes. Even if the benefit of the feature outweighs its costs -- which are considerable -- that's not sufficient to have a feature implemented. Not only does the feature have to be a net win, it has to be a large net win compared to all the other possible features we could be investing in. It also has to be better than spending that time and effort on bug fixing, performance work, and other possible areas that we could put that effort. And ideally it has to fit in well to whatever the "theme" is of the release.
Furthermore, as you correctly note, you can get the benefits of this feature without actually having the feature itself, by using a factory pattern. The existence of easy workarounds makes it less likely that a feature will ever be implemented.
This feature has been on the list of possible features for a long time now. It's never been anywhere near high enough on the list to actually get implemented.
UPDATE March 2015
The proposed feature made it close enough to the top of the list for C# 6 to be specified and designed, but was then cut.
public class MyType<T>
{
private readonly T field;
public MyType(T value) { field = value; }
}
they can, there is no need to tell the constructor 'what T is' again, seeing as you have already done that in the class decleration.
also your factory is incorrect, you need to have public class MyTypeFactory<T> not just public class MyTypeFactory - unless you declare the factory inside the MyType class
Edit for update:
Well, is 42 a long, a short, an int, or something else?
Let's say you have the following
class Base
{
public virtual void DoStuff() { Console.WriteLine("Base"); }
}
class Foo : Base
{
public override void DoStuff() { Console.WriteLine("Foo"); }
}
Then you did this
var c = new Foo();
var myType = new MyType(c);
Would you expect foo to be used, or base? We need to tell the compiler what to use in place of T
When you really wanted to on type base
Hence the
var myType = new MyType<Base>(c);
The main reason generic type inference can't work on constructors like you wish is because the class "MyType" doesn't even exist when all you've declared is "MyType<T>". Remember it is legal to have both:
public class MyType<T> {
}
and
public class MyType {
}
Both would be legal. How would you disambiguate your syntax if you did in fact declare both, and both of them declared a conflicting constructor.
The constructor needs to have the same generic specification as the class itself. Otherwise it would be impossible to know if the int in your example would relate to the class or to the constructor.
var obj = new MyType<int>(42);
Would that be class MyType<T> with constructor MyType(int) or class MyType with constructor MyType<T>(T)?
Although this has been answered many times before, I feel I need to clarify one thing: C# supports generic type inference on constructors. The problem is, it doesn't support neither adding generic parameters to constructors nor type generic type inference. Wanting to infer generic type argument of the type itself is basically the same as requiring Foo.Bar(0) to infer to Foo<int>.Bar(0).

Why can't C# infer this type? [duplicate]

Why is type inference not supported for constructors the way it is for generic methods?
public class MyType<T>
{
private readonly T field;
public MyType(T value) { field = value; }
}
var obj = new MyType(42); // why can't type inference work out that I want a MyType<int>?
Though you could get around this with a factory class,
public class MyTypeFactory
{
public static MyType<T> Create<T>(T value)
{
return new MyType<T>(value);
}
}
var myObj = MyTypeFactory.Create(42);
Is there a practical or philosophical reason why the constructor can't support type inference?
Is there a philosophical reason why the constructor can't support type inference?
No. When you have
new Foo(bar)
then we could identify all types called Foo in scope regardless of generic arity, and then do overload resolution on each using a modified method type inference algorithm. We'd then have to create a 'betterness' algorithm that determines which of two applicable constructors in two types that have the same name but different generic arity is the better constructor. In order to maintain backwards compatibility a ctor on a non-generic type must always win.
Is there a practical reason why the constructor can't support type inference?
Yes. Even if the benefit of the feature outweighs its costs -- which are considerable -- that's not sufficient to have a feature implemented. Not only does the feature have to be a net win, it has to be a large net win compared to all the other possible features we could be investing in. It also has to be better than spending that time and effort on bug fixing, performance work, and other possible areas that we could put that effort. And ideally it has to fit in well to whatever the "theme" is of the release.
Furthermore, as you correctly note, you can get the benefits of this feature without actually having the feature itself, by using a factory pattern. The existence of easy workarounds makes it less likely that a feature will ever be implemented.
This feature has been on the list of possible features for a long time now. It's never been anywhere near high enough on the list to actually get implemented.
UPDATE March 2015
The proposed feature made it close enough to the top of the list for C# 6 to be specified and designed, but was then cut.
public class MyType<T>
{
private readonly T field;
public MyType(T value) { field = value; }
}
they can, there is no need to tell the constructor 'what T is' again, seeing as you have already done that in the class decleration.
also your factory is incorrect, you need to have public class MyTypeFactory<T> not just public class MyTypeFactory - unless you declare the factory inside the MyType class
Edit for update:
Well, is 42 a long, a short, an int, or something else?
Let's say you have the following
class Base
{
public virtual void DoStuff() { Console.WriteLine("Base"); }
}
class Foo : Base
{
public override void DoStuff() { Console.WriteLine("Foo"); }
}
Then you did this
var c = new Foo();
var myType = new MyType(c);
Would you expect foo to be used, or base? We need to tell the compiler what to use in place of T
When you really wanted to on type base
Hence the
var myType = new MyType<Base>(c);
The main reason generic type inference can't work on constructors like you wish is because the class "MyType" doesn't even exist when all you've declared is "MyType<T>". Remember it is legal to have both:
public class MyType<T> {
}
and
public class MyType {
}
Both would be legal. How would you disambiguate your syntax if you did in fact declare both, and both of them declared a conflicting constructor.
The constructor needs to have the same generic specification as the class itself. Otherwise it would be impossible to know if the int in your example would relate to the class or to the constructor.
var obj = new MyType<int>(42);
Would that be class MyType<T> with constructor MyType(int) or class MyType with constructor MyType<T>(T)?
Although this has been answered many times before, I feel I need to clarify one thing: C# supports generic type inference on constructors. The problem is, it doesn't support neither adding generic parameters to constructors nor type generic type inference. Wanting to infer generic type argument of the type itself is basically the same as requiring Foo.Bar(0) to infer to Foo<int>.Bar(0).

CA1033 with Properties

When I run code analysis (VS2013) with the 'Microsoft Managed Recommend Rules' rule set, the only warnings I get for my class library are of type CA1033: 'Interface methods should be callable by child types'. But I don't understand the rule in this situation:
/// An object that has a chemical formula
public interface IChemicalFormula
{
/// The chemical formula of the object
ChemicalFormula ChemicalFormula {get;}
}
public class ChemicalFormula: IChemicalFormula
{
ChemicalFormula IChemicalFormula.ChemicalFormula
{
get { return this; }
}
}
The docs recommends making a protected method with the same name so that deriving types can access it, but you cannot name a method the same as the enclosing type. They also recommend making the class sealed, but I don't want it to be sealed in this case. Is this a time just to ignore this rule, or is there an appropriate way to handle it?
EDIT
To add clarification why the class/interface is designed this way, I have another class, Peptide that contains a IChemicalFormula[] array to store modifications. Not every modification necessarily derives directly from ChemicalFormula, but they need to implement the IChemicalFormula interface. Therefore, if I modify an instance of a peptide withsome molecule (H2O for example), then ChemicalFormula class needs to also implement IChemicalFormula.
This is the description of the rule:
Consider a base type that explicitly implements a public interface
method. A type that derives from the base type can access the
inherited interface method only through a reference to the current
instance (this in C#) that is cast to the interface. If the derived
type re-implements (explicitly) the inherited interface method, the
base implementation can no longer be accessed. The call through the
current instance reference will invoke the derived implementation;
this causes recursion and an eventual stack overflow.
I think you should consider evaluating the usage of this property. A good example where TDD could be used to figure out the interface. There are some possible usages (and some invalid ones) below. I am not yet sure what you intend to achieve by looking at those.
In your example, let's say another class, NewChemicalForumla is derived from ChemicalForumula, and references ChemicalFormula, what does that mean?
public class NewChemicalFormula: ChemicalFormula
{
public void Method()
{
Console.WriteLine("{0}", ChemicalFormula.GetType()); // Compile error
Console.WriteLine("{0}", this.ChemicalFormula.GetType()); // Effectively same as above, compile error
Console.WriteLine("{0}", ((IChemicalFormula)this).ChemicalFormula.GetType()); // Works, is that what you intend?
}
}
Now from outside the class, there are two possibilities:
When you have a handle to a derived class:
new NewChemicalFormula().ChemicalFormula.GetType() // Error
or
// This works, is that what you intend to achieve?
((IChemicalFormula)new NewChemicalFormula()).ChemicalFormula.GetType()
When you have a handle to the IChemicalFormula already. In this case, ChemicalFormula seems redundant:
IChemicalFormula formula = new NewChemicalFormula();
Console.WriteLine("{0}", formula.GetType()); // Works, returns NewChemicalFormula
Console.WriteLine("{0}", formula.ChemicalFormula.GetType()); // Works, returns NewChemicalFormula
Console.WriteLine("{0}", formula.ChemicalFormula.Method()); // Compile error
formula.ChemicalFormula.Method() leads to an error because you must cast it to NewChemicalFormula before you can use Method(). Just because the property returns this doesn't help solve this problem.
So the FXCop warning is worth considering, and evaluating the design.

Why are C# 4 optional parameters defined on interface not enforced on implementing class?

I noticed that with the optional parameters in C# 4 if you specify an optional parameter on an interface you don,t have to make that parameter optional on any implementing class:
public interface MyInterface
{
void TestMethod(bool flag = false);
}
public class MyClass : MyInterface
{
public void TestMethod(bool flag)
{
Console.WriteLine(flag);
}
}
and therefore:
var obj = new MyClass();
obj.TestMethod(); // compiler error
var obj2 = new MyClass() as MyInterface;
obj2.TestMethod(); // prints false
Does anyone know why optional parameters are designed to work this way?
On one hand I suppose the ability to override any default values specified on the interfaces is useful though to be honest I'm not sure if you should even be able to specify default values on the interface as that should be an implementation decision.
On the other hand, this disconnect means you can't always use the concrete class and the interface interchangeably. This of course, wouldn't be a problem if the default value is specified on the implementation, but then if you're exposing your concrete class as the interface (using some IOC framework to inject the concrete class for instance) then really there's no point having the default value as the caller will have to always provide it anyway.
UPDATE: This question was the subject of my blog on May 12th 2011. Thanks for the great question!
Suppose you have an interface as you describe, and a hundred classes that implement it. Then you decide to make one of the parameters of one of the interface's methods optional. Are you suggesting that the right thing to do is for the compiler to force the developer to find every implementation of that interface method, and make the parameter optional as well?
Suppose we did that. Now suppose the developer did not have the source code for the implementation:
// in metadata:
public class B
{
public void TestMethod(bool b) {}
}
// in source code
interface MyInterface
{
void TestMethod(bool b = false);
}
class D : B, MyInterface {}
// Legal because D's base class has a public method
// that implements the interface method
How is the author of D supposed to make this work? Are they required in your world to call up the author of B on the phone and ask them to please ship them a new version of B that makes the method have an optional parameter?
That's not going to fly. What if two people call up the author of B, and one of them wants the default to be true and one of them wants it to be false? What if the author of B simply refuses to play along?
Perhaps in that case they would be required to say:
class D : B, MyInterface
{
public new void TestMethod(bool b = false)
{
base.TestMethod(b);
}
}
The proposed feature seems to add a lot of inconvenience for the programmer with no corresponding increase in representative power. What's the compelling benefit of this feature which justifies the increased cost to the user?
UPDATE: In the comments below, supercat suggests a language feature that would genuinely add power to the language and enable some scenarios similar to the one described in this question. FYI, that feature -- default implementations of methods in interfaces -- will be added to C# 8.
An optional parameter is just tagged with an attribute. This attribute tells the compiler to insert the default value for that parameter at the call-site.
The call obj2.TestMethod(); is replaced by obj2.TestMethod(false); when the C# code gets compiled to IL, and not at JIT-time.
So in a way it's always the caller providing the default value with optional parameters. This also has consequences on binary versioning: If you change the default value but don't recompile the calling code it will continue to use the old default value.
On the other hand, this disconnect means you can't always use the concrete class and the interface interchangeably.
You already can't do that if the interface method was implemented explicitly.
Because default parameters are resolved at compile time, not runtime.
So the default values does not belong to the object being called, but to the reference type that it is being called through.
Optional parameters are kind of like a macro substitution from what I understand. They are not really optional from the method's point of view. An artifact of that is the behavior you see where you get different results if you cast to an interface.
Just want to add my take here, as the other answers do provide reasonable explanations, but not ones that fully satisfy me.
Optional parameters are syntactic sugar for compile-time injection of the default value at the call site. This doesn't have anything to do with interfaces/implementations, and it can be seen as purely a side-effect of methods with optional parameters. So, when you call the method,
public void TestMethod(bool value = false) { /*...*/ }
like SomeClass.TestMethod(), it is actually SomeClass.TestMethod(false). If you call this method on an interface, from static type-checking, the method signature has the optional parameter. If you call this method on a deriving class's instance that doesn't have the optional parameter, from static type-checking, the method signature does not have the optional parameter, and must be called with full arguments.
Due to how optional parameters are implemented, this is the natural design result.
Thanks for your explanation #eric-lippert
Here is some code example:
[Fact]
public void TestOptionalMethodArgument()
{
var implementation = new TestHello();
IHello #interface = implementation;
Assert.Equal(23, #interface.Action());
Assert.Equal(40, implementation.Action());
}
public class TestHello : IHello
{
public int Action(int number = 40)
=> number;
}
public interface IHello
{
int Action(int number = 23);
}
var obj = new MyClass();
obj.TestMethod(); // compiler error
var obj2 = new MyClass() as MyInterface;
obj2.TestMethod(); // prints false
Use
MyInterface obj = new MyClass();
obj.TestMethod(); // compiler error
var obj2 = new MyClass() as MyInterface;
obj2.TestMethod(); // prints false
and both result in false

Co-/contravariance support for non-generic types? [duplicate]

This question already has answers here:
Why does C#/CLR not support method override co/contra-variance?
(5 answers)
Closed 8 years ago.
I wonder why the C# team decided not to support co-/contravariance for non-generics, considering they could be just as safe. The question is rather subjective, as I don't expect a team member to respond, but someone may have the insight I (and Barbara Liskov) lack.
Lets look at this sample interface:
public interface ITest
{
object Property
{
get;
}
}
The following implementation will fail, although completely safe (we could always return a more specific type without violating the interface - not in C#, but at least in theory).
public class Test : ITest
{
public string Property
{
get;
}
}
The code would naturally not be safe, if the interface included a setter, but this is no reason for limiting implementation overall, as this could be pointed out by using out/in to declare safety, just as for generics.
The CLR doesn't support covariant return types, whereas it's supported delegate/interface generic variance from .NET 2.0 onwards.
In other words, it's not really up to the C# team, but the CLR team.
As to why the CLR doesn't support normal variance - I'm not sure, other than adding complexity, presumably without the requisite amount of perceived benefit.
EDIT: To counter the point about return type covariance, from section 8.10.4 of the CLI spec, talking about vtable "slots":
For each new member that is marked
"expect existing slot", look to see if
an exact match on kind (i.e., field or
method), name, and signature exists
and use that slot if it is found,
otherwise allocate a new slot.
From partition II, section 9.9:
Specifically, in order to determine
whether a member hides (for static or
instance members) or overrides (for
virtual methods) a member from a base
class or interface, simply substitute
each generic parameter with its
generic argument, and compare the
resulting member signatures.
There is no indication that the comparison is done in a way which allows for variance.
If you believe the CLR does allow for variance, I think that given the evidence above it's up to you to prove it with some appropriate IL.
EDIT: I've just tried it in IL, and it doesn't work. Compile this code:
using System;
public class Base
{
public virtual object Foo()
{
Console.WriteLine("Base.Foo");
return null;
}
}
public class Derived : Base
{
public override object Foo()
{
Console.WriteLine("Derived.Foo");
return null;
}
}
class Test
{
static void Main()
{
Base b = new Derived();
b.Foo();
}
}
Run it, with output:
Derived.Foo
Disassemble it:
ildasm Test.exe /out:Test.il
Edit Derived.Foo to have a return type of "string" instead of "object":
.method public hidebysig virtual instance string Foo() cil managed
Rebuild:
ilasm /OUTPUT:Test.exe Test.il
Rerun it, with output:
Base.Foo
In other words, Derived.Foo no longer overrides Base.Foo as far as the CLR is concerned.
Returned value of method is always "out", they are always on right side of an assignment expression.
CLR Assembly format has metadata which assigns instance methods to interface methods, but this method inference is only dependent on input parameters, they might need to create new format to support, not only that it also becomes ambigious.
New methods mapping algorithm between instance method and interface signature could be complex and CPU intensive as well. And I belive method signatures of interface methods are resolved at compile time. Because at runtime it may be too expensive.
Method inference/resolution could be problem as explained below.
Consider following sample with allowed dynamic method resolution with different return types only (Which is absolutely wrong)
public class Test{
public int DoMethod(){ return 2; }
public string DoMethod() { return "Name"; }
}
Test t;
int n = t.DoMethod(); // 1st method
string txt = t.DoMethod(); // 2nd method
object x = t.DoMethod(); // DOOMED ... which one??
The CLR does not support variance on method overrides, but there is a workaround for interface implementations:
public class Test : ITest
{
public string Property
{
get;
}
object ITest.Property
{
get
{
return Property;
}
}
}
This will achieve the same effect as the covariant override, but can only be used for interfaces and for direct implementations

Categories

Resources