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

Proposal: Trailing return type #8448

Closed
alrz opened this issue Feb 6, 2016 · 5 comments
Closed

Proposal: Trailing return type #8448

alrz opened this issue Feb 6, 2016 · 5 comments

Comments

@alrz
Copy link
Member

alrz commented Feb 6, 2016

From #7681:

I have the following snippet of code:

Body = Activities.Invoke<int>(i =>
{
    runCount++;
    throw new Exception("broke");
}),

There are 16 available overloads of Invoke<>. These are the two that are confused. Roslyn is selecting the first.

public static AsyncActionActivity<TArg1> Invoke<TArg1>(Func<TArg1, Task> func)
public static ActionActivity<TArg1> Invoke<TArg1>(Action<TArg1> action)

Clearly, the first requires that the delegate returns a Task. In my example, I am returning nothing. I am throwing an Exception. The code compiles, selecting the Func<int,Task> signature, but then fails at runtime.

if I make one change to my original calling code block, the compiler chooses the correct implementation:

Body = Activities.Invoke<int>(i =>
{
    runCount++;
    throw new Exception("broke");
    return;
}),

A useless return statement fixes it.

To not fall into that kind of situations, where compiler would infer the return type, and you'll need to trick it to understand what you meant, one should be able to explicitly declare lambda's return type to prevent accidental mess-up, e.g.

Body = Activities.Invoke<int>(i -> void =>
{
    runCount++;
    throw new Exception("broke");
}),

One other use case is that when the return type is rather complicated, like intersection types (#4586), tuples (#347), etc, which causes a "weird" method signature,

public (int sum, int count) Tally(IEnumerable<int> values)  { ... }

And honestly, tuple type syntax doesn't look well with C-like return types,

public Tally(IEnumerable<int> values) -> (int sum, int count) { ... }

This would also address the backward declaration of type parameters.

public auto F<TResult>() -> TResult { ... }

PS: I'm not proposing return type inference, so presence of auto or var or none is up for discussion.

@tpetrina
Copy link

tpetrina commented Feb 7, 2016

Or you can manually select the overload by writing:

Body = Activities.Invoke<int>(action: i =>
{
    runCount++;
    throw new Exception("broke");
}),

Which is sometimes the only possible solution to this problem.

@andrewjsaid
Copy link

Currently you can also explicitly cast the expression to Action or call the constructor.

// Call constructor
Body = Activities.Invoke(new Action<int>(i =>
{
    runCount++;
    throw new Exception("broke");
}))

// Explicit Cast
Body = Activities.Invoke((Action<int>)(i =>
{
    runCount++;
    throw new Exception("broke");
}))

@alrz
Copy link
Member Author

alrz commented Feb 10, 2016

This is already discussion-ed.

@andrewjsaid
Copy link

I am not sure of your point. I was just adding additional relevant information to the discussion and to present existing alternatives which may or may not highlight the need for the issue.

@alrz
Copy link
Member Author

alrz commented Mar 29, 2017

Closing as dup of #13744

@alrz alrz closed this as completed Mar 29, 2017
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

5 participants