3

I don't understand why I have to declare a variable when calling a method with an out parameter even though I don't care about the out value provided by the method.

To me it seems that it's analogous to calling a method with a return value bool Foo() but not consuming it Foo();. Having the possibility to mark the out parameter as optional would make my code cleaner or would spare the API developer write an overload without an out parameter for the method.

So, what is the reason that out parameters can't be optional?

leppie
  • 115,091
  • 17
  • 196
  • 297
David
  • 2,426
  • 3
  • 24
  • 36
  • Do you have an example of where this is optional? All the times I can think of, the out parameter is there to provide useful information – Sayse May 06 '15 at 07:56
  • 1
    @Sayse You could use a `int.TryParse` to check if a string is a number, while not being interested in its value. There are some use cases for ignoring the out parameters. – xanatos May 06 '15 at 07:58
  • @SonerGönül doesn't explain the why. – Patrick Hofman May 06 '15 at 07:59
  • @xanatos - Yes, but at the same time if it is a number there is a good chance that you would want to use that number somewhere later on – Sayse May 06 '15 at 07:59
  • The presence of such out parameter indicates that code requiring use of the method needs additional info besides the info returned after method execution. If you're calling the method in a part of your code where you don't need that additional info, my only thought is that you should really write an overload (OR, actually, avoid out parameters by having multiple methods instead of that one with the out-param if you can, which should produce cleaner code.) – Allmighty May 06 '15 at 08:00
  • 1
    Bear in mind that `out` has existed since C# 1.0. Optional was introduced much later (to C#). – Damien_The_Unbeliever May 06 '15 at 08:01

4 Answers4

3

I think there isn't a real reason why it can't be. Maybe the reason is just: because it is documented.

As far as I know, there isn't any compiler magic that makes out special. Look at this CIL code:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       17 (0x11)
  .maxstack  1
  .locals init ([0] int32 y)
  IL_0000:  nop
  IL_0001:  ldloca.s   y
  IL_0003:  call       void ConsoleApplication15.Program::X(int32&)
  IL_0008:  nop
  IL_0009:  ldloc.0
  IL_000a:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_000f:  nop
  IL_0010:  ret
} // end of method Program::Main

.method public hidebysig static void  X([out] int32& i) cil managed
{
  // Code size       6 (0x6)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.s   10
  IL_0004:  stind.i4
  IL_0005:  ret
} // end of method Program::X

Derived from this method:

public static void X(out int i)
{
    i = 10;
}

static void Main(string[] args)
{
    int y;
    X(out y);

    Console.WriteLine(y);
}

As you see, the variable is allocated in the calling method, and the value is passed 'by reference'. Defining a default value for an out parameter 'just' breaks checking if a value is set (since it is already).

Also, as Damien_The_Unbeliever commented, it might just be a feature overlooked / skipped in the initial build of optional parameters, since out already existed back then.

Community
  • 1
  • 1
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • Using this reasoning, even optional parameters are a trick of the compiler, and they don't exist at the CIL level. Both `out` and "optional" are compiler tricks, lightly supported with meta attributes – xanatos May 06 '15 at 08:13
  • @xanatos: Any reference? Also `[opt]` is a CIL parameter attribute. – Patrick Hofman May 06 '15 at 08:16
  • The disassembly http://goo.gl/ulNaS4 . 5 is set caller-side (IL_0001: ldc.i4.5) – xanatos May 06 '15 at 08:18
  • @xanatos: Indeed. That is on optional, but `out`? – Patrick Hofman May 06 '15 at 08:20
  • `out` and `ref` are nearly the same thing at CIL level... In fact there is a single `Type.MakeReferenceType()`, not two. – xanatos May 06 '15 at 08:23
  • @xanatos: Okay. That would still support my sentence 'it isn't that special'. So it could be implemented I guess. (from a noob point-of-view) – Patrick Hofman May 06 '15 at 08:25
  • 1
    Yes... Perhaps I misread your answer... Now that I reread it there is nothing that I don't agree with (or to put it more clearly: I agree with all your response). – xanatos May 06 '15 at 08:27
  • @xanatos: Thanks. I updated according to the knowledge gained from your comments. – Patrick Hofman May 06 '15 at 08:30
  • 1
    *It would be very hard for the compiler to come up with a default allocation for the variable (for reference types the only logical thing would be null)* But this is false... `default(T)` is always valid in C# – xanatos May 06 '15 at 08:32
  • @xanatos: Indeed. Left out out again. – Patrick Hofman May 06 '15 at 08:35
1

Out parameters are compiler trick. There is nothing called as out parameter in CLR world. It is really the ref parameter which is passed in to the method.

Difference is that compiler will make sure value is assigned before the method exits. That's it.

So, when you need to call a method with ref/out parameter you don't need a value but a reference to a variable/field.

For optional parameters, c# compiler will pass the default value when calling methods, but here you can't; you need a reference.

If compiler has to support this feature, it has to create a variable for you, pass it by reference and ignore the result. As you can see this is an ugly thing to do and hence we don't have that feature.

Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
  • 3
    In this discussion, I think an explanation on the down-vote would be very useful, so down-voter, please do. – Patrick Hofman May 06 '15 at 08:12
  • 3
    @PatrickHofman Stackoverflow has become meta I guess. People tend to downvote if they don't like your answer :\ – Sriram Sakthivel May 06 '15 at 08:15
  • Well, I find out last sentence very interesting (what if it is an object and doesn't have a default constructor...). I think you might be right. +1 – Patrick Hofman May 06 '15 at 08:17
  • I do not agree. The compiler makes hidden locals everywhere. For example, when using `using(IDisposable)` a hidden local is always created. – Martin Mulder May 06 '15 at 08:18
  • @MartinMulder: But you specify the construction of the object yourself. In this case you can't. – Patrick Hofman May 06 '15 at 08:18
  • 1
    @Patrick Homan: Yes and NO. The value inside `using` is assigned to the hidden local. The hidden local is disposed when losing scope, not the given local. You can try this to change the given local inside the using-scope and see if it will get disposed. You will see the original object will be dispose, not the newly assigned value. – Martin Mulder May 06 '15 at 08:20
  • @MartinMulder Hidden local is created but it is on purpose but not to just throw away. In this case compiler has to throw it away after use. Also there will not be a hidden local created when you give the local variable. It will only be created when you don't give a local. i.e `(using (new MyDisposable()))` not when `using (MyDisposable d =new MyDisposable())` – Sriram Sakthivel May 06 '15 at 08:25
  • @Sriram Sakthivel: True. But do we not do that every time we call a function and ignore its return value? True, on a technical level we do not create a local. But on a functional level, we ignore values either way. So seen from a technical point op view: Optional out's can be done, on from a functional point of view: We already have the possibility to ingore return values, so why not the possibility to ignore out-values? – Martin Mulder May 06 '15 at 08:28
  • @MartinMulder I never said we can't do this. We can, but by doing so involves rather ugly trick. Creating a local isn't a bad thing, but creating a hidden local and passing it with `ref` then ignoring the result is a bad thing to do IMHO. – Sriram Sakthivel May 06 '15 at 08:30
  • 1
    So... we create hidden locals... that is okay. We already ignore return values... that is okay too. So why does it becomes "ugly" when we combine those two? – Martin Mulder May 06 '15 at 08:35
  • @MartinMulder *We already ignore return values* We refers to the developers here. Developers create local, pass it as ref and we ignore the result. Not the c# compiler. In this case, C# compiler has to do the thing. It is not optimal for the compiler to create code which passes the hidden local as `ref` to some method just to ignore it later. – Sriram Sakthivel May 06 '15 at 08:45
  • @Sriram Sakthivel: With `ignore return values` is was refering to return values from functions, as i stated in my previous comment. – Martin Mulder May 06 '15 at 08:56
0

The "current" C# compiler (pre-Roslyn) is quite complex, and at Microsoft they tried to modify it only when strictly necessary. Optional parameters where necessary for COM interop, so they added them. Perhaps optional out parameters weren't necessary.

We can hope that with Roslyn the compiler will advance more quickly and we will enter a new age of syntax bloath :-)

Someone did a feature request for this on the Roslyn github: https://github.com/dotnet/roslyn/issues/186

xanatos
  • 109,618
  • 12
  • 197
  • 280
  • 3
    In this discussion, I think an explanation on the down-vote would be very useful, so down-voter, please do. – xanatos May 06 '15 at 08:14
  • I think complexity of the compiler is not an argument. The compiler solves much bigger problems than this. – Martin Mulder May 06 '15 at 09:35
  • @MartinMulder No, various times persons that "know" said that features wheren't added to the compiler because A) You don't add unless you really need it and B) the C# compiler was quite complex and so they didn't want to touch it too much – xanatos May 06 '15 at 09:36
  • Argument B is almost always rejected if (argument A) they really want it. The technical argument is almost always a non-argument. It is possible, as simple as that. The only question is: do they realy want it? – Martin Mulder May 06 '15 at 09:42
  • @MartinMulder Let's it compare it with another feature: `Null-conditional Operator` of C# 6.0 (the `?.` operator)... To change the compiler is probably quite "simple" (if something can be really "simple", you still have to change the grammar), it is entirely boilerplate code that has to be inserted (like with the `??` operator). It is a very useful feature (you write hundred of `if (xxx != null) { xxx.DoSomething())` in your code)... We will have to wait another year to have it. – xanatos May 06 '15 at 09:47
  • True. As I stated in my own answer: It us up to the developers of the C#-language if the want this. And of course they want many things, so they have to choose what they want most. But it is a question of "wanting", not if it is "to technical" or "to complex". – Martin Mulder May 06 '15 at 09:51
0

I think there are two levels to this discussion. The technical level and functional level.

On the technical level the question should be: Is it possible / can it be done? In this case, the answer is YES. For the compiler it is very easy to create a hidden local and call the method with the optional out parameter with a reference to this hidden local.

On a functional level we should ask ourselves: Is this what we realy want?

My opinion is: Why not? We are already ignoring return values when we call a function and the nothing with its result. So why should we not be allowed to (automatically) ignore a value coming out of an (optional) out-parameter?

Furthermore we can get conflict with other overloads of that method, but as state, we already have those conflicts when using optionals, so nothing new there.

In the end, it is up to the designers of C#. And they should answer those two questions: Is it possible and do we want this?

Martin Mulder
  • 12,642
  • 3
  • 25
  • 54
  • 1
    In this discussion, I think an explanation on the down-vote would be very useful, so down-voter, please do. – Wai Ha Lee May 06 '15 at 09:23
  • *Is it possible and do we want this?* No, the right question should be *is it possible and will it make the programmers able to do new interesting things (LINQ) **or** remove useless boilerplate code (see auto-properties, COM optional parameters, `??` and `?.` operators)* – xanatos May 06 '15 at 09:50
  • And if it adds something new / interesting... then... WE WANT IT. I was talking on an abstract level (technical vs functional), so are bringing it to a specific level. Your and mine arguments do not exclude each other... one is an example of the other. – Martin Mulder May 06 '15 at 09:59