Jump to content

  • Log In with Google      Sign In   
  • Create Account

Ch 3 oddity


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
6 replies to this topic

#1 Sammie22   Members   -  Reputation: 102

Like
0Likes
Like

Posted 21 January 2011 - 08:40 PM

I found this a little strange.. Maybe I'm having a brain fart here but in Managing Memory section, the author states:

"When you pass in a reference type, we are actually passing a copy of the reference to the data."

He then states, in regards to the 'ref' keyword:

"We should not use this keyword on reference types because it will actually slow things down..."

Then, in Program.cs for the PerformanceChecker, he has this static method signature:

static void PrintPerformance(string label, ref Stopwatch sw) { ... }

At first I was thinking Stopwatch was a struct, but it is a class. So am I missing something here, or did he just say one thing and do another? There is no reason I see to pass as a reference, as it does not redefine the memory pointer for that reference. It only access the member variables of that object.

Sponsor:

#2 kiwibonga   Members   -  Reputation: 174

Like
0Likes
Like

Posted 22 January 2011 - 12:13 AM

I now have the same question.

I googled around and I couldn't find any other evidence that using ref when passing reference-types would "slow things down..." In fact, NOT using it means the reference is copied before being pushed to the stack, so there's actually a (probably completely negligible) performance hit from doing that copy and then destroying it.

Odd, to say the least.



#3 Stotto   Members   -  Reputation: 103

Like
1Likes
Like

Posted 22 January 2011 - 07:01 AM

Using ILDASM (C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\ildasm.exe), you could perform a test to see what the difference is between the two.

Lets say we have a class as follows:

class Foo
    {
        public int foo1 = 0;
    }


And lets say we have two methods:

Foo3 (not using the ref keyword)
static void FooMethod3(Foo foo)
        {
            foo.foo1 = 3;
        }

Foo4 (using the ref keyword)
static void FooMethod4(ref Foo foo)
        {
            foo.foo1 = 4;
        }


So lets take a look at the CIL code using ILDASM to see what is going on behind the scenes:

Foo3 (not using the ref keyword)

.method private hidebysig static void  FooMethod3(class RefTest.Foo foo) cil managed
{
  // Code size   	9 (0x9)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.3
  IL_0003:  stfld      int32 RefTest.Foo::foo1
  IL_0008:  ret
} // end of method Program::FooMethod3

And Foo4
.method private hidebysig static void  FooMethod4(class RefTest.Foo& foo) cil managed
{
  // Code size   	10 (0xa)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldind.ref
  IL_0003:  ldc.i4.4
  IL_0004:  stfld      int32 RefTest.Foo::foo1
  IL_0009:  ret
} // end of method Program::FooMethod4

Note: if you optimize these two methods you will just get rid of the nop instruction.


So we can see that Foo4 actually has one more instruction than foo3, called ldind.ref. This instruction is us dereferencing the reference we have made. The rest of the instructions are Identical (well, except for us assigning one a value of 3 and the other a value of 4). There is certainly a performance hit due to one extra operation being performed. But there can be arguments for using the ref keyword with reference types as well.

In the case of the example in the book, I feel that your conclusion is spot on Sammie because as you stated, Stopwatch is not a structure, and only instance-members are accessed, with no re-referencing occurring. There currently is no real need for the ref keyword.

#4 Sammie22   Members   -  Reputation: 102

Like
0Likes
Like

Posted 22 January 2011 - 04:57 PM

Very nice Stotto.. thanks for the reply. And I did not know about that tool, which looks pretty handy.

#5 kiwibonga   Members   -  Reputation: 174

Like
0Likes
Like

Posted 23 January 2011 - 11:19 AM

Thanks for the explanation!

Unfortunately, I'm still confused... Why is it that feeding the reference "directly" requires it to be dereferenced, but feeding a copy of it doesn't?



#6 Stotto   Members   -  Reputation: 103

Like
1Likes
Like

Posted 23 January 2011 - 12:40 PM

Kiwi, I think your confusion lies within how the ref keyword actually operates.

Okay, so as we know:

When a value-type is stored, we store the value.
When a reference-type is stored, we store the contents of the type else-where, and in the reference-type, store a pointer to where those contents are located.

Now, when we don't use the ref keyword:

When a value-type is passed in, we pass in a a copy of that value.
When a reference-type is passed in, we pass a copy of the pointer to where the contents are located.

Using the ref keyword:

When a value-type is passed in, we pass in a pointer to where the value is located.
When a reference-type is passed in, we pass in a pointer to where the reference-type is located. That is to say, we pass in a pointer TO the pointer of where the contents are located.


This may seem odd at first, but I will explain why it is done.

Lets say we have two objects, Foo1 and Foo2. Perhaps we want to make a method that will make Foo1 point to Foo2's contents.

So what we want to do is change the pointer in Foo1 to equal the pointer in Foo2. If we only pass in the locations of the contents, but not the locations of the pointers, we wouldn't be able to do this! We couldn't set the pointer in Foo1 to Foo2 because we do not know where the pointer in Foo1 is located.

By passing in a reference to the reference-type, we now now know where the pointers are located. And because of that we also know their contents, though indirectly. We have to follow the first pointer, to the second, which will lead us to the contents. This is why the dereferencing needs to occur when you are accessing a reference-type's members with the ref keyword.

I hope this helped explain that a little better for you. And if you need further explanation feel free to ask.

#7 kiwibonga   Members   -  Reputation: 174

Like
0Likes
Like

Posted 23 January 2011 - 11:26 PM

Thanks for taking the time to write all that -- I get it now!

Still learning C# for the workshop... :)






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS