Return/break/continue expressions have been discussed but are hard to implement correctly as they interfere with other constructs. At best, it's a convenience feature. As the design meeting notes say:
This is a convenience. However, it risks a syntactic conflict with other potential futures, especially "non-local returns" (allowing a lambda to return from its enclosing method) and "block expressions" (allowing statements inside expressions). While we can imagine syntaxes for those that do not conflict, we don't want to limit the design space for them at this point, at least not for a feature that is merely "nice to have".
Also, while we've been talking about this in analogy with throw expressions, that isn't quite right. throw is a dynamic effect, whereas return, break and continue are statically bound control transfers with a specific target.
As the discussion shows, it's hard to come up with a compelling example while there are many alternatives already.
In any case return expressions aren't similar to throw expressions. An exception is neither a control flow nor a return mechanism. It's a blown fuse that needs handling, otherwise the application can't continue.
Throw expressions aren't just convenience, they allow throwing exceptions in places where only an expression is valid. That's why they are used in functional languages like F#'s raise and failwith functions.
Without them pattern matching constructs like C#'s switch expressions or F#'s match expressions would be impossible to write and analyze at compile time.
Without throw expressions this:
public static RGBColor FromRainbow(Rainbow colorBand) =>
colorBand switch
{
Rainbow.Red => new RGBColor(0xFF, 0x00, 0x00),
Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
_ => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),
};
Would have to be rewritten to include a dummy return statement , making analysis of the code during compilation needlessly hard. The compiler would have to recognize this patter, ignore the return statement and use the throw statement to verify whether the code is valid or not :
public static RGBColor FromRainbow(Rainbow colorBand) =>
colorBand switch
{
Rainbow.Red => new RGBColor(0xFF, 0x00, 0x00),
Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
_ => {
throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand));
return default;
}
};
That return default would also play havoc with C# 8's nullable reference types and nullability analysis.
C# 8 took advantage of C# 7's throw expressions to offer switch expressions. C# 9 will take advantage of both to offer discriminated unions and (hopefully) exhaustive pattern matching.
returnexpression instead of areturnstatement. Just like thethrowstatement has been changed from C#6 to C#7 so that it can be used in places where the compiler normally expects an expression. They don't want to continue the method in case the first value is null, but instead of throwing only want to return. This is technically possible, but obviously nobody asked hard enough for it and no one wanted to implement, test, document and ship it.someValue??double.NaNis valid. What did you try, what failed? Are you sure the problem isn't the invalid return statement after???ifstatement and I would hardly call it boilerplate, any more than?? return... would be.