Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Now that you know why we disallow yielding in a finally, it’s pretty straightforward to see why we also disallow yielding in a catch.
First off, we still have the problem that it is illegal to “goto” into the middle of the handler of a try-protected region. The only way to enter a catch block is via the “non-local goto” that is catching an exception. So once you yielded out of the catch block, the next time MoveNext was called, we’d have no way to get back into the catch block where we left off.
Second, the exception that was thrown and caught is an intrinsic part of the execution of the catch block because it can be re-thrown using the “empty throw” syntax. We have no way of preserving that state across calls to MoveNext.
I suppose that we could in theory allow yields inside catch blocks that do not have an “empty throw”. We could turn this:
try
{
M();
}
catch(Exception x)
{
yield return x.ToString().Length;
yield return 123;
}
into
switch(this.state)
{
case 0: goto LABEL0;
case 1: goto LABEL1;
case 2: goto LABEL2;
}
LABEL0:
try
{
M();
this.state = 2;
goto LABEL2;
}
catch(Exception x)
{
this.x = x;
}
this.current = this.x.ToString().Length;
this.state = 1;
return true;
LABEL1:
this.current = 123;
this.state = 2;
return true;
LABEL2:
return false;
But frankly, that would be pretty weird. It would feel like a very odd restriction to disallow a fundamental part of the “catch” syntax.
And really, what’s the usage case that motivates this situation in the first place? Do people really want to try something and then yield a bunch of results if it fails? I suppose you could do something like:
IEnumerable<string> GetFooStrings(Foo foo)
{
try
{
yield return Foo.Bar();
}
catch(InvalidFooException x)
{
yield return "";
}
… etc.
but there are lots of ways to easily rewrite this so that you don’t have to yield in a catch:
IEnumerable<string> GetFooStrings(Foo foo)
{
string result;
try
{
result = Foo.Bar();
}
catch(InvalidFooException x)
{
result = "";
}
yield return result;
… etc.
Since there are usually easy workarounds, and we would have to put crazy-seeming restrictions on the use of re-throws, it’s easier to simply say “no yields inside a catch”.
We still haven’t explained why it is illegal to yield inside a try that has a catch, nor why it is legal to yield inside a try that has a finally. To understand why, next time I’ll need to muse about the duality between sequences and events.
Anonymous
July 21, 2009
Reading the "Generators" section of the DLR spec makes me think you are not happy with the current situation for .Net 4.0Anonymous
July 21, 2009
Producing a good compiler error message for this case would greatly help. The C# compiler produces decent error/warning messages but could use an update. A VS10 feature to seend feedback on error/warning message via VS IDE would be a nice way for the VS team to produce much better compiler diagnostics.Anonymous
July 22, 2009
The comment has been removedAnonymous
July 23, 2009
The comment has been removedAnonymous
July 23, 2009
@Michael, I see most of the points in your post, and agree with a fair number of them. Especially having a good set of interfaces for dealing with Office applications. Because I develop a fair amount of applications in this space, I have invested the time (signnificant time) to isolate "application" code from the details of the COM interfaces and it has definately paid off. However, one part I fail to dsee is "They can't return the var type. Are you saying nobody wants to return a var?" "var" is a syntactic shortcut for a strong type where the compiler can determin the actual type from the context. In all cases, you can replace "var" with a single specific type [and there are plenty of tools that do just this]. IF one could pass or return something declared as "var" then it would REQUIRE implicit "leaking" of implementation back out through the signature. Not only would this be difficult to achieve, I dont see where it would provide any value. The value is that you could use "extract method" on a query expression to make a helper method that returns a sequence of anonymous type. You cannot do that today because there is no way to represent the anonymous type in the return value of a method. You're forced to refactor the query to produce a nominal type first, and then extract the helper method. The down side is that doing so can impose the burden of whole-program analysis on the compiler. The language has been cleverly designed so that you can analyze all the method bodies in parallel if you choose to; var on returns would prevent that. -- EricAnonymous
July 23, 2009
The comment has been removedAnonymous
July 23, 2009
"The computer will always understand the code, but not humans" I prefer maintainable simple code, that can be easily documented and read, rather than syntax that dissolves and disappears with languages, because the percentage of its use is very low. Why enter into such complexity, while what are of higher priority are the algorithm and its efficiency and code maintenance? Regards RabeehAnonymous
July 24, 2009
@Rüdiger Klaehn - You raise some interesting points. But I have to take exception with: "But I really dislike the special SQL like syntax extension" This is the "N"atural portion of the functionallity. The ability to NOT use methid/propert like system. With out this being "I"ntegrated into the "L"anguage, it would not be LINQ, it would be just another library. This means that your really dont like LINQ, but would rather mainain a more conventional systax, which you are certainly free to do by directly invoking the class propert/methods that back LINQ....Anonymous
July 24, 2009
Re: TheCPUWizard Well, then I guess I don't like LINQ. I think a language should either provide the tools for users of the language to define their own DSL (domain specific languages)/syntax candy in libraries like scala does, or not do DSLs at all. I don't like being treated like a second class citizen by a language :-) LINQ is not domain-specific. Sorting, searching, projecting, grouping and joining are abstractions which are generally useful in almost any conceivable domain, not narrowly tailored to a specific domain. -- EricAnonymous
July 24, 2009
The comment has been removedAnonymous
July 24, 2009
The comment has been removedAnonymous
July 24, 2009
The comment has been removedAnonymous
July 26, 2009
The comment has been removedAnonymous
July 28, 2009
I just want to say I really appreciate the comment discussions. I feel enlightened.