The following operator overload is defined inside my Term
class:
public static Term operator *(int c, Term t) {...}
This class also defines an implicit conversion from a Variable
to Term
:
public static implicit operator Term(Variable var) {...}
I would like to understand why the following does not compile:
static void Main(string[] args)
{
Variable var = ...; // the details don't matter
Console.WriteLine(2 * var); // var isn't implicitly converted to Term...
Console.ReadKey();
}
The compiler says:
Operator '*' cannot be applied to operands of type 'int' and 'OOSnake.Variable'
Why isn't my overload of operator *
found?
EDIT: As per the suggestion in the comments, here is a small complete example that re-produces the error:
namespace Temp
{
class A {
}
class B
{
public static implicit operator B(A a) { return new B(); }
public static B operator *(int c, B b) { return new B(); }
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(2 * new A());
}
}
}
Basically, operator overload resolution doesn't include implicit user-defined conversions in order to find the operators that could be applicable.
From section 7.3.4 of the C# 5 specification:
An operation of the form
x op y
, whereop
is an overloadable binary operator,x
is an expression of typeX
, andy
is an expression of typeY
, is processed as follows:
- The set of candidate user-defined operators provided by
X
andY
for the operation operatorop(x, y)
is determined. The set consists of the union of the candidate operators provided by X and the candidate operators provided byY
, each determined using the rules of §7.3.5. IfX
andY
are the same type, or ifX
andY
are derived from a common base type, then shared candidate operators only occur in the combined set once.
And 7.3.5 doesn't include implicit user-defined conversions in its search for a set of operators.
Note that this also wouldn't work if the implicit conversion to Term
was declared in the Variable
class - although that would be more reasonable to specify and implement, as the compiler could look at the set of conversions from the operand type to other types, and use those for overload resolution.
However, this is only a matter of looking for the operators to start with. The compiler is happy to perform implicit conversions when it considers whether or not an overload is applicable. For example, in your case, if you add:
class A
{
public static B operator *(A a, B b) { return new B(); }
}
Then this is valid:
A a = new A();
Console.WriteLine(a * a);
Console.WriteLine(2 * var) doesn't contain any hint that you would want to convert var to type Term. The compiler sees the int and multiplication operator and a variable of type 'Variable'.
Edit: To clarify, in order for your example to work the compiler would have to go through all the types in scope and see if one just happens to have an implicit conversion from type 'A'.
And if there also happens do be a class C like:
class C
{
public static implicit operator C(A a) { return new A(); }
public static B operator *(int i, C c) { return new C(); }
}
there's no telling what would happen.
Which is why the compiler doesn't do that :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With