Return statement inside try..catch block and switch statement breaks the Flash player

(Didn’t know what other title to give it, so this is what I came up with)
I came upon a strange problem a few days ago. I was trying to create a simple function that would take a String value and return that value in a simple data type (String, Boolean, Number, int or uint), based on a parameter specifying the type to return. So the easiest way was to use a switch test for all five of the types and return the value accordingly. When trying to return a Number, int or uint data type, I wanted to use a try..catch statement, just for making sure that the function would not break when using the parseFloat() and parseInt() functions. So, my function looked like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
function getValue(value:String, type:String):* {
 
	switch(type) {
 
		case "String": {
			return value;
		}break;
 
		case "Boolean": {
			return (value == "true");
		}break;
 
		case "Number": {
			try {
				return parseFloat(value);
			}
			catch(e:Error) {
				return NaN;
			}
		}break;
 
		case "int": {
			try {
				return parseInt(value);
			}
			catch(e:Error) {
				return NaN;
			}
		}break;
 
		case "uint": {
			try {
				var num3:int = parseInt(value);
				if (num3 >= 0) return num3;
				else return NaN;
			}
			catch(e:Error) {
				return NaN;
			}
		}break;
 
	}
 
	return null;
}

With the function in this form, it seems that the player simply breaks down and displays a whole bunch of error messages in the Output panel. Besides those, it also displayed the entire application into compiled code, looking something like this:


verify test_switch_fla::MainTimeline/getValue()
exception[0] from=42 to=52 target=56 type=Error name=e
exception[1] from=78 to=88 target=92 type=Error name=e
exception[2] from=117 to=153 target=157 type=Error name=e
stack:
scope: [global Object$ flash.events::EventDispatcher$ flash.display::DisplayObject$ flash.display::InteractiveObject$ flash.display::DisplayObjectContainer$ flash.display::Sprite$ flash.display::MovieClip$ test_switch_fla::MainTimeline$]
locals: test_switch_fla::MainTimeline String? String? * *
0:getlocal0
stack: test_switch_fla::MainTimeline
scope: [global Object$ flash.events::EventDispatcher$ flash.display::DisplayObject$ flash.display::InteractiveObject$ flash.display::DisplayObjectContainer$ flash.display::Sprite$ flash.display::MovieClip$ test_switch_fla::MainTimeline$]
locals: test_switch_fla::MainTimeline String? String? * *

It also had a few dozen lines more of this kind. Pretty strange problem, I told myself and tried to find out why was this happening. It turns out the problem were those return NaN statements from the try..catch blocks. If I would only use the return statement, without the value to return, that would turn out to be ok (except that the function would still have to return a value and would not be correct from the application point of view).

Also, when testing the try..catch block separately, not inside the switch statement, it seems that there is no problem when the return statement is found in the catch part of the block, including the value to return. So the next code throws no errors:

1
2
3
4
5
6
7
8
9
10
11
function testing():Number {
	try {
		var test:Number = parseFloat("kdhk");
		return test;
	}
	catch(e:Error) {
		trace("catch");
		return NaN;
	}
	return NaN;
}

In conclusion, do not place return value statements in the catch blocks if those blocks are placed in switch statements. Anyway, in my case, there’s no need for the try..catch blocks, since parseFloat() and parseInt() always return a value (NaN if the source string cannot be converted), so it makes no sense using the try..catch block. After reviewing my code, here is the simple conversion function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
function getValue(value:String, type:String):* {
 
	switch(type) {
 
		case "String": {
			return value;
		}break;
 
		case "Boolean": {
			return (value == "true");
		}break;
 
		case "Number": {
			return parseFloat(value);
		}break;
 
		case "int": {
			return parseInt(value);
		}break;
 
		case "uint": {
			var num3:int = parseInt(value);
			if (num3 >= 0) return num3;
			else return NaN;
		}break;
 
	}
 
	return null;
}
 
 
trace(getValue("test", "String"), getValue("test", "Boolean"), getValue("test", "Number"));
//    test false NaN
trace(getValue("12.34", "String"), getValue("12.34", "Boolean"), getValue("12.34", "Number"));
//    12.34 false 12.34
trace(getValue("-23", "Number"), getValue("-23", "int"), getValue("-23", "uint"));
//    -23 -23 NaN

5005: Unknown error optimizing byte code

This is a really “interesting” error message that Flash throws in the Output panel and unfortunately there is no other explanation accompanying the message. At Jumpeye we’ve had to deal a few times with this error message which seems to be generated whenever working with large .fla files that make use of rather large amounts of code.

The solution would be to turn off the Optimizer and then recompile. You can turn the Optimizer off from the Publish Settings dialog box, select Settings for the “ActionScript 3.0″ option and in that dialog box disable the “Reduce file size and increase performance” option. You can do this whenever you are working on a very large project and get this error message. In the rest of the cases, you should leave this option checked.

Another solution I’ve found on the web (didn’t test it) is to delete the .aso files generated by Flash (Control -> Delete ASO Files) .