Interesting notice regarding pointers

  • Thread starter Lasse Vågsæther Karlsen
  • Start date
L

Lasse Vågsæther Karlsen

K said:
Just for fun of it i tried to send in the value of null into a
constructor. It looks
like this.

public Donkey (Object ob, char ch) {}

The first call below works well but the second produces errors.

Donkey d1 = new Donkey (null, 'd');
Donkey d2 = new Donkey (null, null);

It's a good idea to also post which errors you're getting if you want
anyone to actually consider why you get it.

I'm assuming you get something along the lines of "Argument '2': cannot
convert from <'null>' to 'char'".

The reason is of course that Char is not a reference type, but a value
type, and hence null isn't a valid value for it.
I understand it's got to do with the fact
that char is a native _BUT_ there's a class in IntelliSence called Byte
and i

No, it has nothing to do with char being "native". char is the C#
keyword for the Char BCL type.
was convienced that "byte" was just a
syntactic sugar for "Byte", the same way "string" is for "String".

Well, yes, byte is for Byte what string is for String, same as what char
is for Char, etc.
1.
Can i/should i use "Byte" instead of "byte" (etc. for other types)?

Depends, it doesn't matter to the compiler or .NET. Personally I use the
..NET BCL types (Int32, Byte, String, Object, Double) instead of the C#
keywords (int, byte, string, object, double), but it's a matter of taste.
2. Aren't "byte", "int", "double" etc. really objects in this
OO-language, C#?

They're objects in the sense that they have methods, properties, etc. I
feel the hint of a different meaning of your question though, and I
think you're asking if those things are objects in the sense of
heap-allocated objects. In .NET and C#, they're not, they're value
types, which are allocated inline where you declare them (on the stack
in a method, in a class/struct when fields). You can box them to produce
an Object, like this:

Object o = 10;

which will produce a heap-allocated boxed Int32 object.
3. In Java, passing a native was passing by reference, while passing an
object was passing by value. Is it true
for C# as well?

I don't really know what a native is.

In .NET you can pass everything by reference or by value, however the
default convention is by value, and you need to explicitly state that
you want by reference by using either the ref or the out keyword.

Hence, the following three methods:

public void Test(String s)
public void Test(ref String s)
public void Test(out String s)

the first one passes by value, the two others by reference, and the
distinction between ref and out is basically wether it's the caller or
callee that is responsible for setting the value first.

Note that a common source of confusion in discussions about passing by
reference or value is what you can do with the objects being passed.

Take the following small class:

public class Class1 {
public Int32 Field1;
}

and the following two methods:

public void Test(Class1 c)
public void Test(ref Class1 c)

In both cases, the methods will be able to change the value of the
Field1 field of the object being passed in, passing by value or
reference have nothing to do with that.

But, the second method, passing by reference, can construct a new object
and replace the one being passed in with the newly constructed one. This
is the distiction.

In C++ you have const arguments as well, which prevents the callee from
modifying the contents of the object being passed as well, and this
concept does not exist in C#.
4. (off-topic)
Did anybody got the characters "R2", when regarding the second donkey? :)

Huh? (I understand the reference, just not where R2 would come into play
in this post)
 
K

K Viltersten

Just for fun of it i tried to send in the
value of null into a constructor. It looks
like this.

public Donkey (Object ob, char ch) {}

The first call below works well but the
second produces errors.

Donkey d1 = new Donkey (null, 'd');
Donkey d2 = new Donkey (null, null);

I understand it's got to do with the fact
that char is a native _BUT_ there's a
class in IntelliSence called Byte and i
was convienced that "byte" was just a
syntactic sugar for "Byte", the same way
"string" is for "String".

1.
Can i/should i use "Byte" instead of
"byte" (etc. for other types)?

2.
Aren't "byte", "int", "double" etc.
really objects in this OO-language, C#?

3. In Java, passing a native was
passing by reference, while passing an
object was passing by value. Is it true
for C# as well?

4. (off-topic)
Did anybody got the characters "R2",
when regarding the second donkey? :)
 
L

Lasse Vågsæther Karlsen

Lasse Vågsæther Karlsen wrote:
Depends, it doesn't matter to the compiler or .NET. Personally I use the
.NET BCL types (Int32, Byte, String, Object, Double) instead of the C#
keywords (int, byte, string, object, double), but it's a matter of taste.

Actually, there is one place where you need to use one and not the
others, and it's when you need to force the size of an enum type to 1, 2
or 4 bytes, by "inheriting" from a byte, short, or int (and some other
types). In this place you cannot use the BCL types, so this is legal:

public enum Enum1 : byte
public enum Enum1 : short
public enum Enum1 : int

but this is not:

public enum Enum1 : Byte
public enum Enum1 : Int16
public enum Enum1 : Int32

<snip>
 
G

Gilles Kohl [MVP]

Konrad,

Just for fun of it i tried to send in the
value of null into a constructor. It looks
like this.
public Donkey (Object ob, char ch) {}

The first call below works well but the
second produces errors.

Donkey d1 = new Donkey (null, 'd');
Donkey d2 = new Donkey (null, null);

I don't think the error that you get has anything to do with calling a
constructor - you'd get the same error trying to call the method

public void Donkey(Object ob, char ch) {}

with

Donkey(null, null);

char is a value type - you cannot assign null to it - only reference types can
"refer to nothing".
I understand it's got to do with the fact
that char is a native _BUT_ there's a
class in IntelliSence called Byte and i
was convienced that "byte" was just a
syntactic sugar for "Byte", the same way
"string" is for "String".

Slooowly here. Byte and byte are indeed aliases - use them synonymously if you
wish. Byte is also a value type - you'd get the same error if "ch" were
defined as byte. That being said, a char is NOT a byte (if you were under that
impression). Check out e.g.

Console.WriteLine(sizeof(char));
Console.WriteLine(sizeof(byte));
1.
Can i/should i use "Byte" instead of
"byte" (etc. for other types)?

Yes, you can. "byte" is a C# alias for the framework type "Byte". Same for
e.g. "string" and "String", "int" and "Int32" or "long" and "Int64". The
guidelines that I use say to prefer the language-specific alias.
2.
Aren't "byte", "int", "double" etc.
really objects in this OO-language, C#?

For all practical purposes, yes. If need be - e.g. had you called your Donkey
this way:

Donkey Op = new Donkey (3, 'c');

the compiler would have converted the value type 3 into an object through a
process called "boxing". (Converting a value type to a reference type).
When you cast back, e.g. through

int theValue = (int)ob;

it converts back - this is called "unboxing".

What you tried when passing null for char ch was use something reserved for
reference types with a value type though, that won't work.
3. In Java, passing a native was
passing by reference, while passing an
object was passing by value.

I'm not familiar with Java, but are you sure you haven't got this one
backwards?
Is it true
for C# as well?

AFAIK C# passes value types by value (by default) - when you change the object
in the method called, the callers object remains unchanged. Reference types
are passed by reference - changing the object via the reference changes the
callers object.
4. (off-topic)
Did anybody got the characters "R2",
when regarding the second donkey? :)

Ehrm - closely examine "Op" sample above - read it backwards :)

Regards,
Gilles.
 
K

K Viltersten

Just for fun of it i tried to send in the
I'm assuming you get something along the
lines of "Argument '2': cannot convert
from <'null>' to 'char'".

The reason is of course that Char is not a
reference type, but a value type, and hence
null isn't a valid value for it.

OK, got it. I'm guessing that "blue colored"
types are value types (i.e. "int", "double",
"bool" and some other common ones).

Just to be sure - is "string" a value type?
They're objects in the sense that they
have methods, properties, etc...
...you're asking if those things are
objects in the sense of heap-allocated
objects. In .NET and C#, they're not,
they're value types, which are allocated
inline where you declare them...


I don't really know what a native is.

I think it's value type. Not sure, though.
In .NET you can pass everything by
reference or by value, however the default
convention is by value, and you need to
explicitly state that you want by
reference by using either the ref or the
out keyword.

Are you sure? I created an object and sent it
in a constructor where it was assigned to a
public member. When i checked

Console.Write (sentIn == obj.Member);

i got it to be true. (The type of sentIn and
Member is "Din2D", a class i created.)

Did i miss something?
Huh? (I understand the reference, just not
where R2 would come into play in this post)

I'm unsure if was clear enough. If you
regard the name of the second donkey at the
top of my post and combine it with "R2",
you'll see a name of a figure in a popular
movie about a political conflict in a galaxy
far, far away. (I'm assuming you to be an
average entertainment consumer, of course).

Aside of that - big thanks for a very
informative response. It was a huge amount
of text to be written in such a short time.
You're a good typer, i guess... :)
 
L

Lasse Vågsæther Karlsen

K said:
OK, got it. I'm guessing that "blue colored"
types are value types (i.e. "int", "double", "bool" and some other
common ones).

No, "blue colored types" in the Visual Studio editor is C# keywords.
Those cyan-colored ones are types.

This also makes it easier (for that other thread on the forum about case
sensitivity) to spot mistakes like If and While.
Just to be sure - is "string" a value type?

No, it's a reference type.

You can spot reference types by writing their class name or keyword and
hovering the mouse over them, it would say things like:

for string: class System.String
for int: struct System.Int32

anything that is a struct is a value type, anything that is a class is a
reference type.
I think it's value type. Not sure, though.

Ok. C# or .NET doesn't make such distinctions between the two.
Are you sure? I created an object and sent it
in a constructor where it was assigned to a
public member. When i checked
Console.Write (sentIn == obj.Member);

i got it to be true. (The type of sentIn and
Member is "Din2D", a class i created.)

Did i miss something?

Well, yes.

Passing an object by value does not create a copy of the object, it just
creates a copy of the reference to the object.

Let me describe the difference using other terms.

Suppose I want you to go to a house somewhere. I write down the address
on a piece of paper (copy) and give it to you (pass it). You then go to
the house and do what you need to do there.

Now, let's suppose I did the same thing with another person as well once
you indicate you're done with the house (return from the method). I
write down the address on another piece of paper and give it to him,
then he would end up in the same house as you did. Any changes you did
to the house, he will see when he gets there. Additionally, if you made
a copy of the note before indicating you were done with it, you could
revisit the house at any time, observing any changes that other person
had done in the meantime. This is because which house we're talking
about here hasn't changed at all, it's still just one house.

Now, the difference between this (passing by value) and passing by
reference is that once you're done with the house, if you were passed
the address by reference, you would be free to take an eraser and erase
out the address I wrote on the paper, and write a new one instead,
before handing back the paper to me (return from the method).

So for instance, if I have a piece of paper with the address on, and I
give this to you, passing it by reference, and you change the address
before giving the paper back to me, when I give the paper to that other
person, he will not go to the original house I had in mind, he will go
to the house you wrote down the address to on the paper.

This is the distinction between passing by reference and passing by value.

Note again, that this is different from preventing you from messing up
the house by making sure you either is not allowed to change it, or that
I would give you a whole new house to play with.

In .NET, if you want to make sure the code being called cannot mess up
your object, you have a few options available:

1. pass it an immutable object (String is such an object)
2. pass it a copy of the original object (in which case the called code
can mess it up all it wants, it won't matter to you)
3. other languages have syntax for this, notably the "const" keyword in
C++, which C# or .NET doesn't have

Option 1 would force the called code to basically do what you would do
in option 2, in order for it to work with a modified object, it would
basically have to construct a whole new object based on the original one
with a few changes.

<snip>
 
L

Lasse Vågsæther Karlsen

Lasse Vågsæther Karlsen wrote:
Now, the difference between this (passing by value) and passing by
reference is that once you're done with the house, if you were passed
the address by reference, you would be free to take an eraser and erase
out the address I wrote on the paper, and write a new one instead,
before handing back the paper to me (return from the method).
<snip>

Note that in this case the code which I'm actually talking about here is
required to either null the reference (just had back an empty note), or
construct a new object (build a new house, or pick an existing one). C#
doesn't really allow you to just write down addresses all willy nilly.
 
J

Jon Skeet [C# MVP]

I'm not familiar with Java, but are you sure you haven't got this one
backwards?

I think the poster meant it the other way round, but was wrong anyway.
AFAIK C# passes value types by value (by default) - when you change the object
in the method called, the callers object remains unchanged. Reference types
are passed by reference - changing the object via the reference changes the
callers object.

That's not what passed by reference means.

See http://pobox.com/~skeet/csharp/parameters.html
 
G

Gilles Kohl [MVP]

That's not what passed by reference means.

See http://pobox.com/~skeet/csharp/parameters.html

"<b>This difference is absolutely crucial to understanding parameter passing
in C#, and is why I believe it is highly confusing to say that objects are
passed by reference by default instead of the correct statement that object
references are passed by value by default.</b>"

While I am quite aware of what you are referring to (sic!), I'm not sure about
the "highly confusing" part. Or rather, what is initially more confusing.

I've seen my share of e.g. StringBuilders being passed with the ref keyword,
"because I need to append to it in my method".

Is it easier to say "don't worry, your object will be passed by reference"
here, or would you say "don't worry, what you think of as 'your object' is in
fact only a reference, and it will be passed by value (the reference), which
is enough, because your method gets passed a copy of the reference (by value)
and hence can easily modify the object (via the reference) it is referring to"

Maybe, didactically, something comparable to the buddhist "two truth doctrine"
is what we need here. The "commonsense truth" would be that objects are passed
by reference. The absolute spiritual truth :) being that there is no such
thing as an "object" per se, always only a reference to it, which is indeed
passed by value by default.

Regards,
Gilles.
 
J

Jon Skeet [C# MVP]

"<b>This difference is absolutely crucial to understanding parameter passing
in C#, and is why I believe it is highly confusing to say that objects are
passed by reference by default instead of the correct statement that object
references are passed by value by default.</b>"

While I am quite aware of what you are referring to (sic!), I'm not sure about
the "highly confusing" part. Or rather, what is initially more confusing.

I've seen my share of e.g. StringBuilders being passed with the ref keyword,
"because I need to append to it in my method".

Is it easier to say "don't worry, your object will be passed by reference"
here, or would you say "don't worry, what you think of as 'your object' is in
fact only a reference, and it will be passed by value (the reference), which
is enough, because your method gets passed a copy of the reference (by value)
and hence can easily modify the object (via the reference) it is referring to"

It's certainly *easier* to give the inaccurate answer. I believe it's
more *useful* for people to understand the difference between a
reference and an actual object.

It doesn't just affect parameter passing. How would just explain the
following:

StringBuilder sb = new StringBuilder();
StringBuilder sb2 = sb;
sb2.Append("Foo");
Console.WriteLine(sb);

What is the assignment doing? It's copying the value of one variable to
another. As soon as you understand that the values of the variables are
*references*, you can look at assignment as being entirely consistent
between value types and reference types. If your view of the world is
confused and you think that the values of the variables are the objects
themselves, you've got to make complicated ways of thinking of things.

Another point to consider: if you explain it as "objects are passed by
reference by default" how do you *then* explain what happens in the
case where a StringBuilder parameter genuinely *should* be passed by
reference? With my (accurate) explanation, it's simple and consistent
with the value type behaviour. With the fudged explanation, you have to
make up yet more workarounds.

I would personally rather make people think a bit up front, but get the
right idea and then have relatively plain sailing from then onwards,
than give them a simple but inaccurate idea which will cause confusion
on a number of fronts in the future.
Maybe, didactically, something comparable to the buddhist "two truth doctrine"
is what we need here. The "commonsense truth" would be that objects are passed
by reference. The absolute spiritual truth :) being that there is no such
thing as an "object" per se, always only a reference to it, which is indeed
passed by value by default.

Understanding the "real" truth here is trivial once you understand the
background - and that background informs any number of other things.
 
K

K Viltersten

public Donkey (Object ob, char ch) {}
The first call below works well but the
second produces errors.

Donkey d1 = new Donkey (null, 'd');
Donkey d2 = new Donkey (null, null);

I don't think the error that you get has
anything to do with calling a constructor
- you'd get the same error trying to call
[a] method

Yes, it sounded misguiding in my question.
char is a value type - you cannot assign
null to it - only reference types can
"refer to nothing".

Right. Thanks.
a char is NOT a byte (if you were under
that impression). Check out e.g.

Console.WriteLine(sizeof(char));
Console.WriteLine(sizeof(byte));

I wasn't under that impression but it
still was surprising. It's unicode, right?
I thought all the time that it was:

sizeof (byte) = sizeof (sbyte) = sizeof (char)

I'm not familiar with Java, but are you
sure you haven't got this one backwards?

Yes. Yes, i did, indeed. :)
Donkey Op = new Donkey (3, 'c');
int theValue = (int)ob;

Ehrm - closely examine "Op" sample above
- read it backwards :)

Good one. Inspired by it, i tried to see
something on "ob" but i didn't find "one"
nor "kenobi"...
 
K

K Viltersten

Now, the difference between this (passing by
<snip>

Note that in this case the code which I'm
actually talking about here is required to
either null the reference (just had back an
empty note), or construct a new object (build a
new house, or pick an existing one). C# doesn't
really allow you to just write down addresses
all willy nilly.

Got it. Thanks.
 
K

K Viltersten

3. In Java, passing a native was
That's not true in Java either. Java
doesn't have pass-by-reference at all.
C# has it when you use "ref".

First of all, i put it in the wrong order.
It ment say "native by value" and "object
by reference", as mr Kohl pointed out.

Secondly, it might be my nomenclature that
is to blame. What i ment (note the past
tense) was that modifying an int sent in a
method, lives the callers value unchanged,
while modiying members of an object sent
in, affects the callers objects members.
I stand corrected. Thanks.

Lastly, perhaps my idea about references
was a bit primitive. I've never realized
(until pointed out by mr Gerrard) that
there are four cases. I've always seen it
as only two.

Primitive view:
1. value type passed by value
2. reference type passed by reference

Far closer to truth view:
1. value type passed
a. by value
b. by reference
2. reference type passed
a. by value
b. by reference

I'm a little bit embarassed to admit it
but that distinction actually has slipped
my attention. Thanks to all for clearing
that up. A discussion on that topic is
coming soon at a newsgroup near you. :)
 
A

Arne Vajhøj

K said:
Lastly, perhaps my idea about references was a bit primitive. I've never
realized (until pointed out by mr Gerrard) that there are four cases.
I've always seen it as only two.

Primitive view:
1. value type passed by value
2. reference type passed by reference

Far closer to truth view:
1. value type passed
a. by value
b. by reference
2. reference type passed a. by value
b. by reference

I'm a little bit embarassed to admit it but that distinction actually
has slipped my attention. Thanks to all for clearing that up. A
discussion on that topic is coming soon at a newsgroup near you. :)

I once made the little code snippet attached below to illustrate.

Arne

==============================================

using System;

namespace E
{
public struct VT
{
public int v;
public VT(int v)
{
this.v = v;
}
}
public class RT
{
public int v;
public RT(int v)
{
this.v = v;
}
}
public class MainClass
{
public static void VTBV(VT v1, VT v2)
{
v1.v++;
v2.v++;
VT tmp = v1;
v1 = v2;
v2 = tmp;
}
public static void VTBR(ref VT v1, ref VT v2)
{
v1.v++;
v2.v++;
VT tmp = v1;
v1 = v2;
v2 = tmp;
}
public static void RTBV(RT v1, RT v2)
{
v1.v++;
v2.v++;
RT tmp = v1;
v1 = v2;
v2 = tmp;
}
public static void RTBR(ref RT v1, ref RT v2)
{
v1.v++;
v2.v++;
RT tmp = v1;
v1 = v2;
v2 = tmp;
}
public static void Main(string[] args)
{
VT a = new VT(1);
VT b = new VT(2);
VTBV(a, b);
Console.WriteLine(a.v + " " + b.v);
VT c = new VT(1);
VT d = new VT(2);
VTBR(ref c, ref d);
Console.WriteLine(c.v + " " + d.v);
RT e = new RT(1);
RT f = new RT(2);
RTBV(e, f);
Console.WriteLine(e.v + " " + f.v);
RT g = new RT(1);
RT h = new RT(2);
RTBR(ref g, ref h);
Console.WriteLine(g.v + " " + h.v);
}
}
}
 

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