C# delegates blow my mind

Started by
18 comments, last by -MadHatter 15 years, 11 months ago
Quote:Original post by Sneftel
Quote:Original post by -MadHatter
reference types are passed by reference. value types are passed by value. anything declared as a struct is a value type, while things declared class are reference types.

You seem to be confusing reference types with reference passing. C# passes both value and reference types by value, unless the ref keyword is given. The remainder of your post shows that you understand the practical upshot of C#'s system, but you should get your terminology straight. There's nothing "sort of" about C#'s evaluation strategy. ref variables are passed by reference; everything else, value type or reference type, is passed by value.


Think I need to clear something up here before people get confused.

First of all we will go over some terms to make sure we are all on the same page.
reference type and value type - these are the two base types, value types are structs and other base types such as int, float, ect. When you use a value type a copy of the information is made and that is used. A reference type (classes) are used by reference, so when you use them the reference is passed around not the data itself.

reference parameters vs. value parameters. Unless you use the 'ref' keyword, the parameter for a method will be a value parameter, so the parameter will be passed by value.

So what does this mean to us? Well that is where it gets a little strange.

take the fallowing

DoSomething(myClass a);

That is a value parameter, so we are passing it by value but what does it really mean? It means that we are coping the data. So what data gets copied? The reference to a gets copied and passed in. So why is this important? Let me show you.

void DoSomething(myClass a)
{
a = new myClass();
a.Text = "Did something";
}

So we do this.

myClass first = new myClass();
first.Text = "Some text";

Now we call the function.

DoSomething(first);

What will be the value of first.Text when we are done? It will still be "Some text";

Now we call the functions using a function call like so; void DoSomething(ref myClass a);

What will the value of first.Text be when you are done? "Did something".

So why is that? Because in this case we are passing the acutal reference to first and not just a copy. In the first case we changed the reference and so we were no longer referencing 'first', in the second one we were always referencing 'first'.

I really hope that didn't confuse anyone. By value of a reference is just a copy of the reference and doesn't really matter unless you change the reference.

theTroll


Advertisement
Quote:Original post by TheTroll
Because in this case we are passing the acutal reference to first and not just a copy.

No, it's because we pass the reference by reference.
Quote:Original post by Washu
You should perhaps read my blog posts on this very subject. Inlining in .Net is actually quite different than perhaps what you're used to.


Now that was an interesting read. One thing popped in my mind though. In some "dumb" compilers you can optimize looping over an array sequentially by using running pointers:

for (int i = 0; i < count; i++){  x += array; // array: extra instructions for calculating the memory address of the value}


can be optimized into:

int* ptr = array;int* end = array + count;while (ptr < end){  x += *ptr;  ptr++;}


In an embedded audio processing project I did recently this simple optimization resulted in 10-20% fewer instructions for functions that were mainly made up of such loops.
Note though that the processing was relatively simple and was mainly made up of loops like these. The things that were done inside the loop every iteration was not much.


But what I was wondering is if the JIT will pick up on optimizations like these or if the "foreach" keyword can play a role here? A search on "foreach vs for loops" does not turn up anything that indicates this though, but I can't help but wonder.

Now, I do realize that for games this is less of an issue as the heavy number crunching does not depend on looping over arrays, but for video and audio processing this is more of an issue where you are constantly looping over buffers.
STOP THE PLANET!! I WANT TO GET OFF!!
Quote:Original post by DevFred
Quote:Original post by TheTroll
Because in this case we are passing the acutal reference to first and not just a copy.

No, it's because we pass the reference by reference.


No, it works exactly as I described. Why don't you test it and you will be a bit shocked.

This exact thing bit me hard when I first started working in C#.

theTroll
Quote:Original post by TheTroll
Quote:Original post by DevFred
Quote:Original post by TheTroll
Because in this case we are passing the acutal reference to first and not just a copy.

No, it's because we pass the reference by reference.


No, it works exactly as I described. Why don't you test it and you will be a bit shocked.

This exact thing bit me hard when I first started working in C#.

theTroll


No, it's because the reference is passed by reference.

I'm not saying it doesn't behave as you described, it's your explanation that's not correct. But it's possible that in the end, it's just a terminology issue.
But what is certain, is that it does work with a reference-to-a-reference-to-an-object.

No, the reference is passed by-value, unless you specify 'ref'.

So you have a copy of the reference, not the reference. Now in most cases this does not matter, it works the same. The exception is if you try to create a new object based on that reference. Because it is a copy of the reference and not the original reference when you do a new you do create a new object, but it's reference is assigned to the copy of the reference not to the original one. So then you will loose what you just created.

This is covered under parameters in the C# Standard.

"12.1.4 Value parameters
A parameter declared without a ref or out modifier is a value parameter.
A value parameter comes into existence upon invocation of the function member (method, instance
constructor, accessor, or operator) to which the parameter belongs, and is initialized with the value of the
argument given in the invocation. A value parameter ceases to exist upon return of the function member
(except when the value parameter is captured by an anonymous method (§14.5.15.3.1) or the function
member body is an iterator block (§26))."

theTroll

P. S. Just for some mucilaginous information. DoSomething(myClass a) and DoSomething(ref myClass a) are different in relation to function overloading. So both would be allowed without giving you an error. Makes sense just never thought of it before.
Quote:Original post by TheTroll
Quote:Original post by DevFred
Quote:Original post by TheTroll
Because in this case we are passing the acutal reference to first and not just a copy.

No, it's because we pass the reference by reference.

No, it works exactly as I described. Why don't you test it and you will be a bit shocked.

It does work as you described, and I never doubted that.

All I'm saying is that your terminology is a bit fuzzy. The reason it works as described is because if you use the ref keyword, the reference gets passed by reference instead of by value. This does not make the reference more "actual".
With all the cold medication I am on right now, I am a bit surprised I was not talking about pink bunnies. Also typed that holding a 4 month old that is sick also. So yeah, the terminology could have been much better.

Just didn't wanted to try to make sure that folks understood there is a difference between passing by-reference and passing a reference by-value.

theTroll
Quote:Original post by TheTroll
there is a difference between passing by-reference and passing a reference by-value.

That is the gist of it, yes.

The problem is that in C# and Java, pointers were (restricted and) renamed to "references", so there are certain types that consist of values called "references". Since these references are values, expressions can yield references, you can store references in variables etc.

In C++ we have a clear distinction between pointers and references. In C++, pointers are values (addresses of objects*), whereas references are not. A reference variable is just another name for some object, there are no references to references (because a reference is not an object) etc.

References were introduced in C++ to support call-by-reference semantics in operator overloading (so user-defined types could be used just as built-in types). The concepts "reference" and "call-by-reference" are closely related in C++.

In Java there is only call-by-value (primitive types are passed by value and reference types are passed by value), and there are no user-defined value types (classes always define reference types). So the term "reference" always means "reference to an object", which is a value.

In C#, there are user-defined reference types (classes) and user-defined value types (structs), and there is call-by-value and call-by-reference. You can
- pass value types by value (the object is copied)
- pass value types by reference (the original object is used)
- pass reference types by value (the reference is copied)
- pass reference types by reference (the original reference is used)

So you have to be very carefully when you talk about the word "reference" in C#. Do you mean the reference to an instance of a class (a value), or do you mean "call-by-reference" (a parameter passing mechanism involving the keyword ref)?

* In C++, an object is something that consumes memory and has an address. Don't confuse this with the term "object" in "OOP". I bet Zahlman can come up with a better definition though ;)

[Edited by - DevFred on May 14, 2008 3:06:21 PM]
unlike java, you can still use normal pointers in .NET, but yea, they renamed managed pointers to handles in .net.

This topic is closed to new replies.

Advertisement