views:

632

answers:

9

Let us say for a moment that C# allowed multiple return values in the most pure sense, where we would expect to see something like:

string sender = message.GetSender();
string receiver = message.GetReceiver();

compacted to:

string sender, receiver = message.GetParticipants();

In that case, I do not have to understand the return values of the method until I actually make the method call. Perhaps I rely on Intellisense to tell me what return value(s) I'm dealing with, or perhaps I'm searching for a method that returns what I want from a class I am unfamiliar with.

Similarly, we have something like this, currently, in C#:

string receiver;
string sender = message.GetParticipants(out receiver);

where the argument to GetParticipants is an out string parameter. However, this is a bit different than the above because it means I have to preempt with, or at least go back and write, code that creates a variable to hold the result of the out parameter. This is a little counterintuitive.

My question is, is there any syntactic sugar in current C#, that allows a developer to make this declaration in the same line as the method call? I think it would make development a (tiny) bit more fluid, and also make the code more readable if I were doing something like:

string sender = message.GetParicipants(out string receiver);

to show that receiver was being declared and assigned on the spot.

A: 

At best you would have to use var rather than an explicit type, unless you want to restrict all multiple return values to be of the same type (not likely practical). You would also be limiting the scope of the variable; currently you can declare a variable at a higher scope and initialize it in an out parameter. With this approach, the variable would go out of scope in the same block as its assignment. Obviously this is usable in some cases, but I wouldn't want to enforce this as the general rule. Obviously you could leave the 'out' option in place, but chances are people are going to code for one approach or the other.

Adam Robinson
Having to use var is not true, the syntactic sugar, if it did exist, should simply declare a new variable in the same scope as you mentioned, and pass it into the method for assignment. Thus, each parameter would be typed naturally.
JoshJordan
string param1, int param2 = FuncCall(param3)?
Adam Robinson
The post was asking about syntactic sugar of the form: string returned = FuncCall(out int param2, out string param3). However, what you have posted would be a viable form, yes.
JoshJordan
+7  A: 

No, there isn't currently any syntactic sugar around this. I haven't heard of any intention to introduce any either.

I can't say I use out parameters often enough for it really to be a significant concern for me (there are other features I'd rather the C# team spent their time on) but I agree it's a bit annoying.

Jon Skeet
How is the current implementation a double standard...?
Adam Robinson
Because they're not return values, they're out parameters. There's no "double standard" - they're different things, treated differently. It's not like you represent the return value as an initial out parameter or anything like that - at *that* point it would be fair to call it a double standard.
Jon Skeet
Note that out parameters *aren't* the same as return values anyway. You can assign the value of an out parameter during the method, and that change occurs immediately. You can see this if you call a method and use an instance variable for the out argument.
Jon Skeet
A: 

Participants p = message.GetParticipants(); log(p.sender,p.receiver);

Dustin Getz
A: 

I think this is not what you want. You may have come across a piece of code where you would have liked that. But variables popping out of nowhere because they have been introduced in the parameter list would be a personal nightmare ( to me :) )

Multiple return values have grave downsides from the point of portability/maintainability. If you make a function that returns two strings and you now want it to return three, you will have to change all the code that uses this function. A returned record type however usually plays nice in such common scenarios.

you may be opening pandora's box ;-)

For line compacting:

string s1, s2; s1 = foo.bar(s2);

Lines can be any length, so you could pack some common stuff into one. Just try to live with the semicolons.

AndreasT
Please don't compact it ...
Jabe
Well, there are many, many constructs that have harsh implications for maintainability already, and the developers need to learn to work with them. In this case, it would more likely than not be appropriate to introduce another method of the same name but with a different return signature.
JoshJordan
The point is that variables "coming out of nowhere" is what we have for a single return value, if we choose to do a declaration and an assignment. The lack of a facility to do this for multiple return values (or out params) gives us a double standard.
JoshJordan
@Jabe: Yeah, I don't want to. But I am happy to be able to :) @Josh: I can see nothing "double standard"ly here. Return values and out parameters are, by definition, something completely different. You should mix/use out parameters only where it's logical/necessary.
AndreasT
+3  A: 

.NET 4 will be adding a Tuple concept, which deals with this. Unfortunately, the C# language isn't going to provide any language support for "destructuring bind".

wekempf
It's called "destructuring bind".
Anton Tykhyy
+2  A: 

You can also return a Tuple<T,U> or something similar. However, since you want to return two string, it might get confusing.

I use the Tuples structs of the BclExtras library which is very handy (found it on SO, thank you JaredPar!).

Jabe
+3  A: 

Personally, I like the inconvience introduced when using out parameters. It helps me to think about whether my method is really doing what it should be or if I've crammed too much functionality into it. That said, perhaps dynamic typing in C#4.0/.Net 4 will address some of your concerns.

dynamic participant = message.GetParticipants();

var sender = participant.Sender;
var recipient = participant.Recipient;

where

public object GetParticipants()
{
     return new { Sender = ..., Recipient = ... };
}
tvanfosson
Yuck, this looks sooo ugly!
m0rb
+2  A: 

I don't think such functionality exists, but if it were implemented in a way similar to arrays in perl that could be useful actually.

In perl You can assign an array to a list of variables in parentheses. So you can for example do this

($user, $password) = split(/:/,$data);
Michał Piaskowski
+2  A: 

Where this bugs me the most: since there's no overload of (say) DateTime.TryParse that doesn't take an out parameter, you can't write

if (DateTime.TryParse(s, out d))
{
   return new ValidationError("{0} isn't a valid date", s);
}

without declaring d. I don't know if this is a problem with out parameters or just with how the TryParse method is implemented, but it's annoying.

Robert Rossney