I was going to update BIKI with this but it went full retard on me once again, not to mention that I can no longer post links on it even if it is to feedback tracker tickets.  Anyway, if you’re familiar with try-catch structures from other languages you know, that by putting your code inside try {} block you can intercept script errors and deal with them in your way. In Arma you cannot intercept anything but you can stop the rest of your code from executing, with a reference. Arma exception catching takes following format:

  • try {throw ANY} catch {_exception};

The try {} catch {} is inseparable structure. The code inside try {} scope always runs by default, but the code inside catch {} scope will only run if throw is used inside corresponding try {} scope. The special variable  _exception inside catch {} scope will then receive value passed to throw command, which could be anything. Most importantly, the try {} scope will exit as soon as the 1st throw command is executed. This means that any code after triggered throw will not be executed. Let’s look at the following example:

try { if !(isNull _unit) then {throw _unit}; /*...code...*/ } catch { diag_log format ["Unit <%1> is not null", _exception]; };

So if the _unit is not null in the above example, the script will throw exception with _unit object in it, which will be caught by catch block and logged. The rest of the code inside try {} block will never get executed. Let’s spice it up a bit and add assert command to it, which will also display error message on screen provided you are on DEV branch or run your build with -showscripterrors flag, and log it to .rpt file:

try { if !(assert isNull _unit) then {throw _unit}; /*...code...*/ } catch { diag_log format ["Unit <%1> is not null", _exception]; };

Now lets look at a few unconventional uses of this structure. How about turning it into a switch?

_taste = "dunno"; _fruit = try { if (_taste == "sweet") then {throw "a cherry"}; if (_taste == "sour") then {throw "a lemon"}; "a good day" } catch {_exception}; hint ("Have " + _fruit); //Have a good day

As you can see the scopes are acting like any other scopes, meaning that the last line gets returned whether it is in try {} block or catch {} block. Or maybe turn it into a call only instead of _this the arguments would get passed in _exception variable:

_a = 1; _b = 2; _c = try { throw [_a, _b]; } catch { (_exception select 0) + (_exception select 1); }; //3

Why not to build the whole error logging reusable structure out of it finally?

fnc_log_error = { diag_log format ["Error: %1", _exception]; }; try { if !(assert false) then {throw "log whatever"}; } catch fnc_log_error;