-
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
Proposal: Expression Alternative for Statements #5402
Comments
This seems more like a concept than a proposal, as there are more questions than answers in the suggestion. |
I find this proposal strange because you mention immutability as a motivation but several of your examples explicitly involve mutable state. // foreach, conditional — basically list.Where(...).Select(...);
var result = foreach(var item in list) => if(item.Condition) => new Foo(item); Why would you want this at all? Why not just write var result = from item in list where item.Condition select new Foo(item); which is more readable, more concise, and already exists. And then you have both this: IEnumerable<int> result = for(var i = 1; i <= 10; ++i) => i; and this: // block body
var result = for(var i = 1; i <= 10; ++i) => {
var item = i.ToString();
yield return item;
}; What does this mean? It suggests that if there are braces after the |
@aluanhaddad As I said, loop expressions can be easily written in terms of LINQ methods/expressions. But for
Which is nice, because you don't need to define a method wherever you just want a value and have to use a |
I think you are conflating |
@gafter @aluanhaddad I just figured out my mistake about loop expressions: they cannot return values unless they are used in iterators. So there would be no implicitly defined and implicitly invoked anonymous function. Please review the new specification. |
What is expression-or-block? If it supports a block, what is it's value and type? |
@gafter It follows anonymous-function-body rules. so if it supposed to return a value, one may use Action f = () => try => this.VoidMethod() catch => this.VoidMethod();
Action f = () => try => { this.VoidMethod(); } catch => { this.VoidMethod(); };
Func<int> g = () => try => this.IntMethod() catch => this.IntMethod();
Func<int> g = () => try => { return this.IntMethod(); } catch => { return this.IntMethod(); }; The lambda expression body remains in the expression context in all cases. However, |
@alrz I see, but I think it would make more sense, in the context of this proposal, to allow loops to return values but to disallow iterators in loop expression block bodies. What I was pointing out that the return type didn't make sense. It would have been something like That said, I do not think any of this is a good idea. Initially I found the exception handling capabilities of this proposal to be compelling, but after seeing these examples Action f = () => try => this.VoidMethod() catch => this.VoidMethod();
Func<int> g = () => try => this.IntMethod() catch => this.IntMethod(); I think it could well encourage overgeneralized exception handling for the sake of brevity. |
You think checked exceptions in Java (as the opposite case) encourage developers to really catch the exceptions or explicitly bubble them up with I think this totally depends on developers, if that is not the case, a general
I didn't quite get that, can you give an example? |
@alrz It is not about checked vs unchecked exception, it is about having catch clauses that catch everything. I'm not saying
You originally posted this example: IEnumerable<int> result = for(var i = 1; i <= 10; ++i) => i; and this example: IEnumerable<string> result = for(var i = 1; i <= 10; ++i) => {
var item = i.ToString();
yield return item;
}; But for the proposal to make any sense, one of them must be wrong. |
That would not make sense. Because |
Part of your original proposal was also block expressions. The second example suggested that you could use an iterator body as a block expression body meaning that the body which as you say would be evaluated several times, would evaluate to a new iterator for each iteration of the loop. So the second example would have been a loop which produced multiple iterators hence the type of the loop as an expression. |
@aluanhaddad now I see what you're talking about. with |
@gafter As @GSPP pointed out, it makes sense to have I updated the original post, however, I wasn't sure about precedence of these expressions so I just omitted augmented existing rules for now. |
Do you have semantic rules in mind for this? e.g. what is the type of an if-expression or an iterator expression? Which statements are allowed in a block-expression, and which are not? What are the semantics of statements embedded in a block-expression? What are the precedence rules? It appears that this would make the language terribly ambiguous, for example if (e) { M(); } // expression or statement?
.ToString(); // Oh, it was an expression. Is .ToString applied to the whole if expression or the block? |
It wasn't, with previous syntax with the
if-expression would be Array.ForEach(array, item => if(item % 2 == 0) => Console.WriteLine(item))
statement-list implies that any statement would be allowed in a block-expression because, the point is to allow non-expression statements or ones that haven't an expression alternative to be used there. I don't think that it would be a good idea to have an expression form for like any statement that exist in the language (or is it?).
As I said, I wasn't sure about precedences, you made
First, if-expression doesn't return any value, so you can't do that. The following
is very similar to an object initializer. since |
I don't get it. How is an if-expression any more convenient than an if-statement? So we would be allowed to break and continue from an enclosing loop, and return from the enclosing method in a block-expression? |
@gafter the purpose is to keep the procedure in the expression context. that's all. |
@alrz There are other ways to "return from an expression" - for example, |
I don't understand. you mean from outside of the block (expression block?)? Is that possible while label is not in the scope? about expression lambdas, well, there are two options left;
btw, there is an "expression block" in Scala and it works. What I'm missing here? This is kind of problems that you were trying to solve by choosing parens for |
What I meant is that you can "return early" from inside a block by using a Indeed, there is an expression-block in Scala and it does not hijack the meaning of We already toyed with block-expressions in C# 6 and the syntax we came up with was |
that wouldn't be possible because goto-statement is not part of expression-statement.
this is just great, and it's consistent with parenthesised-expression. I love to see this in the next version along with |
@gafter block-expression aside, I replaced |
@alrz Re
It could be extended by relaxing the set of statement forms allowed within it. On the other hand, if you co-opt the meaning of |
@gafter since the syntax you have mentioned was well designed enough I removed expression-block from the suggestion. So there would be no |
You introduced conjunctive-pattern and disjunctive-pattern, but those productions aren't used anywhere. If you intend them to be examples of pattern, then your grammar is ambiguous. |
@gafter I just wanted to show how would multiple-case |
Is this a conjunction of a disjunction or vice versa? Your grammar is ambiguous. |
@gafter Yes, I just figured out. Fixed. |
@alrz I still don't see conjunctive-pattern or disjunctive-pattern used in (the right-hand-side of) any syntactic productions, so I don't see how they can be used in a program, or what their precedence would be. |
@gafter They are defined under pattern so they would be used in |
Instead of using static Action Foo;
static Func<int, int> Bar;
static void Main(string[] args)
{
Foo = () => Console.WriteLine("Foo Lambda");
Foo();
Foo = delegate { Console.WriteLine("Foo Delegate"); };
Foo();
// next one is the (by me declined) proposal:
Foo = delegate => Console.WriteLine("Why would this statement really help?");
Foo();
Bar = (x) => x;
Console.WriteLine("Bar Lambda: " + Bar(5).ToString());
Bar = delegate(int x) { return x; };
Console.WriteLine("Bar Delegate: " + Bar(5).ToString());
Console.ReadLine();
} |
Closing in favor of dedicated issues for each subject discussed in this thread. |
@gafter Is there an issue or design discussion tracking the "block expressions" you mentioned earlier? My primary use case is the ability to wrap void returning expressions into a larger |
Following the proposals #254, #3718, #5154, #5143 and others, it would be a good idea to have an expression alternative for other constructs as well.
Syntax
Note: It is not proposed that these be added to the set of syntax forms allowed as an expression-statement.
Note that if-expression cannot return and
else
expression seems redundant because of the existing ternary operator.try-expression returns a
null
in case of an exception, so you can use null-coalescing operator.Note that iterator-expression cannot return values unless it's used in expression-bodied iterators.
Additional syntaxes to be used with statement expressions including:
Some of the general expressions mentioned above should be narrowed to prevent polluted code.
The text was updated successfully, but these errors were encountered: