Skip to content
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

Closed
GoEddie opened this issue Jan 28, 2015 · 52 comments
Closed

Allow multiple return values in C# #102

GoEddie opened this issue Jan 28, 2015 · 52 comments

Comments

@GoEddie
Copy link

GoEddie commented Jan 28, 2015

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 :)

@ErikSchierboom
Copy link

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);

@XuTpuK
Copy link

XuTpuK commented Jan 28, 2015

Multiple return values IS a great feature! Many languages have it and it's too strange C# has nothing.
But I don't want such feature implemented thru goddamn tuples-figuples! It's performance penalty - it should be done on low level, passing return values thru stack. Not sure .NET VM can support it....

@ashmind
Copy link
Contributor

ashmind commented Jan 28, 2015

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

public {bool success, string blah} Process(int number1, int number2) {
    return new { success = true, blah = "blah blah blah" };
}

(ignoring the performance question -- just imagine it is all structs).

@mikedn
Copy link

mikedn commented Jan 28, 2015

@XuTpuK

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 struct tuple type and then you get exactly what you want, values are returned via the stack or even in CPU registers. There's certainly no need for any kind of special support in VM for this.

@XuTpuK
Copy link

XuTpuK commented Jan 28, 2015

@mikedn
I speak about stack because I wanna AVOID tuples at all. Look at pseudocode:

{
....some instructions....
push a
push b
return
}

in caller:
call DivReminderFn
pop x
pop y

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??

@mikedn
Copy link

mikedn commented Jan 28, 2015

@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.

@XuTpuK
Copy link

XuTpuK commented Jan 28, 2015

<comment deleted>

@mikedn
Copy link

mikedn commented Jan 28, 2015

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.

@s-aida
Copy link

s-aida commented Jan 28, 2015

I think C#6.0 once considered making out parameter slightly look better.

// 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.

@XuTpuK
Copy link

XuTpuK commented Jan 28, 2015

<comment deleted>

@mwadams
Copy link

mwadams commented Jan 28, 2015

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:notifications@github.com
Sent: ‎28/‎01/‎2015 15:28
To: dotnet/roslynmailto:roslyn@noreply.github.com
Subject: Re: [roslyn] Allow multiple return values in C# (#102)

@mikedn
I was writing DOS resident programs when you was just a drop on father's panties! Not lamer like you can point me what CPU does. For fighting troll like you this is code you never write due to lack of any IT education: http://pastebin.com/bL52HeDF (FASM source) Look, shame and never appear again with your lamerish knowledge.


Reply to this email directly or view it on GitHub:
#102 (comment)

@mikedn
Copy link

mikedn commented Jan 28, 2015

@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.

@mburbea
Copy link

mburbea commented Jan 28, 2015

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(...);
}

@XuTpuK
Copy link

XuTpuK commented Jan 28, 2015

<comment deleted>

1 similar comment
@XuTpuK
Copy link

XuTpuK commented Jan 28, 2015

<comment deleted>

@ufcpp
Copy link
Contributor

ufcpp commented Jan 28, 2015

@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.

@XuTpuK
Copy link

XuTpuK commented Jan 28, 2015

<comment deleted>

@xanather
Copy link

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.

@mburbea
Copy link

mburbea commented Jan 28, 2015

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. var (found,res) = myDict.TryGetValue(2); The return type is inferred here.

Out/Ref parameters also don't work well with dynamic. Tuples do.

@XuTpuK
Copy link

XuTpuK commented Jan 28, 2015

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??

@s-aida
Copy link

s-aida commented Jan 29, 2015

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(); 

@XuTpuK
Copy link

XuTpuK commented Jan 29, 2015

@shunsukeaida You use rare example (at least from my practice). More frequently I need something like that:
(ClickedCol, ColIdx) = GetClickedColumn();

ColIdx is not the part of column, but needed during work. So what "normal" you found to put (ref ColIdx) into the parameters???

@monoman
Copy link

monoman commented Jan 29, 2015

👍 for @ErikSchierboom syntax

@HaloFour
Copy link

@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 struct tuple would be just as effective as pushing multiple individual values onto the stack. The compiler could generate those tuples automatically based on the return signature, e.g.:

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.

@EamonNerbonne
Copy link

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 :-).

@HaloFour
Copy link

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.

@mwadams
Copy link

mwadams commented Jan 29, 2015

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:notifications@github.com]
Sent: 29 January 2015 21:31
To: dotnet/roslyn
Cc: Matthew Adams
Subject: Re: [roslyn] Allow multiple return values in C# (#102)

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.


Reply to this email directly or view it on GitHub #102 (comment) . https://github.com/notifications/beacon/AAVMOnyvEE_8jdBrvOPSYERNm7uB6cZKks5nmp4ggaJpZM4DYO7z.gif

@mikedn
Copy link

mikedn commented Jan 29, 2015

@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.

@mwadams
Copy link

mwadams commented Jan 29, 2015

True – I was just pointing out that the named return values thing does not require any automatic type generation.

M

From: mikedn [mailto:notifications@github.com]
Sent: 29 January 2015 21:50
To: dotnet/roslyn
Cc: Matthew Adams
Subject: Re: [roslyn] Allow multiple return values in C# (#102)

@mwadams https://github.com/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.


Reply to this email directly or view it on GitHub #102 (comment) . https://github.com/notifications/beacon/AAVMOv3_wMGkmUAlw7URJYfHnTWVzvLoks5nmqKbgaJpZM4DYO7z.gif

@HaloFour
Copy link

@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.

@mwadams
Copy link

mwadams commented Jan 29, 2015

We wouldn’t have to use the existing ref types, of course.

M

From: HaloFour [mailto:notifications@github.com]
Sent: 29 January 2015 22:54
To: dotnet/roslyn
Cc: Matthew Adams
Subject: Re: [roslyn] Allow multiple return values in C# (#102)

@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.


Reply to this email directly or view it on GitHub #102 (comment) . https://github.com/notifications/beacon/AAVMOmE6b-LYmgVNrZ6nViQ9tsxzRH4kks5nmrFqgaJpZM4DYO7z.gif

@s-aida
Copy link

s-aida commented Jan 30, 2015

@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 ref/out which I dislike, it is about the only way to get multiple values from one function). Plus, I for one wouldn't let my API, which is supposed to return the clicked column, return something that isn't part of the column, to begin with.
I'd welcome multiple return values (or declaration expression), but the positional return values are not particularly exciting.

@XuTpuK
Copy link

XuTpuK commented Jan 30, 2015

<comment deleted>

@s-aida
Copy link

s-aida commented Jan 30, 2015

@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.

@XuTpuK
Copy link

XuTpuK commented Jan 30, 2015

<comment deleted>

@s-aida
Copy link

s-aida commented Jan 30, 2015

Here people above_the_average are discussing features

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.

@xanather
Copy link

@XuTpuK

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.

@XuTpuK
Copy link

XuTpuK commented Jan 31, 2015

<comment deleted>

@xanather
Copy link

Show me at least one document where MS says "We promise to implement & support C# on Linux" - seems you're just dreaming and unable to read properly MS' promo. MS DOES NOT support Linux, relax.

Have you not heard of .NET Core yet?
http://blogs.msdn.com/b/dotnet/archive/2014/12/04/introducing-net-core.aspx

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 still cannot return multiple values. Pattern matching(PM) just in plans - guys, hey, wake up! First PM was used in... SNOBOL, year 1962!! Xanather, if you had good IT erudition, you'll never protect C#.

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
Copy link

XuTpuK commented Jan 31, 2015

<comment deleted>

@HaloFour
Copy link

@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.

@XuTpuK
Copy link

XuTpuK commented Jan 31, 2015

<comment deleted>

@xanather
Copy link

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.

@ashmind
Copy link
Contributor

ashmind commented Jan 31, 2015

After reading this thread I feel Roslyn repo needs code-of-conduct + banhammer.
Some high quality trolling (or sincere /r/iamverysmart material).

@GoEddie
Copy link
Author

GoEddie commented Jan 31, 2015

Yes, I hope it doesn't detract in any way from the original request!

@jaredpar
Copy link
Member

jaredpar commented Mar 4, 2015

@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.

@jaredpar
Copy link
Member

jaredpar commented Mar 4, 2015

@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.

@GoEddie
Copy link
Author

GoEddie commented Mar 4, 2015

Thank you.


@XuTpuK
Copy link

XuTpuK commented Mar 5, 2015

<comment deleted>

@gafter
Copy link
Member

gafter commented Apr 23, 2015

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.

@jibal
Copy link

jibal commented Apr 28, 2015

" 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.

@MadsTorgersen
Copy link
Contributor

Per #3912 this will be addressed by Tuples (#347). Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests