Archived

This topic is now archived and is closed to further replies.

yaroslavd

Problem with finally clause in C#

Recommended Posts

yaroslavd    150
Hi, guys. In one of my methods, I compare two things. If they are NOT equal, I want to throw an exception. Then, regardless of if they are equal, I want to return a value. Naturally, I tried using a finally clause because that's what it's for.
try {
  if(n1!=n2)
    throw AnException(args);
}
finally {
  return obj;
}
I know you can do that in Java, but my C# compiler doesn't like this. It gives me this error: C:\Documents and Settings\Yaroslav\My Documents\Visual Studio Projects\TestApp\Recorder.cs(117): Control cannot leave the body of a finally clause Any ideas? Thanks in advance. [edited by - yaroslavd on March 28, 2004 3:20:18 PM]

Share this post


Link to post
Share on other sites
CWIZO    118
try
{
if(n1!=n2)
throw AnException(args);
}
finnaly
{
return somtin;
}


I think this shoudl wokr, but I am not shure

.:3delavnica.com:. Slovenian digital colture
Another day, another bug

Share this post


Link to post
Share on other sites
sjelkjd    171
quote:
Original post by yaroslavd If they are NOT equal, I want to throw an exception. Then, regardless of if they are equal, I want to return a value.

The exception is going to exit the function, not the return. You can exit a function via a return or an exception, but not both. That''s why you can''t return from a finally.

What exactly are you trying to do? It smells a little fishy

Share this post


Link to post
Share on other sites
yaroslavd    150
Basically, the method reads in an object. You pass an object into it. All the fields that were serialized in the serialized object are read into the passed object. However, if the versions of the said objects differ, some of the passed object''s fields will remain unassigned. I wanna throw an exception telling the user which fields were left unassigned. However, I still wanna return the deserialized object (with default values for unassigned fields).

Share this post


Link to post
Share on other sites
Oluseyi    2103
quote:
Original post by yaroslavd
I wanna throw an exception telling the user which fields were left unassigned. However, I still wanna return the deserialized object (with default values for unassigned fields).
And that makes sense to you, that you''d throw and exception and return a value? What use is the value when an exception has been thrown (unless you''re misusing exceptions)?

The finally clause is for cleanup that should be executed regardless of exit path.

Share this post


Link to post
Share on other sites
yaroslavd    150
quote:
Original post by Oluseyi
quote:
Original post by yaroslavd
I wanna throw an exception telling the user which fields were left unassigned. However, I still wanna return the deserialized object (with default values for unassigned fields).
And that makes sense to you, that you'd throw and exception and return a value? What use is the value when an exception has been thrown (unless you're misusing exceptions)?

The finally clause is for cleanup that should be executed regardless of exit path.


Why wouldn't it make sense? Java does it. For example,


try{
object o = AMethod(2);
}
catch(SomeException e)
{
}


In this scenario, o would still get assigned the value returned from AMethod(), yet an exception will be thrown to signal that some error has occured. However, this isn't supported in C#, I guess.

Any way to get around this? I thought of putting the object in my exception. That way, the user can get the partially-loaded object through the exception instance. Good idea?

[edited by - yaroslavd on March 28, 2004 3:54:19 PM]

[edited by - yaroslavd on March 28, 2004 3:56:44 PM]

[edited by - yaroslavd on March 28, 2004 3:58:51 PM]

Share this post


Link to post
Share on other sites
TangentZ    450
You''re grossly mis-using exceptions, when a simple if-then-else
will do the job.

From your description, it is not an exception when two
objects are not equal. Rather, it''s just a control branching
condition.


object obj;

if (n1 != n2)
{
obj = new MyObject(); // Assign a properly constructed object

}
else
{
obj = MyObject.DefaultObject; // Assign a default object

}
// end if


return obj;





Kami no Itte ga ore ni zettai naru!

Share this post


Link to post
Share on other sites
yaroslavd    150
quote:
Original post by tangentz
You''re grossly mis-using exceptions, when a simple if-then-else
will do the job.

From your description, it is not an exception when two
objects are not equal. Rather, it''s just a control branching
condition.


object obj;

if (n1 != n2)
{
obj = new MyObject(); // Assign a properly constructed object

}
else
{
obj = MyObject.DefaultObject; // Assign a default object

}
// end if


return obj;





Kami no Itte ga ore ni zettai naru!


I don''t think so. It would be exceptional for the versions to be different. I know I didn''t give you enough information in my post, so you wouldn''t know this. However, it''s too complex to briefly describe.

Like I said, I think I''ll pass the object into the exception class, and that''s how the user will be able to access it.

Share this post


Link to post
Share on other sites
sjelkjd    171
quote:
Original post by yaroslavd
Why wouldn''t it make sense? Java does it. For example,


try{
object o = AMethod(2);
}
catch(SomeException e)
{
}


In this scenario, o would still get assigned the value returned from AMethod(), yet an exception will be thrown to signal that some error has occured.

No, it wouldn''t. An exception stops the normal flow of execution. If AMethod threw, o would not be assigned to, and control flow would pass immediately to the catch.

Share this post


Link to post
Share on other sites
Alias2    122
The reason the C# compiler gives that error message is because the finally clause does not stop the exception, so you cannot change the control flow of the program since you still have an active exception which will continue to unwind the stack until it is caught.

I believe what you want is the ''catch'' statement, instead of the finally clause:


try {
// ...

if (n1 != n2)
throw new SomeException(args);

// ...
} catch (SomeException e) {
// do whatever cleanup you want to do in the error case here
return obj;
}


That will catch the exception (so it will not get bubbled back to the calling method), and return control flow to your program. The finally clause you were trying to use is similar, but is used to allow you to run code when an exception is thrown, but not stop the exception from being thrown (thus, somewhere / someone else higher up the stack will have to catch the exception).

Share this post


Link to post
Share on other sites
yaroslavd    150
quote:
Original post by sjelkjd
quote:
Original post by yaroslavd
Why wouldn''t it make sense? Java does it. For example,


try{
object o = AMethod(2);
}
catch(SomeException e)
{
}


In this scenario, o would still get assigned the value returned from AMethod(), yet an exception will be thrown to signal that some error has occured.

No, it wouldn''t. An exception stops the normal flow of execution. If AMethod threw, o would not be assigned to, and control flow would pass immediately to the catch.



In Java, it would because before the exception is thrown, finally{} would get executed before it''s thrown.

Share this post


Link to post
Share on other sites
yaroslavd    150
quote:
Original post by Alias2
The reason the C# compiler gives that error message is because the finally clause does not stop the exception, so you cannot change the control flow of the program since you still have an active exception which will continue to unwind the stack until it is caught.

I believe what you want is the ''catch'' statement, instead of the finally clause:


try {
// ...

if (n1 != n2)
throw new SomeException(args);

// ...
} catch (SomeException e) {
// do whatever cleanup you want to do in the error case here
return obj;
}


That will catch the exception (so it will not get bubbled back to the calling method), and return control flow to your program. The finally clause you were trying to use is similar, but is used to allow you to run code when an exception is thrown, but not stop the exception from being thrown (thus, somewhere / someone else higher up the stack will have to catch the exception).




I tried this, but I want the exception to bubble up. I tried rethrowing the exception, but again I can either return or rethrow, not both.

Share this post


Link to post
Share on other sites
Oluseyi    2103
quote:
Original post by yaroslavd
I tried rethrowing the exception, but again I can either return or rethrow, not both.
Which is a great big hint from the compiler and programming language.

You can keep butting your head against a stone wall if you like. It won''t move.

Share this post


Link to post
Share on other sites
yaroslavd    150
quote:
Original post by Oluseyi
quote:
Original post by yaroslavd
I tried rethrowing the exception, but again I can either return or rethrow, not both.
Which is a great big hint from the compiler and programming language.

You can keep butting your head against a stone wall if you like. It won''t move.


I''m not butting my head against a wall. I decided to either throw the exception or return the object. However, the exception will have access to the partially-loaded object.

Share this post


Link to post
Share on other sites
sjelkjd    171
Much to my amazement, exceptions really do work that way in java. Java will let you return something and have that evaluated before the exception resolves.

This is such a bad language feature.
Consider the following code:

public class Test
{
public int blah()
{
int answer = 0;
try
{
answer = stupidFunction() + stupidFunction();
}
catch(Exception e)
{

}
return answer;
}
int stupidFunction()
{
try
{
throw new Exception();
}
finally
{
return 5;
}
}
}

Guess what Test.blah() returns? 10!!!!! That means that two exceptions are live at once!!!

Share this post


Link to post
Share on other sites
yaroslavd    150
quote:
Original post by sjelkjd
Much to my amazement, exceptions really do work that way in java.


LOL. Told you!

I don''t know which way I like better, however... I''d expect java to do it the C# way since Java is built on the more-restrictive-more-simplistic principle.

Share this post


Link to post
Share on other sites
sjelkjd    171
Allowing more than one exception to be live at once, without providing the ability for handling that situation in the language, is very broken. Exceptions are supposed to be deterministic - when an exception fires, the only other things to happen should be finally blocks and catch blocks. By allowing returns to happen in finally blocks, java forces evaluation of any other statements necessary to resolve the line of code that invoked the original throwing function. As I''ve shown in the example, this can cause other functions to execute, and can even cause more than one exception to be live! I suppose you could throw in a finally too...but that also seems blatantly wrong. I''m not sure if java only takes the last exception or what, but in any case it''s bad news.

This really seems like a "gee-whiz" language feature that has hidden subtleties. Which is surprising, since java''s philosophy is generally to stifle the user by restricting langauge features to the bare minimum to achieve turing completeness. =)

Share this post


Link to post
Share on other sites
yaroslavd    150
quote:
Original post by sjelkjd
Which is surprising, since java''s philosophy is generally to stifle the user by restricting langauge features to the bare minimum to achieve turing completeness. =)


Yep, I agree.

BTW, what exactly does turing mean? I''ve seen the term before, but I have no idea what it means.

Share this post


Link to post
Share on other sites
markr    1692
Turing was a mathematician who amongst other things
- Cracked German Engima codes during WWII
- Helped build several computers during and after WWII
- Put his name on several of the main pieces of computer science, notably the Church-Turing thesis.

Turing-complete means it can do everything which is computable. Computable is something which can be defined mathematically, notably the "halting problem" (for which the thesis is famous) is NOT computable in the general case.

I didn''t realise that in Java you can return inside a finally block. My response to this would be that either:
- It has some application so obscure that it isn''t worth thinking about
or
- It''s a quasi-bug*; don''t do it.

Mark

*A quasi-bug is my name for something which isn''t technically a bug, but was some kind of feature which may have slipped in accidentally, and would have been a bug, except that its behaviour is well defined and possibly even useful (although not usually).

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
sjelkjd,

After testing (with lots of disbelief) with code similar to yours, it seems that there are no multiple exceptions alive at once. I think the return statement in the finally clause actually "eats" the thrown exception.


public class App
{
public static void main(String[] args)
{
int a = 0;

try
{
a = 100 * get() + 10 * get() + get();
}
catch ( Exception e )
{
System.out.println(e.getClass().getName());
}

System.out.println(a);
}

public static int i = 0;

public static int get()
{
++i;

try
{
switch ( i )
{
case 1:
throw new IllegalArgumentException();

case 2:
throw new IndexOutOfBoundsException();
}

return 1;
}
finally
{
return 2;
}
}
}


It just prints 222. Only if I remove "return 2;" from the finally clause the catch is reached.
Also notice that the return in the finally clause overrides the regular return (otherwise the output would be 221).

Java will never cease to amaze me...
(btw, C# forbids return statements in its finally clauses)

Share this post


Link to post
Share on other sites
sjelkjd    171
quote:
Original post by Anonymous Poster I think the return statement in the finally clause actually "eats" the thrown exception.



Weird, very weird...

Share this post


Link to post
Share on other sites
DrPizza    160
quote:
Java does it.

It''s one of Java''s many misfeatures. It''s fucking idiotic. javac 1.5 will warn about it.

That this:

try
{
return 2;
}
finally
{
return 4;
}

returns 4 and not 2 is a combination of crap and stupid that''s rarely encountered.

C# is very much doing the Right Thing by prohibiting this abomination.

Share this post


Link to post
Share on other sites