I got to this video after researching unity to help my niece out, and I have to say this just makes me appreciate C++ so much more. It manages to be much less verbose but simultaneously much more clear about what is going on.
in : arguments cannot be changed by the called method ref : arguments can be changed out : arguments must be changed by the caller and these changes are tracked in the calling context
readonly ref = const in C++, now we need a readonly method (which doesn't change the data members of the class) which returns a readonly ref (a reference which we can only read but not modify). I completely love these performance improvements :D
Another interesting case is if you have a class "class Point { public int X; public int Y; }" and then do something like: Point p = new Point { X = 5, Y = 10 }; ref int x = ref p.X; x = 20; int xb = x; xb = 25; where in the end p.X is 20 and p.Y is 10, as xb creates a copy from x which is then overridden but the assignment to xb never touches p.X
What I understood is, Say the main variable is A and the parameter is B, Reference type without ref: Creates an object on the heap and assigns that object's location to A. So when calling the method, it is actually passing the object it self. So what happens is, It creates another allocation in the stack named B which has the pointer to the same object. Now A and B both are pointing the same object. Now when you say B equals new object, it creates a new object in the heap and updates B's location to point to the new object. Now A is pointing to the first object and B is pointing to newly created one. That's why A is not affected. Reference type with ref: Creates an object on the heap and assigns that object's location to A. When calling the method, it is actually passing the a reference to A or a pointer to A. So what happens is, It creates another allocation in the stack named B which has the pointer to A. It is like saying A= new object and B = A. Now when you say B equals new object, it creates a new object in the heap and since B is just a pointer to A it updates A's location to point to the new object. That's why A is affected.
There is no "reference type without ref". You have a class, which is allocated on the heap, and you have a reference to it to access it. When passed to a method the reference is copied, but the data stays in place. You have a struct, which lives either inside a class, or on the stack. When passing it to a method the whole struct is copied onto the stack. Then you have a ref struct, the data is allocated once on the stack, and you're also given a reference to it like with a class. When passed to a method again the reference is copied, but the data again just stays in place. As objects on the stack are not controlled by the garbage collector accessing members of a ref struct is much more efficient than accessing members of a class. Then there is "passing by ref" where you have something like "myfunc(ref mytype x)", in which case a new reference is created for the method. That reference is either a reference to a reference of a class-object, or a reference to a struct, or just the copy of a reference to a ref struct. For the first case if you use new() the old reference is overridden with the reference to the new object. Any other references to the old object remain unchainged, and will still point to the old object. In the case of the latter two the actual data will be overridden.
One interesting point to mention in my opinion is that ref and out keywords with value type do not lead to any boxing/unboxing and it is pretty efficient in that case.
Huh never thought of this,but thats when you'd want to return a value,or just have a void function.When you pass by reference,you can ignore returning and put void.But if it's passed by value,you'd have to return the renewed value.I see.
Hi, thanks for your videos. Are you can to make some "off top" video? About chair, monitor rack, table? We are (programmers) spent a lot of time with this :) I'm interesting with your opinion about this topic. Thanks
Always thought that the confusing part was mixing the "ref means reference" and the "ref means stack-allocated", is there any logic behind why they both use the same keyword?
It's not so much a mix than you think. As C# is managed the actual data can usually be moved freely by the garbage collector and the reference to that needs to be updated when that happens. This is what happens when you have a class. The reference is a small lightweight object that points to your actual data, which is why classes are regarded as "slow". Now if you take structs if you use them inside a function they are allocated on the stack, if they are part of a class the data of the instance also stores the struct (which is on the heap). Now if you do 'var mystruct = something.mystructinstance' that struct is copied onto the stack for you to use, but chaning it will not also change the struct in the original something object. Now if you want a reference to the data which is in the something object you have to use 'ref var mystruct = ref something.mystructinstance'. The issue is that this reference just isn't as fast as accessing the struct directly. Now for C# to be as fast as most other languages here there's the 'ref struct'. As it can only be allocated on the stack so the whole garbage collector stuff which usually runs in the background isn't active. In essence if you're using a ref struct it's allocated on the stack and you're returned a direct pointer to the object which has way faster access than a class. If you would try to allocate a 'ref struct' on the heap it would essentially be nothing else but a class (ignoring stuff like inheritance which structs in C# do not have to keep them as light as possible).
@@DarthJane You misunderstand me. I know what the ref keyword does in both situations. I don't understand why we use the same keyword for very different things. Especially when constraining something to be stack allocated doesn't have anything to do with references, which is the namesake of the keyword.
@@DarthJane Wrong: Essentially, a ref struct is not allowed to be a field of a class. Why does this matter in an async context? Because the compiler converts an async method to a class, and all local variables are turned into a field, essentially.
@@weluvmusicz Depends on how you look at it. ref structs can still be used inside ref classes, but the point is that the scope of an async operation might shift, or even be on another whole thread which is why a ref class is not able to be used. So from that point of view your and my explanation are both true.
Not quite. C# also has pointers which is just like "basic C values and pointers", but not everyone knows C, and C# provides a similar, safer way of passing arguments by reference
@@sodiboo In that case while I was watching the video, yes. Who works with C, value and pointer, masters almost everything :) In embedded systems, its always a rule to pass structs as pointers due low footprint and limited stack. But pointers are "wild" hehehehe
Ok, this one is an unusual use that you might find interesting: Improving performance when accessing members of value tuples stored in arrays. Given: class Foo { (int, int, string, string, CustomObject) _Buffer; ... public CustomObject ReadObjectAtSlow(int index) { (_,_,_,_,var res) = _Buffer[index]; return res; } public CustomObject ReadObjectAtFast(int index) { // This should profile about 20% faster for big N scenarios ref var reftuple = ref _Buffer[index]; return reftuple.Item5; } }
public interface ISerivce{}
public interface ISerivce{}
public interface ISerivce{}
Please make a video on this topic
it's called type variance - simple to explain but hard to understand and use in your practice
+1 for a video on these.... They're really useful if you can pick up the times you should be using them, and such a pain to get those times right...
That wouldn't compile
@@tamaratiny 😂😂😂
Also It could be great to mention "in" keyword for structs
Watching Nick Chapsas video > Reading Docs
I got to this video after researching unity to help my niece out, and I have to say this just makes me appreciate C++ so much more. It manages to be much less verbose but simultaneously much more clear about what is going on.
Me here getting Pointers/Refs PTSD from my cpp era
Both pointers and refs are available in C# :-)
well it's not called c++++ for no reason lol
It's worth mentioning that you can't return a List element by reference.
Thank you so much! Learned something today. Didn’t know you could return ref values from a function!
in : arguments cannot be changed by the called method
ref : arguments can be changed
out : arguments must be changed by the caller and these changes are tracked in the calling context
readonly ref = const in C++, now we need a readonly method (which doesn't change the data members of the class) which returns a readonly ref (a reference which we can only read but not modify). I completely love these performance improvements :D
420 69 in the struct example :)
I love you nick
Another interesting case is if you have a class "class Point { public int X; public int Y; }" and then do something like:
Point p = new Point { X = 5, Y = 10 };
ref int x = ref p.X;
x = 20;
int xb = x;
xb = 25;
where in the end p.X is 20 and p.Y is 10, as xb creates a copy from x which is then overridden but the assignment to xb never touches p.X
Thanks Nick good content! I liked the fact you made a correction/clarification in the end, very professional and time saver.
I love your random values.
Thanks for a nice video, as always! Next time, please, add a reference to a video you are talking about, would be great!
What I understood is, Say the main variable is A and the parameter is B,
Reference type without ref: Creates an object on the heap and assigns that object's location to A. So when calling the method, it is actually passing the object it self. So what happens is, It creates another allocation in the stack named B which has the pointer to the same object. Now A and B both are pointing the same object. Now when you say B equals new object, it creates a new object in the heap and updates B's location to point to the new object. Now A is pointing to the first object and B is pointing to newly created one. That's why A is not affected.
Reference type with ref: Creates an object on the heap and assigns that object's location to A. When calling the method, it is actually passing the a reference to A or a pointer to A. So what happens is, It creates another allocation in the stack named B which has the pointer to A. It is like saying A= new object and B = A. Now when you say B equals new object, it creates a new object in the heap and since B is just a pointer to A it updates A's location to point to the new object. That's why A is affected.
There is no "reference type without ref".
You have a class, which is allocated on the heap, and you have a reference to it to access it. When passed to a method the reference is copied, but the data stays in place.
You have a struct, which lives either inside a class, or on the stack. When passing it to a method the whole struct is copied onto the stack.
Then you have a ref struct, the data is allocated once on the stack, and you're also given a reference to it like with a class. When passed to a method again the reference is copied, but the data again just stays in place.
As objects on the stack are not controlled by the garbage collector accessing members of a ref struct is much more efficient than accessing members of a class.
Then there is "passing by ref" where you have something like "myfunc(ref mytype x)", in which case a new reference is created for the method. That reference is either a reference to a reference of a class-object, or a reference to a struct, or just the copy of a reference to a ref struct. For the first case if you use new() the old reference is overridden with the reference to the new object. Any other references to the old object remain unchainged, and will still point to the old object. In the case of the latter two the actual data will be overridden.
One interesting point to mention in my opinion is that ref and out keywords with value type do not lead to any boxing/unboxing and it is pretty efficient in that case.
It’s not about just boxing but about the cost of passing a value type by reference too, which is very cheap
@@nickchapsas this is exactly what I meant.
@Nick Chapsas Hi, can you please share your settings on code visual look, what is this theme, or is it custom? Font size, font family, colors...
These videos are indeed helpful. tnx
Great content as always!
thanks buddy
69, 420 nice example bro
Lool
Huh never thought of this,but thats when you'd want to return a value,or just have a void function.When you pass by reference,you can ignore returning and put void.But if it's passed by value,you'd have to return the renewed value.I see.
Hi, thanks for your videos. Are you can to make some "off top" video? About chair, monitor rack, table? We are (programmers) spent a lot of time with this :) I'm interesting with your opinion about this topic. Thanks
Nice
Nice
@@eXelerator97 Nice
Cool video, thanks :)
I still don't know what the ref keyword in C# actually does. How is it realised? Is it just a stack pointer?
Ha I see what you did there. Thumbs up for that for sure
Okay Nick, Can we say that ref is same with pointer in c, c++ ?
Not really, ref is like C++ reference.
C# has actual pointers available in unsafe context.
It is a pity that there were no performance tests for ref structures.
Always thought that the confusing part was mixing the "ref means reference" and the "ref means stack-allocated", is there any logic behind why they both use the same keyword?
It's not so much a mix than you think.
As C# is managed the actual data can usually be moved freely by the garbage collector and the reference to that needs to be updated when that happens. This is what happens when you have a class. The reference is a small lightweight object that points to your actual data, which is why classes are regarded as "slow".
Now if you take structs if you use them inside a function they are allocated on the stack, if they are part of a class the data of the instance also stores the struct (which is on the heap). Now if you do 'var mystruct = something.mystructinstance' that struct is copied onto the stack for you to use, but chaning it will not also change the struct in the original something object. Now if you want a reference to the data which is in the something object you have to use 'ref var mystruct = ref something.mystructinstance'. The issue is that this reference just isn't as fast as accessing the struct directly.
Now for C# to be as fast as most other languages here there's the 'ref struct'. As it can only be allocated on the stack so the whole garbage collector stuff which usually runs in the background isn't active. In essence if you're using a ref struct it's allocated on the stack and you're returned a direct pointer to the object which has way faster access than a class.
If you would try to allocate a 'ref struct' on the heap it would essentially be nothing else but a class (ignoring stuff like inheritance which structs in C# do not have to keep them as light as possible).
@@DarthJane You misunderstand me. I know what the ref keyword does in both situations. I don't understand why we use the same keyword for very different things.
Especially when constraining something to be stack allocated doesn't have anything to do with references, which is the namesake of the keyword.
Why can't we mix ref with async?
async behind the scenes creates a state machine to store its data, so the "ref" you have will go out of scope.
@@DarthJane Wrong: Essentially, a ref struct is not allowed to be a field of a class. Why does this matter in an async context? Because the compiler converts an async method to a class, and all local variables are turned into a field, essentially.
@@weluvmusicz Depends on how you look at it. ref structs can still be used inside ref classes, but the point is that the scope of an async operation might shift, or even be on another whole thread which is why a ref class is not able to be used. So from that point of view your and my explanation are both true.
Is there a reason you use the VS colour scheme? To me it's kinda appalling that it doesn't have different highlighting for structs.
I just prefer it visually
Hello
7:48 yeah this is so random
ref the way you can make an struct behave as a class
Great video...
Video paused. Value shall be only "hello"
Its a basic C value and pointer..
Not quite. C# also has pointers which is just like "basic C values and pointers", but not everyone knows C, and C# provides a similar, safer way of passing arguments by reference
@@sodiboo In that case while I was watching the video, yes. Who works with C, value and pointer, masters almost everything :)
In embedded systems, its always a rule to pass structs as pointers due low footprint and limited stack. But pointers are "wild" hehehehe
It's more like C++'s `&` reference
@@protox4 Love and hate for the & and *. What else language can navigate thru structures with Ptr++ like a charm?
@@mascotto C, C++ and C# :-)
ref. The absolute worst feature of C#. Should be removed.
use sharp without refs
thats all)
Ok, this one is an unusual use that you might find interesting: Improving performance when accessing members of value tuples stored in arrays.
Given:
class Foo
{
(int, int, string, string, CustomObject) _Buffer;
...
public CustomObject ReadObjectAtSlow(int index) {
(_,_,_,_,var res) = _Buffer[index];
return res;
}
public CustomObject ReadObjectAtFast(int index) {
// This should profile about 20% faster for big N scenarios
ref var reftuple = ref _Buffer[index];
return reftuple.Item5;
}
}