[Mono-devel-list] Incorrect interpretation of operator arguments?

Jonathan Pryor jonpryor at vt.edu
Tue Jun 8 18:34:52 EDT 2004


Below...

On Tue, 2004-06-08 at 12:54, Anders Gustafsson wrote:
> This might be a general C# language question; if that is so, I am sorry 
> in beforehand that I have posted the issue in this forum :-)

It's a C# language question... :-)

> To follow-up on my bug report (#59694, see 
> http://bugzilla.ximian.com/show_bug.cgi?id=59694), I made a simple test 
> program, TestClass.cs:
> 
> *****
> using System;
> 
> class TestClass

  ^---  this is your problem, as I explain below. :-)

<snip/>

> Upon compiling (mcs TestClass.cs or gmcs TestClass.cs) and running (mono 
> TestClass.exe) it, I get the following output (Mono 1.0 Beta 2, Fedora 
> Core 2, Linux kernel 2.6.5-1.358):
> 
> ****
> t1 is 30, should be 10
> t2 is 20, should be 20
> t3 is 30, should be 30
> ****
> 
> i.e. t1 is modified in the addition operation t3 = t1 + t2 !

This is the correct behavior.

> As far as I understand, arguments are passed by value if not explicitly 
> specified otherwise (ref, out; see e.g. ECMA-334 C# Language 
> Specification, secs. 8.3 and 17.5.1). 

Actually, this is always true, period.  The question is, *what* are you
"always" passing by value?

For value types (ints, enumerations, structures, etc.), you pass the
entire value type by value.  For *everything* *else*, you're passing a
pointer to the actual object.  (Whether this is the "object reference"
or the implicit pointer used for "ref" and "out" doesn't matter; it's
still, ultimately, a pointer.)

The problem is that TestClass is a reference type, not a value type. 
Consequently, you're passing a *reference* (pointer) to the object to
your, so in your operator+ method:

    public static TestClass operator+(TestClass iLhs, TestClass iRhs)
    {
        TestClass ret = iLhs;
        ret.mX = ret.mX + iRhs.mX;
        return ret;
    }

you're actually modifying the existing "iLhs" object, as, again, the
"pass-by-value" is for the object reference, not the object itself.

For the behavior you want, use a struct instead of a class.

To prove this is correct, add the following to the end of Main():

	Console.WriteLine ("&t1 == &t3? {0}, should be False",
		((object)t1 == (object)t3));

If it prints True (as it does with classes), t1 and t3 refer to the same
object, which is why they both have the same value.  When structures are
used, t1 and t3 are boxed, which is why the equality operator returns
false.

<snip/>

> Now, this problem is not confined to Mono. I have compiled the same 
> source code with Microsoft.NET compiler csc (through Borland C# 
> Builder), and I get the same result as with Mono!

This should have indicated immediately that things didn't work like you
thought they did. :-)

 - Jon





More information about the Mono-devel-list mailing list