Determing whether formal parameters are passed by value or byrefer

D

David Levine

This is really more of a "why was C# designed this way?" type of question.
Hope this is the write forum for this question. Given the following :

class Base1
{
public int i;
}

struct Base2
{
public int i;
}

class Program
{
static void Increment(Base1 b) { b.i++; }
static void Increment(Base2 b) { b.i++; }

static void Main(string[] args)
{
Base1 b1 = new Base1();
Base2 b2 = new Base2();

Increment(b1);
Increment(b2);

System.Console.WriteLine("b1 = " + b1.i + " and b2 = " + b2.i);
System.Console.ReadKey();
}
}

I know this produces:

b1 = 1 and b2 = 0

Why make the distinction between reference and value parameters implicit in
the case of classes versus structs, but explicit in the case of passing an
actual parameter to a formal paremeter declared with the 'ref' keyword? It's
not only explicit but required. That requirement would seem to lose a lot of
its value in light of the implicit distinction this example highlights.

So, what am I missing?
 
M

Marc Gravell

Why make the distinction between reference and value parameters implicit in
the case of classes versus structs,

I'm not sure I would say that it *is* implicit - simply: there is no
distinction made. In both cases, the value of the *variable* is
passed, which for a struct means "a copy of the value" and for a class
means "a copy of the reference". In the case of pass-by-ref, then the
*address* of the variable is passed. This needs to be explicit,
because it involves doing things differently both at the caller
(putting the address onto the stack rather than the value) and at the
callee (performing a dereference).

For what it is worth, a lot of the issues with structs goes away if
you make the recommended decision: don't make mutable (editable)
structs. Eric Lippert had a few thins to say about this recently:
http://blogs.msdn.com/ericlippert/archive/2008/05/14/mutating-readonly-structs.aspx

Marc
 
A

Arne Vajhøj

David said:
This is really more of a "why was C# designed this way?" type of question.
Hope this is the write forum for this question. Given the following :

class Base1
{
public int i;
}

struct Base2
{
public int i;
}

class Program
{
static void Increment(Base1 b) { b.i++; }
static void Increment(Base2 b) { b.i++; }

static void Main(string[] args)
{
Base1 b1 = new Base1();
Base2 b2 = new Base2();

Increment(b1);
Increment(b2);

System.Console.WriteLine("b1 = " + b1.i + " and b2 = " + b2.i);
System.Console.ReadKey();
}
}

I know this produces:

b1 = 1 and b2 = 0

Why make the distinction between reference and value parameters implicit in
the case of classes versus structs, but explicit in the case of passing an
actual parameter to a formal paremeter declared with the 'ref' keyword? It's
not only explicit but required. That requirement would seem to lose a lot of
its value in light of the implicit distinction this example highlights.

I can not see the problem.

In C# classes are reference types and structs are value types.

The C# code above would look like:

#include <iostream>

using namespace std;

class Base1
{
public:
Base1() { i = 0; }
int i;
};

struct Base2
{
public:
Base2() { i = 0; }
int i;
};

void Increment(Base1 *b) { b->i++; }
void Increment(Base2 b) { b.i++; }

int main()
{
Base1 *b1 = new Base1();
Base2 b2;

Increment(b1);
Increment(b2);

cout << "b1 = " << b1->i << " and b2 = " << b2.i << endl;
return 0;
}

in C++ and behave the same way.

Arne
 
J

Jon Skeet [C# MVP]

<=?Utf-8?B?RGF2aWQgTGV2aW5l?= <David
(e-mail address removed)>> wrote:

Why make the distinction between reference and value parameters implicit in
the case of classes versus structs, but explicit in the case of passing an
actual parameter to a formal paremeter declared with the 'ref' keyword?

Because in the struct vs class case it's not the distinction between
reference and value *parameters* - the distinction is between reference
and value types in general. Would you want to have to explicitly state
that you're aware that you're using a value type every time you use
one?

As Marc said, the issues of this example are easily avoided by never
creating mutable structs.
 
P

Pavel Minaev

This is really more of a "why was C# designed this way?" type of question. 
Hope this is the write forum for this question.  Given the following :

        class Base1
        {
                public int i;
        }

        struct Base2
        {
                public int i;
        }

        class Program
        {
                static void Increment(Base1 b) { b.i++; }
                static void Increment(Base2 b) { b.i++; }

                static void Main(string[] args)
                {
                        Base1 b1 = new Base1();
                        Base2 b2 = new Base2();

                        Increment(b1);
                        Increment(b2);

                        System.Console.WriteLine("b1 = " + b1.i + " and b2 = " + b2.i);
                        System.Console.ReadKey();
                }
        }

I know this produces:

     b1 = 1 and b2 = 0

Why make the distinction between reference and value parameters implicit in
the case of classes versus structs, but explicit in the case of passing an
actual parameter to a formal paremeter declared with the 'ref' keyword?  It's
not only explicit but required.  That requirement would seem to lose a lot of
its value in light of the implicit distinction this example highlights.

So, what am I missing?

The confusion is mostly due to two different uses of the term
"reference" in C#, which reflect two distinct concepts in CLR. On one
hand, there are references to objects of reference types (that which C+
+/CLI refers to as "handles", but the proper CLR term is indeed
"reference"). Since you never deal with values of type "object", but
always "reference to object", C# designers have decided to make the
indirection implicit. On the other hand, there is the "ref" keyword
and the "pass-by-reference" semantics, which is actually represented
by something that is called a "managed pointer" in CLR (C# pointer
types are _not_ managed pointers). Now you cannot have a managed
pointer to an object of a reference type, but you can have one to a
reference to an object, or to an object of a value type (such as a
struct or an enum). Since value type objects are not always accessed
via managed pointers, it makes sense to make the indirection explicit.

Personally, I've always thought it a pity that references are explicit
in C# - it's much easier to explain semantics of object references to
someone when they are explicitly spelt out in the code, as in C++/CLI
- it always reminds one that he's not working with (assigning,
comparing etc) objects themselves, but only references. It also makes
the concept of passing a reference to object as a by-ref argument
easier to grasp.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top