views:

172

answers:

2

Is this a CLR restriction or a language design decision? I tried to do it in C++/CLI, of course where it works because the need to support native c++:

public ref class Test
    {
     public:
     static Test^ operator &( Test^ msg, int& i )
     {
      i = i + 1;

      return nullptr;
     } 
    };

and then looked at the compiler omitted output:

public: static Test __gc* op_BitwiseAnd(Test __gc* msg, Int32 __gc** modopt(IsImplicitlyDereferenced __gc*) i)
{
    i[0] += 1;
    return 0;
}

I went further and tried to call this operator from C# project - and of course I needed to go [unsafe] to do it( I needed pointer ):

Test t = new Test();
int i = 0;

unsafe
{
    t = t & &i;
}

Obviously not so hard to implement for the CLR? I really miss pass by reference in operators overloading and would like to at least in light myself in why is this missing?

Why can't C# hide the ugliness behind the unsafe and pointers when we need to deal with reference variables in our operator overloads? Even if I chose to go with this ugly workaround it wouldn't work in Silverlight, where unsafe operations is not allowed...

+3  A: 

In C#, your variables are never altered by callees without you explicitly passing them as references (e.g. int.TryParse(s, out i) where you explicitly specify the out keyword). This feature would make things complicated by allowing the overloaded operator alter the contents of the operands without your explicit permission.

For instance,

public static MyStruct operator + (ref MyStruct left, ref MyStruct right) {
    left = new MyStruct(); // !!!!!!!!
    return something(left, right);
}

When you reference such an operator in C#:

MyStruct x = new MyStruct();
MyStruct y = new MyStruct();
MyStruct z = x + y; // in C#, you never expect `x` to be changed.
Mehrdad Afshari
Not at all. Just make operator overloading to take ref parameter?
Ivan Zlatanov
Ivan: then how you'd call the overloaded operator? If a method takes a `ref` parameter, the call site **and** the definition site should **explicitly** declare the parameter as `ref`.
Mehrdad Afshari
Mehrdad: This is perfectly OK. They have different signature, so calling without ref will never match a ref overload. What is so complicated about that, that made C# team not implement it? What if I really need to alter a operand that is not a reference type - how do I do it?
Ivan Zlatanov
You could use z = x + (ref y); I suppose. But to what end? Operators should be combining values, not mutating them.
Joren
Ivan: C# is designed not to clone C++ complexities. "What if I really need to alter a operand that is not a reference type - how do I do it?" First, if you **really** need it, you should create a method, not an operator for that purpose. You are abusing operator overloading. Second, what if the callee isn't conscious of your decision and suddenly sees his variable modified in an expression? This will cause headaches in debugging.
Mehrdad Afshari
"What if I really need to alter a operand that is not a reference type - how do I do it?" Use a method instead. I don't think there is ever a situation where you *really* need an operator, specifically, that works this way.
Joren
My last comment: s/callee/caller
Mehrdad Afshari
@Ivan: I think you are missing the point that is trying to be made. C# has a set of fundamental, core rules, one of which is that operators will never modify the references it operates on. It is a useful and appropriate rule, in my opinion, and the C++ behavior can lead to bugs that are very hard to identify and track down. Given your C++/CLI implementation, I would have been very confused by its behavior if I had ever encountered it without knowing the implementation.
jrista
Joren: You're wrong. There are plenty, and if you look at boost c++ library you will find great techniques that can be done as well in C#. But I don't want to get into details, too much to explain. I just needed to reason myself why this operator overloading is left out.
Ivan Zlatanov
Ivan: Designing a language involves a bunch of trade offs. C# puts "simplicity" high in its list of design goals. It's not a matter of technical possibility. Sure, it's possible. C++ is the existence proof. With the same reasoning you can argue why Java does not have operator overloading at all. Because the designers thought for accomplishing the design goals of Java, the benefits do not outweigh the costs and the increased complexity.
Mehrdad Afshari
@Ivan: C# is not C++, and as a matter of fact, it specifically aims to plug some of the loopholes in C++ that can lead to excessively convoluted behavior and unexpected memory modification. I think this is a supreme example of WHY C# doesn't allow ref-modifying operators and similar things. Don't assume that C# == (C++ + extra). C# only inherits C++ structure and basic syntax, not all of its behavior, and appropriately so.
jrista
+1  A: 

I think it is because an operator (in the more mathematical view that C# seems to take) is logically something that combines its arguments into a new value, never supposed to be mutating anything. C++ seems to consider operators more as a version of general operations with more convenient syntax than functions, than as a way to represent maths in particular. I think that in C# you'll almost never see things like defining operators for stream operations and such.

Joren