Return vs. Finally (2)
The Return statement and finally have competition. Both can are the "last" thing to execute when a function exits, so which of them is really last? I blogged about this before regarding C#'s semantics setting data. Now I'll compare some interesting differences between C# and Python.
Who wins if you set them up in direct competition like this (non-exceptional path):
void f1()
{
try
{
return 10;
}
finally
{
return 5;
}
}
or this (the exceptional path):
void f2()
{
try
{
throw new Exception();
}
finally
{
return 5;
}
}
There are multiple intelligent ways a language design could answer this.
C#'s answer: Illegal
In C#, this is just illegal. Returns are forbidden in finally clauses. This nicely just avoids the whole problem by refusing to let you write such potentially ambiguous and confusing code. (CS0157: "Control cannot leave the body of a finally clause"). And if a consensus emerges down the road that there really is a clear "right" answer, C# can always make it legal with the "right" semantics.
IL's answer: Illegal
The underlying CLR's IL instruction provides try/catch/finally and branching opcodes. The only branching opcode out of a finally is 'endfinally', which jumps to the end of the finally block. You can't return / branch out of a finally. (See VER_E_RET_FROM_HND=0x80131845 in CorError.h).
Since .NET languages compile to IL, it may be natural for a language to have the same semantics as the IL instructions it compiles to. It's not surprising that C# has the same restrictions as the underlying IL instruction set here. However, a .NET language can have more clever opcode usage to provide their own semantics.
Python's answer: Legal
In Python, return inside of finally is actually allowed.
|
In this case, you can see that even on the exceptional path, the return statement will swallow the exception and return a value.
Note that IronPython compiles to IL, and still faithfully maintains the python exception semantics here.