Passing by reference twice

T

tshad

If I am passing a variable by reference to another routine by reference, do
I need to dereference first?

string testString;
....

FirstSub(ref firstString)
{
HandleString(ref firstString); //do I need to de
reference here or just pass theString without the "ref"
}
void HandleString(ref theString)
{
Console.WriteLine(thestring);
}
 
M

Michael C

tshad said:
If I am passing a variable by reference to another routine by reference,
do I need to dereference first?

string testString;
...

FirstSub(ref firstString)
{
HandleString(ref firstString); //do I need to de
reference here or just pass theString without the "ref"
}
void HandleString(ref theString)
{
Console.WriteLine(thestring);
}

No, but why pass it a ref?
 
T

tshad

Because I am building the string in another function which can get fairly
large and I don't want to pass the actual string which will get very large.

It does seem to work now and I am not sure what I was doing that was causing
the problem. The example actually work.

I am curious as to why it work, however.

If I have testString and I pass it as a reference to FirstSub, then it has
the reference to testString (not the string itself). When I pass it to
HandleString, aren't I passing a reference to a reference of testString?

If that is the case, how does HandleString handle it correctly?

Thanks,

Tom

FirstSub(ref testString);

void FirstSub(ref firstString)
 
M

Michael C

tshad said:
Because I am building the string in another function which can get fairly
large and I don't want to pass the actual string which will get very
large.

C# doesn't copy the entire string when passing it by value. It's a reference
type so only a pointer to it will be passed anyway. You only need to pass a
reference if you want to modify the string.
If that is the case, how does HandleString handle it correctly?

It probably just passes on the pointer it has.

Michael
 
M

Mike

Michael C said:
C# doesn't copy the entire string when passing it by value. It's a
reference type so only a pointer to it will be passed anyway. You only
need to pass a reference if you want to modify the string.

As strings are immutable in C#, in neither case (ref or not) is it possible
for you to modify a string.
If it's passed by ref, you can modify the reference that the caller has
passed to a new string, but you still can not change the existing string.
If you want to actually "modify a string", pass a StringBuilder or char[]
instead.

m
 
M

Mart

Hi,

In .NET, String is a Reference Type. It is allocated on the heap, and
the variable that you've declared (testString) contains it's address (a
pointer to it). This means that you will always be passing some form of
reference to the instance rather than the instance itself, whether you
pass the testString variable by ref or by value -- so I'm not sure that
you need to put the 'ref' bit in.

If testString was a Value Type, then adding ref would give you the same
behaviour as when you pass a Reference Type by value -- it would allow
you to manipulate the same instance of the Value Type.

In the code in your post, would I think that all of the variables will
be pointing to the same instance of your String. I suspect you could
drop the ref and all would be ok.

Cheers, Mart.
 
M

Michael C

Mike said:
As strings are immutable in C#, in neither case (ref or not) is it
possible for you to modify a string.
If it's passed by ref, you can modify the reference that the caller has
passed to a new string, but you still can not change the existing string.
If you want to actually "modify a string", pass a StringBuilder or char[]
instead.

That's true, although from outside the function the appearance is the string
has been modified. This is the same as any time you use a string as you're
always getting a reference to a new string, so the case of using the
function is nothing special.

Michael
 
B

Bruce Wood

Because I am building the string in another function which can get fairly
large and I don't want to pass the actual string which will get very large.

A string is a reference type, so whenever you pass it, it doesn't get
copied on the stack anyway. You're always passing a reference.

The only question is whether you want to replace the string you passed
with a different string, in which case you need the "ref" keyword. What
"ref" says is that you may want to change the variable that contains a
reference (pointer) to the string to contain a reference (pointer) to a
different string upon return.

So, if HandleString changes the string to which theString points, and
wants the caller to FirstSub to receive the change, then you need
"ref". Something like this:

void FirstSub(ref string theString)
{
...
HandleString(ref theString);
...
}

void HandleString(ref string aString)
{
aString = String.Format(...);
}

Then any caller to FirstSub will get a changed string on return.

If FirstSub and HandleString are just _using_ the string for something,
but not replacing it with a different string, there is no reason to use
"ref".
I am curious as to why it works, however.

If I have testString and I pass it as a reference to FirstSub, then it has
the reference to testString (not the string itself). When I pass it to
HandleString, aren't I passing a reference to a reference of testString?

No, because C# isn't like C. In C#, when you mention the variable name
then the language dereferences automatically. So, in

void FirstSub(ref string theString)
{
...
}

when you say "theString", you are not talking about the reference to
"theString". You are talking about "theString" itself (which is a
reference to a string). So, no, you never get a reference to a
reference to a reference, because there is no language construct for
talking about "the reference to the reference called 'theString'". The
"ref" simply indicates how "theString" gets passed to the method. Once
inside the FirstSub method, "theString" is just a normal string again.
 
J

Jon Skeet [C# MVP]

Mart said:
In .NET, String is a Reference Type. It is allocated on the heap, and
the variable that you've declared (testString) contains it's address (a
pointer to it). This means that you will always be passing some form of
reference to the instance rather than the instance itself, whether you
pass the testString variable by ref or by value -- so I'm not sure that
you need to put the 'ref' bit in.

He does if the point is that a method lower down the call chain will
change the value of the parameter to be a different string. For
instance:

using System;

public class Test
{
static void Main()
{
string x = "hello";

Foo (ref x);
Console.WriteLine (x);
}

static void Foo (ref string y)
{
Bar (ref y);
}

static void Bar (ref string z)
{
z = "there";
}
}

The code actually being shown doesn't use this facility, admittedly,
and it looks like the OP does have misconceptions given his reluctance
to pass the string reference by value because "I don't want to pass the
actual string which will get very large".

Obligatory link for this kind of thread:
http://www.pobox.com/~skeet/csharp/parameters.html
 
F

Fabio

Because I am building the string in another function which can get fairly
large and I don't want to pass the actual string which will get very
large.

IMHO it is not a good design the use of "ref" in a method.
It only add confusion for the use of the method.

For strings also, since they are immutable, there is no reasons to use ref.

Best a simple method following the designing guideline:

public string GetHandledString(string myString)
{
myString = ...
return myString;
}
 
J

Jon Skeet [C# MVP]

Fabio said:
IMHO it is not a good design the use of "ref" in a method.
It only add confusion for the use of the method.

I agree that where possible, pass-by-reference should be avoided - but
sometimes it can make the code simpler.
For strings also, since they are immutable, there is no reasons to use ref.

That's not true. The following two methods have very different effects:

void ChangeMe (ref string x)
{
x = "foo";
}

void DontChangeMe (string x)
{
x = "foo";
}
Best a simple method following the designing guideline:

public string GetHandledString(string myString)
{
myString = ...
return myString;
}

That's fine if you don't need the return value for something else.
Every so often, however, it is useful to use ref/out parameters. Look
at double.TryParse for an example of this. (That uses an out parameter,
but ref parameters can be useful in the same way.)

Jon
 
F

Fabio

"Jon Skeet [C# MVP]" <[email protected]> ha scritto nel messaggio


That's fine if you don't need the return value for something else.
Every so often, however, it is useful to use ref/out parameters. Look
at double.TryParse for an example of this. (That uses an out parameter,
but ref parameters can be useful in the same way.)

You're right, but there are really few occasions that require ref/out.
And I think that also the Fw classes use it so rarely because maybe can make
code run faster, but not more clear.
Elsewhere all the Create<Something>() methods would be Create<Something>(out
Something x).

Don't you think so?
 
J

Jon Skeet [C# MVP]

Fabio said:
You're right, but there are really few occasions that require ref/out.
And I think that also the Fw classes use it so rarely because maybe can make
code run faster, but not more clear.
Elsewhere all the Create<Something>() methods would be Create<Something>(out
Something x).

Don't you think so?

It's not that it can make code run faster - it's just that it's only
really useful if you've already used the return value for something
else.

As I said before, it's rarely useful - which is why it's not usually
considered a major omission from Java, for instance - but every so
often it can be pretty handy.

(It's also fairly useful with interop, IIRC. There are lots of Windows
APIs which do this kind of thing, but with pointers. Using ref/out is
the usualy way of handling this.)

Jon
 
M

Mike

Jon Skeet said:
Fabio wrote:
As I said before, it's rarely useful - which is why it's not usually
considered a major omission from Java, for instance - but every so
often it can be pretty handy.

(It's also fairly useful with interop, IIRC. There are lots of Windows
APIs which do this kind of thing, but with pointers. Using ref/out is
the usualy way of handling this.)

It's also useful for multiple-value returns:

ParseMyString( string str, out string part1, out string part2, out
string part3) ...

Of course, you can also provide a type for the return, and use the new
object initalizers (when 3.0 comes out...) to set up the return, alieviating
the need for c'tors or a temp:

struct ParseRet { string part1, part2, part3; }
ParseRet ParseMyString( string str)
{
...
return new ParseRet { part1 = ..., part2 = ...,part3 = ...}
}

I can't belive object and collection initializers have taken this long - but
I'll be glad to have them!

If/When c# gets tuple unpacking or generalized structure assignment (LHS
only unification) (a la Python, Ruby, etc.), you could do it this way:

part1, part2, part3 = ParseMyString( str); // 3-ary collection unpacked
and assigned

I thought this was in 3.0, but a glance at the currect spec leads me to
beleive it's not there. (Because "tuples" in c# are really anonymous, but
actual classes.)
But it would be cool if a collection/member destructuring assignment was
supplied, as that can be pretty powerful when needed.

There are probably some tricks with new features such as implicit typing,
anonymous types, etc., in combination w/generics that probably provide other
ways of returning multiple values that have different tradeoffs from the
current methods - but probably the most ideomatic in c# is to just define a
struct.

m
 
T

tshad

Jon Skeet said:
He does if the point is that a method lower down the call chain will
change the value of the parameter to be a different string. For
instance:

using System;

public class Test
{
static void Main()
{
string x = "hello";

Foo (ref x);
Console.WriteLine (x);
}

static void Foo (ref string y)
{
Bar (ref y);
}

static void Bar (ref string z)
{
z = "there";
}
}

The code actually being shown doesn't use this facility, admittedly,
and it looks like the OP does have misconceptions given his reluctance
to pass the string reference by value because "I don't want to pass the
actual string which will get very large".

Obligatory link for this kind of thread:
http://www.pobox.com/~skeet/csharp/parameters.html

Good article.

But I was a little confused when he was talking about value types. He uses
as his first example:

public struct IntHolder
{
public int i;
}

I would think a struct would be a reference type. I am assuming that this
is a value type because it only contains one value type (int). If it was
something like:

public struct IntHolder
{
public int i; public int j;
}
would it still be a value type?Thanks,Tom> > -- > Jon Skeet -
<[email protected]>> http://www.pobox.com/~skeet Blog:
http://www.msmvps.com/jon.skeet> If replying to the group, please do not
mail me too
 
B

Bruce Wood

In C#, structs are always value types. Do not confuse C# structs with,
say, C++ structs. They act completely differently.
 
J

Jon Skeet [C# MVP]

tshad said:
Good article.

But I was a little confused when he was talking about value types. He uses
as his first example:

public struct IntHolder
{
public int i;
}

I would think a struct would be a reference type.

No - the whole point of declaring something as a struct instead of a
class is to make it a value type instead of a reference type.

I am assuming that this
is a value type because it only contains one value type (int). If it was
something like:

public struct IntHolder
{
public int i; public int j;
}
would it still be a value type?

Yes. It's a value type as long as it's declared as a struct instead of
a class.
 
I

Ian Semmel

Jon said:
It's not that it can make code run faster - it's just that it's only
really useful if you've already used the return value for something
else.
As a general rule in programming, I don't think that functions should be able to
create side-effects. Some languages will make sure it doesn't happen, some don't.

eg

classa fn1 ( ref classa a )
{
return operation_on_a;
}

classa thing = fn1 ( ref a ) + a

is dependent on how the compiler handles expressions. Now it could be that we
know C# does it one way, but C++ or D# might do it another way.

iow, if the value of parameters can be changed, they should only occur in void
functions.
 
J

Jon Skeet [C# MVP]

Ian Semmel said:
As a general rule in programming, I don't think that functions should be able to
create side-effects. Some languages will make sure it doesn't happen, some don't.

Even if the variable values don't change, there's often nothing to stop
people manipulating referenced objects - adding to lists, etc.

Side-effects *can* be very useful - they just shouldn't be overused
(just like plenty of other things).
eg

classa fn1 ( ref classa a )
{
return operation_on_a;
}

classa thing = fn1 ( ref a ) + a

is dependent on how the compiler handles expressions. Now it could be that we
know C# does it one way, but C++ or D# might do it another way.

Some languages don't define it; C# does, fortunately.
iow, if the value of parameters can be changed, they should only occur in void
functions.

I'd say the example above is certainly bad style just in terms of
readability, but I don't think it's anything that should be restricted
in the language.
 
M

Mike

Ian Semmel said:
As a general rule in programming, I don't think that functions should be
able to create side-effects. Some languages will make sure it doesn't
happen, some don't.

eg

classa fn1 ( ref classa a )
{
return operation_on_a;
}

classa thing = fn1 ( ref a ) + a

is dependent on how the compiler handles expressions. Now it could be that
we know C# does it one way, but C++ or D# might do it another way.

iow, if the value of parameters can be changed, they should only occur in
void functions.

I think a success/failure or status return is quite handy:

if ( DoSomething( a, b, ref out c, ref out d))
// we're golden

This was especially true before nullable values, where it may be hard to
determine from the out params whether the function even suceeded if results
are allowed to be null.
As most functional languages have an implcit notion of success/failure
(where failure sometimes results in backtracking if the language supports
it) even if programming c# in a functional style, I don't think returning
true/false is so bad.

m
 

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