4

Question

Why does the "out" parameter exist in C# as a language construct?

Elaboration on the question

Why does it exist in the first place? Aren't there better language features to get the same effect one can get with the "out" parameter?

Isn't it strange to make an value type behave like a reference type?

Aren't there better ways to return multiple values from a method?

Is it a historical thing, meaning with the first versions of C# there was no way to achieve the things one can achieve with the out parameter but now there are newer features and it's just kept in the language for backwards compatibility?

What I'm not asking

  1. I'm not asking what it does
  2. I'm not asking how it is used
  3. I'm not asking what the difference between "ref" and "out" is
  4. I read that one should avoid its use and choose other constructs

I haven't found any duplicates while reading the similar questions.

Expected answer format

I'd love to hear something like, "Look, here is a problem you can only solve with the use of the "out" parameter language construct and here is a code example for it...".

Or, "Look, this used to be the only way to solve the following problem ...code example..., but since C# version ... the better way to solve is like this ... code example...".

No opinions please.

Lernkurve
  • 20,203
  • 28
  • 86
  • 118
  • For those voting to close this question, could you please let me know why? Is the question unanswerable the way it is posed? https://stackoverflow.com/help/how-to-ask – Lernkurve Sep 13 '18 at 09:46
  • I didn't but I'm assuming people are voting to close because it will be primarly opinion based – Greggz Sep 13 '18 at 09:48
  • Its a good question framed with proper citation. I wouldn't agree on closing this question although this is opinion based. It still can have a good answer. – Carbine Sep 13 '18 at 09:48
  • I think it exists to make sure no bugs are created by people that oversee the method is modifying their reference. – horotab Sep 13 '18 at 09:49
  • 5
    By definition, this question is opinion based, that's why it's being closed. – DavidG Sep 13 '18 at 09:49
  • Agreed, its by definition its opinion based. But still a good question nevertheless. SO has changed in the past on their rules, Rules are meant to be changed. – Carbine Sep 13 '18 at 09:50
  • 5
    @DavidG: I don't understand. How is this opinion based? Isn't it possible to say, "Look, this problem can only be solved with the use of the 'out' parameter and here is a code example"? Just as KristoferA just did in his [answer](https://stackoverflow.com/a/52311117/33311)? – Lernkurve Sep 13 '18 at 09:53
  • At the most basic level, `out` and `ref` expose pass-by-reference for value types, which is a core feature of the .NET runtime, and not easily emulated or replaced without compromising performance. Whether it's a good idea to use `out` in any given (managed) scenario is a separate discussion. – Jeroen Mostert Sep 13 '18 at 09:53
  • SO Strikes again! – Carbine Sep 13 '18 at 09:55
  • 3
    It's obvious that you could get the same result using `ref`, only you wouldn't be guaranteed that the parameter would be initialised inside the method. It was probably the C# design team's **opinion** that it would be good to add this support. However, without actually getting anyone from the C# language team to answer this question, or linking to such an answer elsewhere, all the answers here would just be someone's opinion. – Matthew Watson Sep 13 '18 at 10:00
  • 2
    It exists because the [language specification says it does](https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf) – Liam Sep 13 '18 at 10:00
  • 5
    I disagree with those who think this is opinion based. I'm too lazy to spend an hour googling it, but I *bet* there is a quote somewhere from Hejlsberg or Lippert on this. – KristoferA Sep 13 '18 at 10:00
  • @MatthewWatson: that's not to say that members of the C# language team don't actually use SO and couldn't provide such answers -- because they do and they can. – Jeroen Mostert Sep 13 '18 at 10:07
  • 2
    @JeroenMostert `answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise` See any of that going on here? I do. – Matthew Watson Sep 13 '18 at 10:09
  • 2
    @MatthewWatson: I have no strong opinion (heh) on whether this question is rightfully closed or not. I'm just saying that the possibility of an expert answering the question based on facts is not even improbable. – Jeroen Mostert Sep 13 '18 at 10:16
  • 6
    Entymology questions are usually not a good fit for Stack Overflow because you're really looking for the root reason for something, whereas the root reason **we** know about is just as @Liam said, it is there because the specification says it is there. You're asking why someone added it to the specification in the first place, which will require those people, and as Jeroen posted above, the chance of getting one of them to post a definitive answer is not even improbable. We can all come up with good reasons why it is there, or good reasons why it should be removed, but **those** are opinions. – Lasse V. Karlsen Sep 13 '18 at 10:21
  • 2
    We already have one answer here and I can already poke a hole in that by saying that with unsafe code and pointers you can do the same thing, you don't **need** `out` parameters. They could've been added for convenience (in relation to api-work and p/invoke), they could've been replaced by structs (before tuples) or with tuples (today) so to come up with an answer that says "In this case here, `out` is the only solution" is going to be a hard stretch. – Lasse V. Karlsen Sep 13 '18 at 10:24
  • I've updated the question with an "Expected answer format" section. – Lernkurve Sep 13 '18 at 10:24
  • 2
    All I can say is good luck, both with keeping the question and open and getting an actually good answer. – Lasse V. Karlsen Sep 13 '18 at 10:25
  • @LasseVågsætherKarlsen Well it's already been reopened and I doubt we will get 5 more closers now – DavidG Sep 13 '18 at 10:27
  • 2
    I voted to close as "opinion-based" because the question generates massive amounts discussion that doesn't lead anywhere. It's clear that "out" didn't have to exist, as there are other languages that don't have it. It's just a decision made by the C# designers. – Wim Coenen Sep 13 '18 at 12:00
  • 3
    It can't be opinion based when nobody here seems to understand the definite assignment feature of C#. Odd btw. Voting to reopen. – Hans Passant Sep 22 '18 at 12:04

3 Answers3

12

The C# compiler performs definite assignment checking. That requires it to know exactly when a variable is assigned. Usually not hard to figure out, an assignment is pretty easy to see back.

But there is a corner-case is when a variable is passed by reference to another method. Does the method require that variable to be assigned before the call, then modifies it, or is it only ever going to assign it? The compiler in general cannot know, the method may live in another assembly with the method body unavailable. True for any .NET Framework assembly for example.

So you have to be explicit about it, you use ref when the method requires the parameter to be assigned before the call, out when the method only ever assigns it. Great feature btw, it eliminates an entire swath of very common bugs.


One note about other incorrect answers on this question. Data flow plays an important role in pinvoke as well, the pinvoke marshaller needs to know whether the convert any data returned by an unmanaged function. It does not pay attention to out vs ref keywords, only to the [In] and [Out] attributes. More about that gritty detail in this Q+A.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • I would like to ask an question regarding the last statement. If I use `out` to a value object in an `unsafe` context, do I need to use a `fixed` statement? – ChristianMurschall Sep 13 '18 at 12:33
  • That comment is hard to parse, starting with "value object". In general there is no need to ensure that the passed object cannot be garbage collected. The GC finds it back when it walks the stack. Use the fixed statement only to generate a pointer. – Hans Passant Sep 13 '18 at 12:41
  • Sorry for the bad phrasing. What I mean is this: Afaik the GC is allowed to move any object to another memory location. If I send a pointer to a pinvoke call, I'm concerned, that the GC has moved the object away from the pointed location. – ChristianMurschall Sep 13 '18 at 12:48
  • 1
    One of the basic duties of the pinvoke marshaller is to pin anything you pass. By itself, no help required. If you pass a pointer explicitly (don't) then it does become your job. But C# demands you use GCHandle or the fixed statement to generate that pointer so you can't get that wrong. I strongly recommend you use the Ask Question button with a concrete example to learn more. – Hans Passant Sep 13 '18 at 12:57
5

One reason would be for compatibility with e.g. Win32 APIs. Some method declarations for Win32 API calls will require the use of out and/or ref if you want to call them directly from C#.

You can find some examples of such method declarations at pinvoke.net: http://pinvoke.net/search.aspx?search=out&namespace=[All]

KristoferA
  • 12,287
  • 1
  • 40
  • 62
  • [Here's some P/Invoke code that works using either `out` or `ref`](https://dotnetfiddle.net/ieeUDP) which demonstrates that `out` is *not* required for compatibility with the Windows API. – Matthew Watson Sep 13 '18 at 12:08
1

Why does it exist in the first place? Aren't there better language features to get the same effect one can get with the "out" parameter?

Whats "better"? Arguing based on C#7 where things are a bit easier, is this:

public static (bool Succesful, int Value) TryParse(string s) { ... }

var parseResult = TryParse(s);
if (parResult.Succesful)
    DoSomething(parResult.Result);

better than?

if (int.TryParse(s, out var i))
    DoSomething(i);

Hmmm....

And before native tuple suport, you'd actually have to implement a struct/class to be able to return multiple values.... yuck. True that the out solution wouldn't be as clean either, but still a better option than having to litter your code base with tons of lightweight container classes to simply have methods return multiple values.

Isn't it strange to make an value type behave like a reference type?

Why? Even if its only for backwards compatibility or for interop, its a needed language feature.

Aslo, your mixing up things here. If you want pass by reference semantics, you'd use the ref keyword. The out keyword means that the parameter is meant to be used as a return value; the fact that it needs to be passed by reference is an implementation detail.

Aren't there better ways to return multiple values from a method?

This is basically your first question rewritten.

Is it a historical thing, meaning with the first versions of C# there was no way to achieve the things one can achieve with the out parameter but now there are newer features and it's just kept in the language for backwards compatibility?

Backward compatibility is the obvious and important reason. Also, just because there are better ways to do things doesn't necessarily mean that language features should be removed. You could then make a case for many other language constructs: for loops, goto, etc.

InBetween
  • 32,319
  • 3
  • 50
  • 90