The objects themselves are passed by reference anyway, so I would think that
using "ref" would actually slow things down a tiny bit (adds one more level
of indirection.
I only use "ref" when I need to reseat the variable to point to a different
object.
- Steve
"Arjen" <boah123@hotmai l.comwrote in message
news:1B8D9143-DA8C-4B5A-807B-DA05E6F908E0@mi crosoft.com...
Hi,
>
Form a performance perspective, is it wise to use the ref statement as
much
as possible?
>
Thanks!
Arjen
On Jul 2, 2:12 pm, Jon Skeet [C# MVP] <sk...@pobox.co mwrote:
--
I agree with Jon Skeet here. A ref should be used when you have a
reference-type object passed to your function, which usually means
something that is instantiated with "new" in the function. But, if
you don't use "new" in your method/function for the object passed to
it, then use the default pass by value. Interestingly enough, both
pass by value and pass by reference *will* both alter the object
passed *outside* the function/method--the opposite is usually implied
in most textbook examples. In most examples it is stated that only
pass by reference will alter the object-- with usually the famous
'swap variables' example using 'temp' given--but what most people
don't realize is that this swap variable example is using 'new' inside
the function/method (check it out next time you see it, and you'll see
that's the case), which is exactly when you should use 'ref'--
otherwise stick to the default pass-by-value. If 'new' is not being
used for the object passed, use the default pass-by-value, as it's
slightly faster, as implied in this thread. The only exception to the
above is when primitive values (int, double, etc) are passed to a
function/method--but here, this seems to be an exception because these
are value-type parameters stored on the stack rather than heap, so
boxing/unboxing is involved. Technically, you could box these
primitive value-type parameters as reference-type objects, then there
would be no 'exception'. Anyway, it usually doesn't make sense to
refer to 'ref' when passing an int parameter to a method/function
anyway, so this is really not an exception to the rule.
In short, the rule is this: when using 'new' inside your method, to
instantiate a object being passed to the method (in the parameters
list), then use the 'ref' keyword in the parameters, to pass by
reference, otherwise, stick with the default (no keyword) pass-by-
value.
If the above doesn't make sense, don't worry about it--just keep
programming and it will become clear eventually.
I've read the page, but I still don't see how my languaging would be
considered different than "references are passed by value". What part of
what I wrote isn't correct?
I've read the page, but I still don't see how my languaging would be
considered different than "references are passed by value". What part of
what I wrote isn't correct?
When a parameter is passed by reference, that means that changes to
the parameter are reflected in the variable used as the argument. When
a reference is passed by value, that's not the case.
So consider this code:
public void Swap (object a, object b)
{
object tmp = a;
a = b;
b = a;
}
If the parameter were passed by reference by default, that would work.
As it is, it does nothng.
The *object* isn't actually passed at all, which is another reason
that "objects are passed by reference" is incorrect. In particular,
consider the case where the reference is actually null. What's being
passed and in what way at that point?
It's a clearer and more accurate mental model to talk about references
being passed by value. It avoids confusing people who understand what
"by reference" means, and would expect the Swap method above to work
when presented with your description. (I've seen this happen on
various occasions.) It also makes it very confusing when you add the
"ref" parameter for a reference type - if things were already being
passed by reference, what would adding "ref" do?
On Wed, 02 Jul 2008 23:33:57 -0700, Steve Harclerode
<Camel.Software .Co@hot.mail.co mwrote:
I've read the page, but I still don't see how my languaging would be
considered different than "references are passed by value". What part of
what I wrote isn't correct?
You wrote "objects are passed by reference". But _all_ parameters,
including references to objects, are passed _by value_, except when using
"ref" and "out" of course.
The fact that the value you're passing is a reference does not make the
parameter a "by reference" parameter, nor does it mean that the object is
passed by reference.
public void Swap (object a, object b)
{
object tmp = a;
a = b;
b = a;
}
>
If the parameter were passed by reference by default, that would work.
As it is, it does nothng.
Thinking back on my Pascal days, by golly you're right (you probably knew
that already).
It's a clearer and more accurate mental model to talk about references
being passed by value. It avoids confusing people who understand what
It is a better mental model, I'll use it the next time I have to mentor a
new person. God help the others I've already worked with. Actually, they
seem to be doing all right, so hopefully they absorbed the correct
information somewhere.
:-)
I have to disagree with you that objects themselves are passed by value.
Passing by value means that you pass the value; i.e. a byte[] (or Vector, or
Hashtable) being passed as value passes the entire thing - that doesn't
happen. Also, passing by value means that the thing cannot be changed;
hence passing by value not reference. But when you do "method (list)",
method can change list because a reference to the list is being passed, not
the list (aka value). C# simple passes a reference to the object which is
the same as C passing in a pointer to the data. And the method cannot
change the reference in C# just as the method in C cannot change the pointer
(from the caller's point of view) - same thing.
Pass by reference:
C# - passes a reference to the data (not the data) and the data can be
changed by the method
C - passes a pointer to the data (not the data) and the data can be changed
by the method
The example you give on your page "method (StringBuilder x)" then "x = null"
is exactly the same as C having "method (int *x)", then "x = NULL"; i.e.
pass by reference. If you view "x" as a reference to the StringBuilder
object, then you're passing the object by reference (which you said did not
happen). If you view "x" as the actual StringBuilder object, then the VM is
effectively passing &x (C terminology) - again, by reference. It uses
ldloca.s which is defined as "Loads the address of the local variable at a
specific index onto the evaluation stack, short form." - same as C.
Apart from ints, floats, etc, C# passes all objects by reference. "ref"
simply passes the address of the reference thereby allowing the method to
change it (exactly the same as C). "out" is the same as "ref" except that
the method is forced, by the compiler, to assign a value to the parameter.
How is this C code that uses pass by reference:
byte* b = {some array of bytes};
method (b);
....different to this C# code?
byte[] b = new byte[]{some array of bytes};
method (b);
In a meeting, would you ever say "Add the two string references together to
get the filename"? I wouldn't, I'd say "Add the two strings together to get
the filename". So, if we view "s" as a string, then "method (s)" is pass by
reference.
Jon, Peter, before you reply, I know that most of the literature out there
agrees with your point of view, so no need to rehash what they have already
written. Maybe it's just me, but I cannot see how C# passes objects by
value.
On Thu, 03 Jul 2008 00:36:38 -0700, Hilton <nospam@nospam. comwrote:
Jon,
>
I have to disagree with you that objects themselves are passed by value.
Jon never said they were. In fact, he pointedly stated that objects are
themselves never passed at all in C#.
I agree with this viewpoint, and it's consistent with the usage of the
terms in the C# specification, as well as MSDN's documentation of C#.
Passing by value means that you pass the value; i.e. a byte[] (or
Vector, or
Hashtable) being passed as value passes the entire thing - that doesn't
happen.
Straw man. You're arguing a point that was never in contention.
Also, passing by value means that the thing cannot be changed;
That's not what "passing by value" means. It's true that the original
argument cannot be changed, but that's just a side-effect of what "by
value" really is: making a copy of the original argument and passing that
to the method.
hence passing by value not reference. But when you do "method (list)",
method can change list because a reference to the list is being passed,
not
the list (aka value).
The method can _not_ change the original argument that was passed, which
is what distinguishes passing "by value" and "by reference".
C# simple passes a reference to the object which is
the same as C passing in a pointer to the data.
Not really. In C, you have the option of passing the data as a complete
copy. This simply doesn't exist in C#. The reference _is_ the data. But
more importantly, C++ distinguishes between passing a pointer by value,
and passing a pointer by reference. It's true that before C++ came along
and introduced the passing of parameters by reference, people would just
pass a pointer and call that "by reference". But it's not really what was
happening. In C/C++ when you pass a pointer without the "&" as part of
the parameter declaration, you are passing a pointer _by value_.
And the method cannot
change the reference in C# just as the method in C cannot change the
pointer
(from the caller's point of view) - same thing.
That's right. Because in both cases the parameter is passed by value, the
original storage for that value cannot be modified by the method/function
being called.
Pass by reference:
C# - passes a reference to the data (not the data) and the data can be
changed by the method
Wrong. The fact that a reference is being passed does not mean the
parameter is being passed "by reference".
C - passes a pointer to the data (not the data) and the data can be
changed
by the method
Again, wrong. The pointer is being passed by value.
The example you give on your page "method (StringBuilder x)" then "x =
null"
is exactly the same as C having "method (int *x)", then "x = NULL"; i.e.
pass by reference.
Wrong. Both are passing by value. That's why the caller's copy of the
value is not changed when the method assigns "x" to "null".
If you view "x" as a reference to the StringBuilder
object, then you're passing the object by reference
Saying the same thing over and over again isn't going to make it true.
The fact that a reference is being passed does not make it "passing by
reference". The reference is passed by value.
(which you said did not
happen). If you view "x" as the actual StringBuilder object,
Why would we do that? The actual object is accessible only through a
reference. There is no way to put the object itself into a variable.
then the VM is
effectively passing &x (C terminology) - again, by reference. It uses
ldloca.s which is defined as "Loads the address of the local variable at
a
specific index onto the evaluation stack, short form." - same as C.
"It uses"? What uses? You haven't posted any code that you could be
referring to. What example is it that you are saying uses "ldloca.s"?
Are you comparing this to managed code? If not, how can that be "same as
C"?
In any case, the "ldloca.s" instruction is used when you pass by
reference, yes. But that's only when you use the "ref" or "out" keyword.
Try it and see. If you just pass an object reference by value, a plain
"ldloc" instruction is used, not "ldloca".
If this is the basis of your argument, then I'd say you just blew up your
own argument. By your own description, since "ldloca" is _not_ used when
you pass by value, even when the argument is a object reference, obviously
the object reference is being passed by value, not by reference.
Apart from ints, floats, etc, C# passes all objects by reference.
No. C# passes _everything_ by value, unless you state otherwise with
"ref" or "out". The fact that the value is sometimes a reference is
immaterial. It is still passed by value.
"ref"
simply passes the address of the reference thereby allowing the method to
change it (exactly the same as C).
That's right...it passes a _reference_ to the reference. That is, using
"ref" is how you pass "by reference". If you're not using "ref" or "out",
you're not passing by reference.
"out" is the same as "ref" except that
the method is forced, by the compiler, to assign a value to the
parameter.
And the caller is not.
How is this C code that uses pass by reference:
>
byte* b = {some array of bytes};
method (b);
That's not C code that uses pass by reference. It's passing a pointer by
value.
...different to this C# code?
>
byte[] b = new byte[]{some array of bytes};
method (b);
It's exactly the same and both are passing by value.
In a meeting, would you ever say "Add the two string references together
to
get the filename"? I wouldn't, I'd say "Add the two strings together to
get
the filename".
I would never say "add the two strings" or "add the two string
references". I would say "concatenat e the two strings". But how is this
at all related to the question of passing by value or by reference?
So, if we view "s" as a string, then "method (s)" is pass by
reference.
Huh? If we view "s" as a string, then "method(s)" is passing the object
"s" by value. Even using your incorrect terminology, the "method(s)" can
only be "pass by reference" is we view "s" as a reference.
Jon, Peter, before you reply, I know that most of the literature out
there
agrees with your point of view, so no need to rehash what they have
already
written.
I beg to differ. As long as you insist on posting a claim contrary to the
truth, there will be a need to "rehash what they ahve already written".
All that literature out there that agrees with our point of view, it
didn't just happen by accident. There's a _reason_ that the vast majority
of C# documentation (and _all_ of the definitive documentation, such as
the specification itself) agrees with this point of view.
Maybe it's just me, but I cannot see how C# passes objects by
value.
It'd be one thing if you were approaching this naïvely. We could just
explain how things really work, and you could get on with whatever it is
you're doing. But you've obviously put a lot of effort and thought into
your argument. Which means you're simply not paying attention to reality.
Don't get confused by the fact that the same word is used in two different
ways. That's a huge mistake on your part.
And consider this: if you are already always passing objects by reference,
then what does it mean to use "ref" when you are passing an object? Are
you passing "by reference by reference"?
>I have to disagree with you that objects themselves are passed by value.
>Where did I say that they were? I said that *references* are passed by
>value. Objects aren't passed at all.
You replied to Steve:
Steve Harclerode <Lizard.That.Wa s@hot.mail.comw rote:
The objects themselves are passed by reference anyway
No, they're not.
---
I then made the assumption that if the object wasn't passed by reference, it
is passed by value - which is it?
[zap your reply]
Jon, I totally 'see' you view on this (which seems to be consistent with
many/most others - i.e. I acknowledge that I am in the minority here). My
point is that a method works on data and I care about the data, I care about
the stuff that is in arrays, lists etc. Now, even though you assert that "C
doesn't have pass by reference at all.", for decades millions of people were
taught the difference between passing by reference and passing by value
using C, were they wrong? If I have data, and I don't pass that data to a
method, but rather pass a reference/pointer (whatever the syntax), then (in
my mind) it is pass by reference. C# and C really aren't that different in
these terms, just that it is hidden (thankfully) - I don't think that the
syntax of the language should change the terminology of what really is
happening under the covers. The key here is that you're thinking strictly
in terms of the parameters, I'm thinking in terms of the data.
Wow, I'm still trying to wrap my head around your "C doesn't have pass by
reference at all" comment. I understand your logic of it, but it sure as
heck doesn't make any sense to me. Having said that, I think Wikipedia sums
up our two opposing views in this line: "Java is a call-by-value language,
but since most Java expressions are references to anonymous objects, it
frequently displays call-by-reference semantics without the need for any
explicit reference syntax."
On Jul 3, 11:09 am, "Hilton" <nos...@nospam. comwrote:
Jon Skeet wrote:
Hilton wrote:
I have to disagree with you that objects themselves are passed by value.
Where did I say that they were? I said that *references* are passed by
value. Objects aren't passed at all.
>
You replied to Steve:
>
Steve Harclerode <Lizard.That... .@hot.mail.comw rote:
The objects themselves are passed by reference anyway
>
No, they're not.
---
>
I then made the assumption that if the object wasn't passed by reference,it
is passed by value - which is it?
Well, you could have read the *very next sentence* in my reply, which
explained what actually happens:
"The references are passed by value."
Your assumption reminds me of the "When did you stop beating your
wife?" question.
[zap your reply]
>
Jon, I totally 'see' you view on this (which seems to be consistent with
many/most others - i.e. I acknowledge that I am in the minority here). My
point is that a method works on data and I care about the data, I care about
the stuff that is in arrays, lists etc. Now, even though you assert that "C
doesn't have pass by reference at all.", for decades millions of people were
taught the difference between passing by reference and passing by value
using C, were they wrong?
Yes. If they'd read K&R, I believe they'd have seen something
explicitly saying that C only supports pass by value. (I don't have a
copy to hand, but I'm pretty sure I've seen it there before.) You can
*simulate* pass by reference in C, but it's not true pass by
reference.
If I have data, and I don't pass that data to a
method, but rather pass a reference/pointer (whatever the syntax), then (in
my mind) it is pass by reference.
> C# and C really aren't that different in
these terms, just that it is hidden (thankfully) - I don't think that the
syntax of the language should change the terminology of what really is
happening under the covers.
Whether the language supports pass by reference or not is defined by
the language specification. C# *does* support pass by reference using
the "ref" keyword. C doesn't support it (directly - you can emulate it
but that's not the same thing).
> The key here is that you're thinking strictly
in terms of the parameters, I'm thinking in terms of the data.
I'm thinking in terms of the meanings of technical terms, which are
how we communicate.
Wow, I'm still trying to wrap my head around your "C doesn't have pass by
reference at all" comment. I understand your logic of it, but it sure as
heck doesn't make any sense to me.
That's because I believe you've been misunderstandin g the meaning of
"pass by reference" as indeed many people do.
Pass by reference has a very specific meaning, and it isn't directly
supported by the C language. You have to work round the lack of
support by explicitly passing (and receiving) a pointer *by value*.
As I say, I believe it's explicitly stated in K&R as well.
> Having said that, I think Wikipedia sums
up our two opposing views in this line: "Java is a call-by-value language,
but since most Java expressions are references to anonymous objects, it
frequently displays call-by-reference semantics without the need for any
explicit reference syntax."
Yes, the effects can be similar in many cases. That doesn't mean it's
the same thing. Calling C#'s default behaviour "pass by reference" can
be very confusing (I've seen several people get confused by it) and
often leads to the mistaken belief that adding the "ref" modifier for
a parameter which uses a reference type makes no difference. After
all, if it's already being passed by reference, what difference could
"ref" make?
Once you understand that the value of a variable (or any expression)
is either a value type value or a reference (including null) you end
up with a much more consistent mental model which works well with
parameters, assignment, GC etc. Trying to think of the world in terms
where the value of a variable is the object itself falls down all over
the place, as well as being further removed from the technical
details. Why do you want to push a more complicated world view which
just doesn't stand up to scrutiny?
Hilton wrote:
What example is it that you are saying uses "ldloca.s"? Are you
comparing this to managed code? If not, how can that be "same as C"?
>
In any case, the "ldloca.s" instruction is used when you pass by
reference, yes. But that's only when you use the "ref" or "out" keyword.
My point is that the C# call "method (ref x)" is defined by
you/Jon/community as being pass by reference, yet the C call "method (&x)"
is defined by you/Jon/community as being pass by value - they're doing
EXACTLY the same thing. Both simply take the address of x and pass it
along. Does a prettier syntax changes the entire concept? And if
Microsoft has used "&" instead of "ref" in its definition of the C#
language, would that now mean that the C# call "method (&x)" was now pass by
value???
Pete, really, I don't want to spend more of your time or my time on this.
In my mind (which I agree probably doesn't fit the pure definition of the
pass-by definitions), if I pass a reference or pointer to my chunk of data,
I'm passing by reference (the focus being on the data, not the actual
parameter). I think millions of other people think that way too since
pass-by-reference has been taught for decades when discussing C, but
apparently that capability never existed.
if I pass a reference or pointer to my chunk of data,
I'm passing by reference
You can keep repeating this, but it doesn't make it true. And re-
iterating it only adds confusion for new C# developers; one of the
reasons so many people get it wrong is because others (like yourself)
seem to be going out of their way to keep the myth alive.
In short: no; you simply happen to be passing a value that *is* a
reference. Bass-by-reference (of a class) would be passing a reference/
pointer to something that *itself* happens to be a reference. In this
case, it is the address of the variable/field "x" that is actually
passed. In the original case, it is the current *value* of the
variable/field "x" that is passed - i.e. the reference to the
instance. The explanation works better with a picture, but...
I very-much doubt my voice will sway you much, but there we go...
Comment