Notifications
Clear all

[Closed] Problems with nested try/catch and throw

Do you guys have a ideas for handling “nested try/catches”? (or expections)

When I get a nasty exception I want to terminate the program. Is there a way to directly terminate the program by writing something like “End, Stop, Quit”.

The problem I want to avoid is that when I have many functions that I call throw() can sometimes create run time errorss.

When I have many nested try/catches I use throw() to “get out” of all try statements. Example:

try
(
try
(create_error+0)
catch
(
throw() –throw to get out
)

)
catch
(

)

This occation works fine. The problem arrises when I have many functions that are calling each other.

For example: function1(), function2()
fn function1=
(
try
(
create_error+1
)
catch
(
throw()
)
)

fn function2=
(
try
(
function1()–this creates an exception.

)
catch
(

)
)

************ The Problem ***********
This also works fine, however it does NOT work fine if I call function1 directly. For example:
function1()

In my catch I will THROW the exception but there is nothing to catch it so it will trigger a runtime error, which I do not want since it will open the code window.


Now does anyone have any ideas on how to avoid this problem in a good way? If there is a command to End the execution of a script it should do it.
Another way that would work, but is more of a hassle is to have a global variable, try_count that keeps track of the level of try statements we have pasted. If no other try levels have been passed, then it will not call throw. The downside is that there is much more code in the script.

Example:

try_count=0
try
(
try_count=try_count+1

try
(
try_count=try_count+1
–do stuff
try_count=try_count-1

)
catch
(
if try_count>0 do throw()
)

try_count=try_count-1
)
catch
(
if try_count>0 do throw()
)

I’m considering to do a special ExceptionClass that will take care of remembering the try/catch level, and also add some extra functions (for example I can give the try levels specific names that makes it easier to recognoise them)

/Andreas

10 Replies

I’m experimenting with a DebugClass, that automatically takes care of different “try levels” and only calls throw()

if needed. I will also expand it to present error messages in a better way and perhaps save them too. I will also make it easy for the user to send in error reports. This debugClass can also solve other problems, such as freezing timers while in function calls (they can create nasty bugs).

This is the current work in progress. Any ideas are welcome

debugClass

(

–This debug class keeps track of try “levels”. it will call throws() as long as inside

–nested try statements. In the last try throw will not be called (since that would cause a run time error)

–An error message is instead created.

– Locals ——–

tryLevel=0, ErrorText=””, LastTryName=””, fn ErrorFunction =(), fn FreezeFunction temp=(),

– Definitions —

fn Constructor=(), fn CreateTry=(), fn DeleteTry=(), fn Error=(), fn SetErrorFunction=(),fn SetFreezeFunction=(),

– Functions —–

fn CreateTry TryName=

(

LastTryName=TryName

tryLevel=tryLevel+1 –increases the try levels, throw will not be called if we are at level 0

FreezeFunction false –freezes optional timers.

),

fn DeleteTry=

(

tryLevel=TryLevel-1

if tryLevel==0 do FreezeFunction true –Start potential timers again

),

fn Error=

(

FreezeFunction false –freezes optional timers.

if TryLevel>0 then

throw()–throws an error to get out of to the last layer so the program can stop.

else

(

ErrorText=getException()–saves the exception message

print ErrorText

enablesSceneRedraw(); enablesSceneRedraw(); enablesSceneRedraw(); redrawViews() –restart the Views

ErrorFunction()–Calls custom error function if it exists

MessageBox (“An Error has occured in:” +LastTryName)

),

fn SetErrorFunction inFunctionError=

(

–An Optional Custom Error Function that is used to cleanup from the crasching program.

ErrorFunction=inFunctionError

),

fn SetFreezeFunction=

(

–An optional Freeze Function. Timers should be froozen in function calls

–so they are not called in the middle of operations, this can be run together with the try/catch statements.

)

)

–Example Usage

–The point is to be able to nest try/cathes and to only use Throw when it won’t cause an exception.

global tryDebugger=DebugClass()

function1=

(

try

(

tryDebugger.CreateTry “Function1” –this will tell the debug class that we are entering a new try level.

1/0 –Divide by zero to create the exception

tryDebugger.DestroyTry()–we are leaving a try statement so delete it.

)

catch

(

tryDebugger.Error()–Calls a throw if the tries are nested, otherwise print error message.

)

)

function2=

(

try

(

tryDebugger.CreateTry “Function2”

function1() –may call an exception

tryDebugger.DeleteTry()

)

catch

(

tryDebugger.Error()–Calls a throw if the tries are nested, otherwise print error message.

)

)

 PEN

Larry has mentioned that using try()catch(), throw and others is not a good way to deal with error handling. I gather it is slow and memory intensive. Can you not use other error handling methods?

2 Replies
(@f97ao)
Joined: 11 months ago

Posts: 0

Slow and memory intense doesn’t sound so great.

What I mainly want to avoid is for the maxScript code to popup when an error occurs. I would also like to be able to call a number of functions when an error occurs and stop everything from running.

But how can I do this without try() catch()?
What other error handling methods are you suggesting?
I will do some performance tests to see if the code gets slower.

/Andreas

(@jeff_hanna)
Joined: 11 months ago

Posts: 0

try() / catch() isn’t so bad. Throw() should be avoided if possible. It’s handled via a C exception which can be slow.

I don’t know what your actual code does, but wouldn’t it be possible to perform the nescessary checks inside functions and thereby preventing any errors?

Cheers,
Martijn

<I don’t know what your actual code does, but wouldn’t it be possible to perform the <nescessary checks inside functions and thereby preventing any errors?

What I’m actually after here is errors that I haven’t found yet. If I have found the problems well then the bugs simply wont be there! So this is the last safety net if an unkown bug occurs and I need to terminate the program. Then I need to cleanup some variables, try to save as much work as possible and give the user a chance to make a bug report.

Jeff:
It doesn’t really matter if throw is slow, since the only time it will every happen is if the program has encountered an unrecoverable error and will stop.

How do you guys generally treat errors in bigger encrypted programs?
Thanks for the ideas everyone. The DebuggClass seems to be shaping up quite nicely in concept. It’s useful that it can also disable timers inside functions, and perhaps turn off the escape option (so users don’t terminate functions). I already have classes to handle them so now I can just bundle them.

/Andreas

The project I am working on has thousands of lines of code, and errors can occur in various places.

I have found it necessary to use try/catch blocks for debugging, because if I dont, maxscript attempts to print out the current variables in the window when an error occurs. This takes…about 25 minutes!!!

So, whenever I get a bug, I have to force-quit max if Im not using try/catch. It’s very annoying.

But when I use try catch, I cannot get detailed information about WHAT went wrong…which is kind of a pain too, but I can narrow down the bugs using print messages etc.

1 Reply
(@f97ao)
Joined: 11 months ago

Posts: 0

I feel your pain. I also have a problem with the debugger printing forever when I use complex classes. Otherwise it’s not such a big problem. This class I’m building could be useful for controlling debugging better. I have a bunch of different tools I use, and I’m thinking that I could combine them into this debugg class. For example I have a special benchmark tools, and it would make sense to insert a more flexible print tool, that instead printes to our debugger. If a crasch happens it shows in what functions it happened, and also in what section of the code.

Here is the current code. I only wrote this, this evening so it’s still quite simple:
You can just cut and paste the code and run it.

struct debugClass
 (
 	--This debug class keeps track of try "levels". it will call throws() 	as long as inside
 	--nested try statements. In the last try throw will not be called 	(since that would cause a run time error)
 	--An error message is instead created.
 	
 	-- Locals --------
 	tryLevel=0, ErrorText="", LastTryName="", fn ErrorFunction =(), fn	FreezeFunction temp=(),
 	
 	-- Definitions ---
 	fn Constructor=(), fn Add=(), fn Delete=(), fn Error=(), fn SetErrorFunction=(),fn SetFreezeFunction=(),
 	
 	-- Functions -----
 	fn Add TryName=
 	(
 		LastTryName=TryName
 		tryLevel=tryLevel+1 --increases the try levels, throw will not be called if we are at level 0
 		FreezeFunction false --freezes optional timers.
 	),
 	fn Delete=
 	(
 		TryLevel=TryLevel-1
 		if tryLevel==0 do FreezeFunction true --Start potential timers again
 	),
 	fn Error=
 	(
 		tReturn=false
 		TryLevel=TryLevel-1
 		if TryLevel>0 then
 		(
 			tReturn=true			
 			
 		)
 		else
 		(
 			FreezeFunction false --freezes optional timers.
 			tReturn=false
 			ErrorText=getCurrentException()--saves the exception message
 			print ErrorText
 			
 			--enablesSceneRedraw(); enablesSceneRedraw(); enablesSceneRedraw();
 			redrawViews() --restart the Views
 			ErrorFunction()--Calls custom error function if it exists
 			MessageBox ("An Error has occured in:
" +LastTryName) title:"Runtime Error"
 		)
 		return tReturn
 	),
 	fn SetErrorFunction inFunctionError=
 	(
 	--An Optional Custom Error Function that is used to cleanup from the crasching program.
 		ErrorFunction=inFunctionError
 	
 	),
 	fn SetFreezeFunction inFreezeFunction=
 	(
 		FreezeFunction =inFreezeFunction
 		--An optional Freeze Function. Timers should be froozen in function calls
 		--so they are not called in the middle of operations, this can be run together with the try/catch statements.
 	)
 )
 
 --Example Usage
 --The point is to be able to nest try/cathes and to only use Throw when it won't cause an exception.
 
 global tryDebugger=DebugClass()
 fn function1=
 (
 	try
 	(
 		tryDebugger.Add "Function1" --this will tell the debug class that we are entering a new try level.
 		
 		"hgf"=hjj--Divide by zero to create the exception		
 		tryDebugger.Delete()--we are leaving a try statement so delete it.
 		print "works"
 
 	)
 	catch
 	(
 		print "catch"
 		if tryDebugger.Error() do throw()--Calls a throw if the tries are nested, otherwise print error message.
 	)
 	return false
 )	
 function1()
 
 fn function2=
 (
 	try
 	(
 		tryDebugger.Add "Function2"	
 		"hgf"=hjj--Divide by zero to create the exception	
 
 		function1() --may call an exception	
 		
 		tryDebugger.Delete()		
 	)
 	catch
 	(
 		print tryDebugger.tryLevel	
 		if tryDebugger.Error() do throw()--Calls a throw if the tries are nested, otherwise print error message.
 	)	
 )
 
 function2()

/Andreas

Yeah, I understand. I was just clarifying Paul’s comment regarding try/catch/throw. It’s not a memory useage issue. Throw(), along with break(), exit(), continue(), and return() use C++ exceptions, which makes them slower to use than alternative methods like the for/do/while loop (instead of break(), continue(), or exit()), and using reference parameters in functions instead of return().

Okay, I see why you’d want to use try/catch now