C# Fundamentals Part 3: ReferenceEquals question

M

Marcel Hug

Hi NG!

In my book I have the following code simple and I tested it:

public class Base : ICloneable
{
public int Age;
public string Name;

public Base(string myname)
{
Name = myname;
}

public Object Clone()
{
return MemberwiseClone();
}

public static void Main(String[] argv)
{
Base myTest = new Base("Joanna");
myTest.Age = 36;
Base clone1 = (Base) myTest.Clone();
Base clone2 = myTest;

bool myBTest = false;
myBTest = Object.ReferenceEquals(myTest.Name, clone1.Name);
//Book says false
//My Test returns true

myBTest = Object.ReferenceEquals(myTest.Age, clone1.Age);
//Book says true
//My Test returns false

myTest.Name = "Julie";
myBTest = Object.ReferenceEquals(myTest.Name, clone1.Name);
//Book says false
//My Test returns false

myBTest = Object.ReferenceEquals(myTest.Name, clone2.Name);
//Book saya true
//my Test returns true
}
}

So I'm a little confused!
With the method MemberwiseClone I do a Shallow copy. That means all
value type would be copied and of the reference types just the pointer
in the variable. Or do i understand this wrong ?

Case 1:
A string is a reference type so it is clear for me, why it results as
true. The pointers points to the same string. Or not ?

Case 2:
Why does this return false ? I guess because a boxing of the to integers
is needed ?

Case 3:
Does this return wrong, because "Julie" could be written as new
String("Julie"); ?

Case 4:
It is clear, because they are two variable which points to the same
instance of the class Base.

Thanks for help!
Regards
Marcel
 
C

cody

if you'd do:

Base clone1 = myTest
Base clone2 = (Base) myTest.Clone();

instead, it would work correctly as it should :)
 
S

Stoitcho Goutsev \(100\)

Marcel,

Look for my answers inline.
In my book I have the following code simple and I tested it:

public class Base : ICloneable
{
public int Age;
public string Name;

public Base(string myname)
{
Name = myname;
}

public Object Clone()
{
return MemberwiseClone();
}

public static void Main(String[] argv)
{
Base myTest = new Base("Joanna");
myTest.Age = 36;
Base clone1 = (Base) myTest.Clone();
Base clone2 = myTest;

bool myBTest = false;
myBTest = Object.ReferenceEquals(myTest.Name, clone1.Name);
//Book says false
//My Test returns true

Book says *true* because it is a shallow copy
myBTest = Object.ReferenceEquals(myTest.Age, clone1.Age);
//Book says true
//My Test returns false

Book says false - boxing happens. You can't get the same object after boxing
even if they have the same value.
myTest.Name = "Julie";
myBTest = Object.ReferenceEquals(myTest.Name, clone1.Name);
//Book says false
//My Test returns false
Correct


myBTest = Object.ReferenceEquals(myTest.Name, clone2.Name);
//Book saya true
//my Test returns true

Correct myTest and clone2 are the same object.
}
}

So I'm a little confused!
With the method MemberwiseClone I do a Shallow copy. That means all value
type would be copied and of the reference types just the pointer in the
variable. Or do i understand this wrong ?

This is correct.
Case 1:
A string is a reference type so it is clear for me, why it results as
true. The pointers points to the same string. Or not ?

Yes, you got it right; they point (reference) the same object.
Case 2:
Why does this return false ? I guess because a boxing of the to integers
is needed ?

Yes, ReferenceEquals accept objects, so all value types will be boxed. It
doesn't matter the value of the value type they always will be boxed as
different objects in the heap.
Case 3:
Does this return wrong, because "Julie" could be written as new
String("Julie"); ?

Yes now Julie and Joanna are different objects.
Case 4:
It is clear, because they are two variable which points to the same
instance of the class Base.

Yes, this is the same object in the heap.

Marcel, you get correct results. I don't know, which book(s) you are
refering to, but is seems it/they are not a good one(s)
 
B

Bruce Wood

if you'd do:
Base clone1 = myTest
Base clone2 = (Base) myTest.Clone();

instead, it would work correctly as it should :)

Not entirely true. The line

myBTest = Object.ReferenceEquals(myTest.Age,
clone1.Age);

can never return true, as Stoitcho pointed out. Even if you call:

myBTest = Object.ReferenceEquals(5, 5);

it will return false, because both values must be boxed in order to
pass them to ReferenceEquals, and so they will appear as two separate
objects on the heap, with two different addresses. So, there's at least
one mistake in the book. :)
 
J

Jon Skeet [C# MVP]

Bruce Wood said:
Not entirely true. The line

myBTest = Object.ReferenceEquals(myTest.Age,
clone1.Age);

can never return true, as Stoitcho pointed out. Even if you call:

myBTest = Object.ReferenceEquals(5, 5);

it will return false, because both values must be boxed in order to
pass them to ReferenceEquals, and so they will appear as two separate
objects on the heap, with two different addresses. So, there's at least
one mistake in the book. :)

One interesting thing is that the equivalent code to your last line in
Java 5 (which has autoboxing) *would* return true, at least in Sun's
implementation. It would return true for any number in the range
[-127, 127] - there's a cache of boxed values. Really took me by
surprise when I first saw it...
 
B

Bruce Wood

I suspected that C# might do something similar, so I tested it before I
posted. Turns out that C# boxes every value individually: the compiler
/ JITter don't notice that 5 could be boxed just once and then the same
reference passed twice.
 
J

Jon Skeet [C# MVP]

Bruce Wood said:
I suspected that C# might do something similar, so I tested it before I
posted. Turns out that C# boxes every value individually: the compiler
/ JITter don't notice that 5 could be boxed just once and then the same
reference passed twice.

Fortunately, it's actually documented in the spec:

<quote>
Boxing a value of a value-type consists of allocating an object
instance and copying the value-type value into that instance.
</quote>

(The Java spec specifically says that it *doesn't* necessarily allocate
a new object.)

Admittedly there's one situation (involving strings) where even a
"new" call doesn't actually end up creating a new object, but I think
it's fair to view that as an anomaly :)
 
J

James Park

Jon Skeet said:
Admittedly there's one situation (involving strings) where even a
"new" call doesn't actually end up creating a new object, but I think
it's fair to view that as an anomaly :)

Whaaa? Explain please!
 
J

Jon Skeet [C# MVP]

James Park said:
Whaaa? Explain please!

Try this:

using System;

class Test
{
static void Main()
{
string x = new string (new char[]{});
string y = new string (new char[]{});

Console.WriteLine (object.ReferenceEquals (x, y));
}
}

It prints "true" - meaning that x and y are references to the same
object, despite them being the results of "new" expressions.

I believe this is something odd in the string constructor in the .NET
framework, and not a C# thing in itself. It may well give different
results on Mono. Still, I like it as an odd sort of corner case :)

(And no, I have no idea how I discovered it...)
 
W

Willy Denoyette [MVP]

| > | > > Admittedly there's one situation (involving strings) where even a
| > > "new" call doesn't actually end up creating a new object, but I think
| > > it's fair to view that as an anomaly :)
| >
| > Whaaa? Explain please!
|
| Try this:
|
| using System;
|
| class Test
| {
| static void Main()
| {
| string x = new string (new char[]{});
| string y = new string (new char[]{});
|
| Console.WriteLine (object.ReferenceEquals (x, y));
| }
| }
|
| It prints "true" - meaning that x and y are references to the same
| object, despite them being the results of "new" expressions.
|

Both x and y are initialzed to an empty string (== String.Empty), which by
itself is an interned string. The result is that x and y are references to
the same string object.


| I believe this is something odd in the string constructor in the .NET
| framework, and not a C# thing in itself. It may well give different
| results on Mono. Still, I like it as an odd sort of corner case :)
|
| (And no, I have no idea how I discovered it...)
|
| --
| 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

Willy.
 
J

Jon Skeet [C# MVP]

Willy Denoyette said:
| It prints "true" - meaning that x and y are references to the same
| object, despite them being the results of "new" expressions.

Both x and y are initialzed to an empty string (== String.Empty), which by
itself is an interned string. The result is that x and y are references to
the same string object.

Yes - but this is the only time it ever happens. You can't create a
reference to any other interned string using "new" - and it actually
violates the spec, which says:

<quote>
The new operator implies creation of an instance of a type
</quote>

In this case, no new instance is being created :(
 
W

Willy Denoyette [MVP]

| > | It prints "true" - meaning that x and y are references to the same
| > | object, despite them being the results of "new" expressions.
| >
| > Both x and y are initialzed to an empty string (== String.Empty), which
by
| > itself is an interned string. The result is that x and y are references
to
| > the same string object.
|
| Yes - but this is the only time it ever happens. You can't create a
| reference to any other interned string using "new" - and it actually
| violates the spec, which says:
|
| <quote>
| The new operator implies creation of an instance of a type
| </quote>
|
| In this case, no new instance is being created :(
|

Yes, but all String(Char[]) or String(Char*) constructors are special cases,
take a look at the remark clause(s) in the Framework reference guide.
....
If value is a null reference (Nothing in Visual Basic) or contains no
element, an Empty instance is initialized.
....

On the current version of the CLR, it means that:

string x = String.Empty;
string y = new string (new char[]{});

x and y are references to the same string 'object', but:
- no new instances of String.Empty are ever created, and it's references are
not tracked (like x and y in above)
- the object is not GC heap allocated, it's initialized by the CLR and
shared by all AD's in the process,


Willy.
 
J

Jon Skeet [C# MVP]

Willy Denoyette said:
| In this case, no new instance is being created :(

Yes, but all String(Char[]) or String(Char*) constructors are special cases,
take a look at the remark clause(s) in the Framework reference guide.
...
If value is a null reference (Nothing in Visual Basic) or contains no
element, an Empty instance is initialized.
...

I don't think that documentation even makes sense. What is an "Empty
instance" when Empty is a property? It should probably be worded as "a
new object is not created; instead, the value of String.Empty is
returned". Even that's not perfect as constructors initialise an
instance rather than returning it, but it makes more sense than what's
there, IMO...
On the current version of the CLR, it means that:

string x = String.Empty;
string y = new string (new char[]{});

x and y are references to the same string 'object', but:
- no new instances of String.Empty are ever created, and it's references are
not tracked (like x and y in above)

Again, "instances of Sring.Empty" doesn't make sense, as String.Empty
is a property, not a type.

Besides, you can certainly get different instances of System.String
which *are* empty in other ways:

using System;
using System.Text;

class Test
{
static void Main()
{
string x = new StringBuilder().ToString();
string y = new StringBuilder().ToString();
Console.WriteLine (object.ReferenceEquals(x, y));
}
}

Either way, this constructor means that the C# spec is violated - the
"new" operator doesn't return a new instance.
 
W

Willy Denoyette [MVP]

| > | In this case, no new instance is being created :(
| >
| > Yes, but all String(Char[]) or String(Char*) constructors are special
cases,
| > take a look at the remark clause(s) in the Framework reference guide.
| > ...
| > If value is a null reference (Nothing in Visual Basic) or contains no
| > element, an Empty instance is initialized.
| > ...
|
| I don't think that documentation even makes sense. What is an "Empty
| instance" when Empty is a property? It should probably be worded as "a
| new object is not created; instead, the value of String.Empty is
| returned". Even that's not perfect as constructors initialise an
| instance rather than returning it, but it makes more sense than what's
| there, IMO...
|

Actually, String.Empty is a public static field of type String initialized
to "" by the String .cctor. That means that the first string in an AD
initializes this field to point (a reference) to the interned (process wide)
empty string object.


| > On the current version of the CLR, it means that:
| >
| > string x = String.Empty;
| > string y = new string (new char[]{});
| >
| > x and y are references to the same string 'object', but:
| > - no new instances of String.Empty are ever created, and it's references
are
| > not tracked (like x and y in above)
|
| Again, "instances of Sring.Empty" doesn't make sense, as String.Empty
| is a property, not a type.
|

Sorry I didn't make myself more clear, My point was to show the remark did
not make much sense, that's why I said there is never an 'instance' of an
'Empty' string created by this constructor.

And ...Again, it's a static field of type String.


| Besides, you can certainly get different instances of System.String
| which *are* empty in other ways:
|

Did I say otherwise?

| using System;
| using System.Text;
|
| class Test
| {
| static void Main()
| {
| string x = new StringBuilder().ToString();
| string y = new StringBuilder().ToString();
| Console.WriteLine (object.ReferenceEquals(x, y));
| }
| }
|
| Either way, this constructor means that the C# spec is violated - the
| "new" operator doesn't return a new instance.
|


Let's say, it violates the specs for this particular case (IMO an
optimization with no added value anyway), IMO it's the C# the spec which is
too strict, string objects are so special it should mention this as an
exceptions.


Willy.
 
J

Jon Skeet [C# MVP]

Willy Denoyette said:
| I don't think that documentation even makes sense. What is an "Empty
| instance" when Empty is a property? It should probably be worded as "a
| new object is not created; instead, the value of String.Empty is
| returned". Even that's not perfect as constructors initialise an
| instance rather than returning it, but it makes more sense than what's
| there, IMO...

Actually, String.Empty is a public static field of type String initialized
to "" by the String .cctor. That means that the first string in an AD
initializes this field to point (a reference) to the interned (process wide)
empty string object.

Apologies, yes. It's still not a type though, so I don't think that it
makes sense to talk about an instance of it :)
| Again, "instances of Sring.Empty" doesn't make sense, as String.Empty
| is a property, not a type.

Sorry I didn't make myself more clear, My point was to show the remark did
not make much sense, that's why I said there is never an 'instance' of an
'Empty' string created by this constructor.
Right.

| Besides, you can certainly get different instances of System.String
| which *are* empty in other ways:
|

Did I say otherwise?

I think I misinterpreted this line:

<quote>
no new instances of String.Empty are ever created,
</quote>

I thought you meant "in general" (given the word "ever") rather than
"with the code above".
| Either way, this constructor means that the C# spec is violated - the
| "new" operator doesn't return a new instance.

Let's say, it violates the specs for this particular case (IMO an
optimization with no added value anyway), IMO it's the C# the spec which is
too strict, string objects are so special it should mention this as an
exceptions.

I'm not sure - as you say, the optimization doesn't provide much value,
and I think it's entirely reasonable that "new" should mean *new*.

My guess is that the CLR is violating its spec as well - from partition
III of the ECMA spec (2nd edition, Dec 2002):

<quote>
The newobj instruction creates a new object or a new instance of a
value type.
</quote>

Now, the C# code generates a newobj instruction, but the CLR is *not*
creating a new object.

I would make more of a fuss about this, but I suspect any code that it
actually breaks is pretty poorly written to start with!
 
W

Willy Denoyette [MVP]

| > | I don't think that documentation even makes sense. What is an "Empty
| > | instance" when Empty is a property? It should probably be worded as "a
| > | new object is not created; instead, the value of String.Empty is
| > | returned". Even that's not perfect as constructors initialise an
| > | instance rather than returning it, but it makes more sense than what's
| > | there, IMO...
| >
| > Actually, String.Empty is a public static field of type String
initialized
| > to "" by the String .cctor. That means that the first string in an AD
| > initializes this field to point (a reference) to the interned (process
wide)
| > empty string object.
|
| Apologies, yes. It's still not a type though, so I don't think that it
| makes sense to talk about an instance of it :)
|

Agreed, the "Remarks" clause is incorrect, well, let's say badly worded.

| > | Again, "instances of Sring.Empty" doesn't make sense, as String.Empty
| > | is a property, not a type.
| >
| > Sorry I didn't make myself more clear, My point was to show the remark
did
| > not make much sense, that's why I said there is never an 'instance' of
an
| > 'Empty' string created by this constructor.
|
| Right.
|
| > | Besides, you can certainly get different instances of System.String
| > | which *are* empty in other ways:
| > |
| >
| > Did I say otherwise?
|
| I think I misinterpreted this line:
|
| <quote>
| no new instances of String.Empty are ever created,
| </quote>
|
| I thought you meant "in general" (given the word "ever") rather than
| "with the code above".
|

No, sorry I meant using the String constructors taking the char[] or char*
as argument.

| > | Either way, this constructor means that the C# spec is violated - the
| > | "new" operator doesn't return a new instance.
| >
| > Let's say, it violates the specs for this particular case (IMO an
| > optimization with no added value anyway), IMO it's the C# the spec which
is
| > too strict, string objects are so special it should mention this as an
| > exceptions.
|
| I'm not sure - as you say, the optimization doesn't provide much value,
| and I think it's entirely reasonable that "new" should mean *new*.
|
| My guess is that the CLR is violating its spec as well - from partition
| III of the ECMA spec (2nd edition, Dec 2002):
|
| <quote>
| The newobj instruction creates a new object or a new instance of a
| value type.
| </quote>
|
| Now, the C# code generates a newobj instruction, but the CLR is *not*
| creating a new object.
|
True.

| I would make more of a fuss about this, but I suspect any code that it
| actually breaks is pretty poorly written to start with!
|
True, but that doesn't mean that the Remarks clause couldn't be changed into
something that clearly describes the exact behavior when the constructor
takes an empty char array or null, and that it's preferable to use
String.Empty to get an 'empty' string reference.

Willy.
 
J

Jon Skeet [C# MVP]

| I would make more of a fuss about this, but I suspect any code that it
| actually breaks is pretty poorly written to start with!

True, but that doesn't mean that the Remarks clause couldn't be changed into
something that clearly describes the exact behavior when the constructor
takes an empty char array or null, and that it's preferable to use
String.Empty to get an 'empty' string reference.

Yup. Do you want to put it in the feedback centre or shall I? ;)
 
C

cody

Not entirely true. The line
myBTest = Object.ReferenceEquals(myTest.Age,
clone1.Age);

can never return true, as Stoitcho pointed out. Even if you call:

myBTest = Object.ReferenceEquals(5, 5);

it will return false, because both values must be boxed in order to
pass them to ReferenceEquals, and so they will appear as two separate
objects on the heap, with two different addresses. So, there's at least
one mistake in the book. :)

Oh sure, I misread the lines

Base clone1 = (Base) myTest.Clone();
Base clone2 = myTest;

as

Base clone1 = (Base) myTest.Clone();
Base clone2 = clone1;

:)
 
W

Willy Denoyette [MVP]

|
| <snip lots of agreements>
|
| > | I would make more of a fuss about this, but I suspect any code that it
| > | actually breaks is pretty poorly written to start with!
| >
| > True, but that doesn't mean that the Remarks clause couldn't be changed
into
| > something that clearly describes the exact behavior when the constructor
| > takes an empty char array or null, and that it's preferable to use
| > String.Empty to get an 'empty' string reference.
|
| Yup. Do you want to put it in the feedback centre or shall I? ;)
|
|

Just do it Jon if you will, I will vote for it.

Willy.
 

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