C
C#2w ago
Faker

✅ out vs ref keyword usage

Hello guys, can someone explain when to use the out keyword and when to use the ref keyword please. I understand that in both scenarios, behind the scene, a pointer is passed so that any change made is reflected back. I also read that ref need to be initialized before passing value as argument while out doesn't but out need to be assigned a value inside the method itself. I don't understand where one is used over the other though... can someone explain please, any use cases/best practices.
35 Replies
Core
Core2w ago
I am no expert, but one use case of the out usage is the try patter. Let's say you want to convert/parse from one type to another, without the out keyword the method would either throw an exception, or return null / default value, the later is extremely ugly implementation. With the help of the out keyword it's possible to have the result in an out variable. Instead of thrown an exception, the variable would contain a null value. At the same time with try pattern the method could also return a boolean value.
c#
public bool TryDivide(int a, int b, out int result)
{
if (b == 0)
{
result = 0;
return false; // Division by zero, fail gracefully
}

result = a / b;
return true;
}
c#
public bool TryDivide(int a, int b, out int result)
{
if (b == 0)
{
result = 0;
return false; // Division by zero, fail gracefully
}

result = a / b;
return true;
}
canton7
canton72w ago
You're right, they're pretty much the same under the hood. However: * With ref, the caller needs to pass in a value, and the callee can read this. Because the caller is setting a value, the callee doesn't have to * With out, the caller does not have to pass in a value, but this means that the callee must assign one before returning These have different use-cases: out is for returning multiple values from a method, whereas ref is less used, and is for allowing the callee to mutate a value owned by the caller. For an example of why out is useful, see the TryXXX pattern. It would be quite annoying to have to do:
int result = 0;
if (int.TryParse(..., ref result))
int result = 0;
if (int.TryParse(..., ref result))
Rather than just:
if (int.TryParse(..., out int result))
if (int.TryParse(..., out int result))
Cattywampus
Cattywampus2w ago
Another neat usage of out is to avoid defensive copy by calling it inside a readonly methods
canton7
canton72w ago
That needs a lot more background before it's meaningful 😛 (I suspect it will also just be confusing to OP, as they're learning about much more basic things)
Cattywampus
Cattywampus2w ago
it's a way to roundtrip inside readonly methods when avoiding defensive copies see how they being used extensively here https://github.com/opentk/opentk/blob/master/src/OpenTK.Mathematics/Matrix/Matrix4.cs that said, its common on large structs. System.NumericsMatrixX also doing this trick
FusedQyou
FusedQyou2w ago
This goes way beyond the purpose of this thread tbh
Cattywampus
Cattywampus2w ago
how? 🙂 see the title again
canton7
canton72w ago
Yeah, you need a background on what defensive copies are, what readonly methods are, what problems you can get, etc, before that even starts to make sense. Tbh I'm pretty clued up on that and I've no idea what you mean by "a way to roundtrip inside readonly methods" ><
FusedQyou
FusedQyou2w ago
Faker posts here really often and is very actively learning C#. I know that defensive copies and all that are definitely not what they are looking for on their skill level.
canton7
canton72w ago
Good communication relies on being able to put yourself in your audience's shoes, and look at things with their level of knowledge, not yours
Cattywampus
Cattywampus2w ago
aight, fair
canton7
canton72w ago
If they've just learnt what ref and out are, defensive copies and readonly methods are waaay out of scope
Cattywampus
Cattywampus2w ago
to add to this out will also return a reference anwered that so I won't be completely out of the loop of this post 😉
FestivalDelGelato
i don't see async mentioned, so i'll mention that you can't use them with async
Cattywampus
Cattywampus2w ago
if it's a non-odd layout structs, just pass a span.. again we will be complained of being out os scope :kekw:
FestivalDelGelato
im not out of scope this is about ref/out usage
Faker
FakerOP2w ago
yeah I see, like we don't need to initialize when used with out keyword? yeah I see, this prevent the overhead of exceptions sometimes defensive copy is the same thing as deep copy/shallow copy ?
Cattywampus
Cattywampus2w ago
no
canton7
canton72w ago
Eh, it's similar in that it's a copy, but the compiler will copy a struct under-the-hood in some circumstances
Cattywampus
Cattywampus2w ago
the compiler will create a copy of the struct to prevent further possible mutation. I'd not say it's a deepcopy nor shallowcopy, just "defensive copy" a lil bit abbout it can be read here https://devblogs.microsoft.com/premier-developer/the-in-modifier-and-the-readonly-structs-in-c/
Faker
FakerOP2w ago
yep I see one last question, we say the out keyword is used to return "multiple" values; what do we mean by that? I'm a bit confused... in a method for example, we can only have a single return statement
FusedQyou
FusedQyou2w ago
You can have multiple parameters with an out keyword You could also just use a method return value and use a Tuple or an object, but multiple out parameters might be better suited for a method
Cattywampus
Cattywampus2w ago
as simple as this illustration right here
void Foo(out T returnOne, out T returTwo, out T returnThree)
void Foo(out T returnOne, out T returTwo, out T returnThree)
either way, we rarely do that nowadays because we have tuples now
(T one, T two, T three) Foo();
(T one, T two, T three) Foo();
FusedQyou
FusedQyou2w ago
See this example: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out
public void Main()
{
double radiusValue = 3.92781;
//Calculate the circumference and area of a circle, returning the results to Main().
CalculateCircumferenceAndArea(radiusValue, out double circumferenceResult, out var areaResult);
System.Console.WriteLine($"Circumference of a circle with a radius of {radiusValue} is {circumferenceResult}.");
System.Console.WriteLine($"Area of a circle with a radius of {radiusValue} is {areaResult}.");
Console.ReadLine();
}

//The calculation worker method.
public static void CalculateCircumferenceAndArea(double radius, out double circumference, out double area)
{
circumference = 2 * Math.PI * radius;
area = Math.PI * (radius * radius);
}
public void Main()
{
double radiusValue = 3.92781;
//Calculate the circumference and area of a circle, returning the results to Main().
CalculateCircumferenceAndArea(radiusValue, out double circumferenceResult, out var areaResult);
System.Console.WriteLine($"Circumference of a circle with a radius of {radiusValue} is {circumferenceResult}.");
System.Console.WriteLine($"Area of a circle with a radius of {radiusValue} is {areaResult}.");
Console.ReadLine();
}

//The calculation worker method.
public static void CalculateCircumferenceAndArea(double radius, out double circumference, out double area)
{
circumference = 2 * Math.PI * radius;
area = Math.PI * (radius * radius);
}
Cattywampus
Cattywampus2w ago
also note, there's an obvious difference between the two. the out is actually returning a reference, whicle tuples dont
FusedQyou
FusedQyou2w ago
Below the example on the site is also some rules regarding out keywords, which FestivalDelGelato already hinted on. The following limitations apply to using the out keyword: - out parameters are not allowed in asynchronous methods. - out parameters are not allowed in iterator methods. - Properties cannot be passed as out parameters.
Faker
FakerOP2w ago
yeah I see
FusedQyou
FusedQyou2w ago
The thing with async code and iterators is that it can't properly ensure that the out parameter is set or set to its latest value, so it's just not supported because of it.
Cattywampus
Cattywampus2w ago
Specifically for last point there if your intention to use out as a ref return on properties, which out can't, ref T Foo => ref someStruct can
FusedQyou
FusedQyou2w ago
So generally with async code you just return an object or struct as the return type. Iterators' purpose is to return a collection of items so out parameters don't really make sense anyway
Cattywampus
Cattywampus2w ago
nah, I believe the main reason would be related to concurrency that's why they dont allow it
FusedQyou
FusedQyou2w ago
If this is a comment on why async code can't have an out parameters then yes, most likely All out parameters must be assigned a value before the method returns, but an async method effectively returns immediately by returning a Task, meaning the value wouldn't be available yet until the method reaches a point where the value would have been set.
Faker
FakerOP2w ago
I now have an overview of the out keyword but still need to familiarise with it, thanks guys 👍
Cattywampus
Cattywampus2w ago
can you pls tag this as solved, this is pretty annoying ngl :awesome:
No description
Faker
FakerOP2w ago
yep sorry

Did you find this page helpful?