-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow multiple return values in C# #102
Comments
This feature would become reality if the proposal for destructuring of tuples would be implemented (see #98). Then you could do: public (bool, string) SomeMethod(int number1, int number2)
{
return (true, "blah blah blah");
}
var (result, someOtherValue) = SomeMethod(100, 100); |
Multiple return values IS a great feature! Many languages have it and it's too strange C# has nothing. |
I think this design wouldn't work well with IntelliSense -- you wouldn't know what return values mean without referencing the documentation. In some cases it might be obvious, but for primitives like int and string it is not often so. For a worst case scenario, see Perl's stat function. I much prefer
(ignoring the performance question -- just imagine it is all structs). |
Well, that depends on what kind of tuple such a feature would use. If the existing System.Tuple types are used then yes, the fact that they are reference types and require a heap allocation is a problem. But you could also use some sort of |
@mikedn { in caller: That's it! Using tuples, first you reserve space for structure YOU NEVER NEED, then fill it with return values, then pop this tuple from stack and ONLY THEN you assign tuple's members to the variables in the caller. Feel the difference?? |
@XuTpuK I feel that you don't know what you're talking about. The pseudocode you posted cannot be translated to any meaningful assembly code. The return instruction would end up poping b from the stack and use whatever value b has as return address. |
|
That's hilarious. If you would have any clue about x86 you would know that your pseudocode doesn't make sense. Nor is it actually useful as one way or another the tuple will end up in memory. |
I think C#6.0 once considered making // Multiple return values (with Tuples)
var (result, someOtherValue) = SomeMethod(100, 100); vs // Declaration expressions
var result = SomeMethod(100, 100, var out someOtherValue); Don't know why Declaration expressions is dropped from C#6.0, but in some cases these two features may overlap. |
|
I don't know if you've noticed, but you have an extra pop and push in that example to address exactly the issue Mike describes. At which point it all starts to look a bit moot. Sent from my Windows Phone From: XuTpuKmailto:[email protected] @mikedn Reply to this email directly or view it on GitHub: |
@XuTpuK I'd suggest you learn some manners if you want to have a conversation. No compiler generates that kind of code nor there's any valid reason for a compiler to do so. The only one who is trolling is you, nobody in this discussion cares about useless tricks from 30 years ago. |
I'm not sure why we're having a slap fight here okay we get it you know x86. That doesn't really matter. Because of the nature of how the CLR is implemented without a drastic change to the runtime the only way that makes sense is returning a type. I think a value type struct could be useful and potentially if and when the CLR learns escape analysis that could be "free". Another alternative could be how IronPython automatically translates out parameters into tuple members. Perhaps that could be how this feature is handled? On call site a tuple (that exposed fields I guess as you can't pass properties to out parameters) would be used. You could always call it with the out parameter explicitly if you are extremely cautious about memory usage. var myDict = new Dictionary<int,string>(){1,"a"};
string res;
// b is now true. Res is the value.
var b = myDict.TryGetValue(1,out res);
// t is now a FieldTuple<bool,string> of the values {false,null};
var t = myDict.TryGet(2); Clearly, there is some problems as this could cause overload resolution issues. There are also issues in that the CLR isn't always super efficient when it comes to methods with ref parameters. But mixed with a tuple destructuring feature this can be quite a nice bit of syntax without changing too much of the language. var (found,res) = myDict.TryGetValue(2);
if(!found){
res = CreateRes(...);
} |
|
1 similar comment
|
@XuTpuK Certainly, some language such as Perl allow multiple returns by passing maltiple values through stack. .NET IL, however, don't allow to do that. The ret instruction of the IL requires strictly one values on stack before the ret, and after the ret, the stack must be empty. |
|
What is so bad about using the "out" parameter? There is a reason why you have to explicitly type "out" on formal parameters and actual parameters, so others know it returns more values. |
Nothing but its a lot less friendly to use because of the required explicitness. Even fxcop recommends to avoid them in public apis. I have to always declare a variable first so I lose type reference. Out/Ref parameters also don't work well with dynamic. Tuples do. |
xanather> What is so bad about using the "out" parameter? Because it's "reversive" logic. When you need to GET values, why you should PUT variables into the function?? |
I quite often put a reference into a function to get values. var obj = new SomeStorageClass();
CallFunction(obj); Depended on the situation and personal references, but it may be better than the suggested features in that the caller doesn't need to care about the positions of return values. var obj = new SomeStorageClass();
(obj.foo, obj.bar, obj.buz, obj.qux, obj.quux, obj.corge) = CallFunction(); |
@shunsukeaida You use rare example (at least from my practice). More frequently I need something like that: ColIdx is not the part of column, but needed during work. So what "normal" you found to put (ref ColIdx) into the parameters??? |
👍 for @ErikSchierboom syntax |
@XuTpuK You get more flies with honey. The combative rhetoric isn't likely to win you much favor amongst even those who probably agree with you. A public (int, int) GetPoint() {
return (2, 3);
}
(int x, int y) = GetPoint();
Console.WriteLine($"x = {x}, y = {y}"); would be equivalent to: public struct GetPointTuple {
public readonly int ret1;
public readonly int ret2;
public GetPointTuple(int ret1, int ret2) {
this.ret1 = ret1;
this.ret2 = ret2;
}
}
public GetPointTuple GetPoint() {
return new GetPointTuple(2, 3);
}
int x, y;
GetPointTuple ret = GetPoint();
x = ret.ret1;
y = ret.ret2;
Console.WriteLine($"x = {x}, y = {y}"); In the end the stack would hold 64-bits worth of a return value. Of course the question is what strategies should the compiler follow when generating said structs, how the struct names are determined (if they would be part of the signature), whether this is something that should be permitted on accessible members or handled more like anonymous types within a single class. |
I'd love to see a multiple-return value feature, but anonymous, positional tuples are not the way to go. In medium-to-large codebases - exactly the kind of thing C# is good at - tuples are a maintenance burden because it's too easy to get the order of the values mixed up; and it doesn't scale well past two or three values. However, tuples with named members can be almost as terse, and much easier to work with. For example: public (int row, int col) GetPoint() {
return { row: 2, col: 3 };
}
var p = GetPoint();
var {row, col} = p;
var {x=col, y=row} = p;
var dimension0 = p.col;
Console.WriteLine($"row = {row}, x = {x}"); Note that the order is the reverse of @HaloFour's example. It's conventional to use the x,y ordering, but also the row,col ordering - depending on how the variables are named... Without named members, I'm absolutely certain that on the kind of codebases I work on, tuples would be worse than nothing. Saving a few keystrokes is nice, but it's just not worth a bug or misunderstood code. Tuples are great - but with member names :-). |
I agree. Apple Swift allows both forms, but tuples are also a first-class citizen in Swift whereas they're not really in C#. func GetPoint() : (Int32, Int32) {
return (2, 3)
}
func GetPointNamed() : (row : Int32, col : Int32) {
return (col: 3, row: 2)
}
var point = GetPoint()
var row = point.0
var col = point.1
(row, col) = point
var point2 = GetPointNamed()
(col, row) = (point2.col, point.row) In either case the method through which the names of the type or the members would have to be well defined and it may be argued that these return values shouldn't be exposed outside of the assembly due to the compiler-generated nature of those types. |
Couldn’t this be done with some compiler magic that just aliases those names to Item1, Item2 etc in a regular n-Tuple, without generating any new types at all? You could attribute the method to indicate the aliasing for the benefit of external consumers whose language supports this aliasing, while regular consumers would see them as regular n-Tuples. From: HaloFour [mailto:[email protected]] I agree. Apple Swift allows both forms, but tuples are also a first-class citizen in Swift whereas they're not really in C#. func GetPoint() : (Int32, Int32) { func GetPointNamed() : (row : Int32, col : Int32) { var point = GetPoint() In either case the method through which the names of the type or the members would have to be well defined and it may be argued that these return values shouldn't be exposed outside of the assembly due to the compiler-generated nature of those types. — |
@mwadams The C# compiler could simply transform (int, int) GetPoint() {
return (2, 3)
} into void GetPoint(out int i1, out int i2) {
i1 = 2;
i2 = 3;
} It's all a matter of convention and syntax after all. Though returning a struct could be a tiny bit faster. |
True – I was just pointing out that the named return values thing does not require any automatic type generation. M From: mikedn [mailto:[email protected]] @mwadams https://github.com/mwadams The C# compiler could simply transform (int, int) GetPoint() { into void GetPoint(out int i1, out int i2) { It's all a matter of convention and syntax after all. Though returning a struct could be a tiny bit faster. — |
@mwadams You could. That would require an additional allocation since |
We wouldn’t have to use the existing ref types, of course. M From: HaloFour [mailto:[email protected]] @mwadams https://github.com/mwadams You could. That would require an additional allocation since Tuple<> and it's related types are reference types. A generated struct buys you better performance and potentially the capacity to officially name the members. — |
@XuTpuK Have you rarely passed an object to a function which manipulates it? If so, perhaps we have different coding conventions (and indeed, aside of |
|
@XuTpuK Chill out. It's not the first time you get defensive for nothing. Plus, not expect everything posted in the public discussion will cater for you, regardless of who was the thread author, especially when you're a bit fussy (no for out/ref, no for passing a reference of a storage object, yadda yadda yadda). We don't have the feature in question yet, and that's why people're taking about their own current alternatives or preferred implementations. |
|
That's not always the case because you're right here. Plus, C# has far more rapidly progressed than, say, likes of Java,and while even more features are very welcome, I like how carefully MS avoids a mess like C++ or Scala. I can hardly blame them for being lazy or making many wrong decisions. Anyway, I understand this thread is a palace of you, not a place for a constructive discussion. |
C# delayed in progress? What delay are you talking about? If anything many .NET related projects will evolve even quicker now (the release of CoreCLR (including the jitter/GC), Roslyn and .NET Corefx). C# is getting a new 64-bit jitter RyuJIT, official support for Linux and Mac from Microsoft, and also now has a very powerful compiler written in the language itself. Now I don't want to get into a language war because it's one of the worse discussions to have, especially on a place like Github. Many of your posts however seem to be pessimistic about C# in several aspects and it sounds like its your duty to voice that here. Yes there are many other languages which have better features/design ideas than C# in some aspects, but C# can also beat said languages just as much depending on the context of what we are talking about. A good programmer realizes that there really isn't a perfect language and usage of one depends on what the target scope. Saying ".NET is just suxx." is childish. It really does not contribute to the discussion. Now personally I would consider supporting the return of multiple values in a method not THAT important, you can basically already do it - the only downside would be needing to develop explicit types needed to work with the values returned within the said method. There are also other ways to returning multiple values as discussed in this thread before. |
|
Have you not heard of .NET Core yet? You can see the pull requests of the libraries that are being added to .NET Core (they are supporting Unix) - most of them added by Microsoft. https://github.com/dotnet/corefx
I wasn't really protecting C# I was merely stating that I wouldn't consider having the ability to return multiple values with a method not that important (it can already be done, any other implementation right now would mostly be syntax sugar). There are many other things I would prefer to see over the ability to return multiple values from methods, I am glad quite a few of them are coming in C# 6.0. |
|
@XuTpuK Dude, seriously, how frequently must it be requested that you not act like an immature brat with an axe to grind? Nobody is going to take you seriously if all you do is have temper tantrums on these forums. Take it back to 4chan or reddit or Slashdot or whatever teenaged angsty enclave from which you came. I don't know why I feed the troll, but ASP.NET has been open-source for years yet Microsoft supports it. Entity Framework has been open-source for years yet Microsoft supports it. In both cases Microsoft has intentionally made modifications to those projects in order to improve their function on Linux. RyuJIT is the runtime that Microsoft is going to be using on Windows. .NET Core is the basis of the runtime that Microsoft is going to be using on Windows. Of course they're going to support them. |
|
I can help but laugh at this, @XuTpuK aside from having a hatred for Microsoft, if they were to try and make the full .NET Framework to be cross platform how well do you think that would work out? .NET Framework is deeply intertwined with Windows. .NET Core has less dependencies on other assemblies while many .NET Framework assemblies reference code which only works on Windows. People can develop 3rd party GUI framework's once it releases for it. There's no urge for Microsoft to make and manage something like Java's abysmal Swing. |
After reading this thread I feel Roslyn repo needs code-of-conduct + banhammer. |
Yes, I hope it doesn't detract in any way from the original request! |
@XuTpuK your comments were deleted due to their rude / offensive nature. Please keep the discussion on this topic professional. If you continue to post comments of this nature we will have to consider more serious actions like banning. |
@ashmind @GoEddie @xanather @HaloFour @ErikSchierboom @shunsukeaida sorry. I don't know how this particular thread flew under our radar for so long. If you see behavior like this in the future that we aren't addressing please feel free to email me and I will handle it. |
Thank you. |
|
I would like to point out that this request is not explicitly on the list of features we are considering for C# 7 because it is solved by the "tuples" feature already high on our list of priorities. |
" Pattern matching(PM) just in plans - guys, hey, wake up! First PM was used in... SNOBOL, year 1962!! " SNOBOL's pattern matching was parsing ... not at all related to the sort of pattern matching of functional languages (deconstruction) that is being proposed for C#. And SNOBOL was preceded by the pattern matching language Comit, designed in 1957. |
Hi,
In a newer version of c#, can you consider this as a new feature?
Returning multiple values from a function is really useful and would avoid either returning a class / struct or using out parameters.
The syntax could be something like:
var result = false;
var someOtherValue = "";
result, someOtherValue = SomeMethod(100, 100);
to return multiple values do something like:
public bool, string SomeMethod(int number1, int number2) {
return true, "blah blah blah";
}
which seems a lot nicer than:
public bool SomeMethod(int number1, int number2, out string returnValue) {
returnValue = "blah blah blah";
return true;
}
There are a few uservoices for this:
https://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2083753-return-multiple-values-from-functions-effortlessly
https://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/6072768-allow-methods-to-have-multiple-return-values
https://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/6348329-returning-multiple-values
UPDATE: This is covered by #347 which is listed as having "Strong Interest" on the C# 7 work list :)
The text was updated successfully, but these errors were encountered: