Proper script writing: throwing errors within UDFs

Please check the FAQ (https://www.xyplorer.com/faq.php) before posting a question...
Post Reply
Marco
Posts: 2354
Joined: 27 Jun 2011 15:20

Proper script writing: throwing errors within UDFs

Post by Marco »

Today I just tested the waters when it comes to UDFs, and I'd like to know what's the proper way to throw errors in an UDF.

First, a little observation: something like this

Code: Select all

 $x = formatdate(gttw3tw);
throws an error at formatdate() in the "script console", and then continues setting the variable to nothing.

TheQwerty suggests using assert, which takes an optional "continue" flag. Setting it it's like no "real" error is thrown at all, because the UDF continues. Not setting the "continue" flag terminates the whole script instead.
Then there's end, which is more granular because it allows to abort the UDF without terminating the whole script, however it throws a warning with a popup window, which is not consistent with a "genuine" function error.

So, how can I throw an error in a UDF which
-makes the script console pop up
-aborts the rest of the UDF
-continues executing the rest of the calling script,
much like an XY function?
Tag Backup - SimpleUpdater - XYplorer Messenger - The Unofficial XYplorer Archive - Everything in XYplorer
Don sees all [cit. from viewtopic.php?p=124094#p124094]

bdeshi
Posts: 4256
Joined: 12 Mar 2014 17:27
Location: Asteroid B-612
Contact:

Re: Proper script writing: throwing errors within UDFs

Post by bdeshi »

when does end throw a popup window? end 1,,1;

you can put a conditional return; after the assert cmd.
Icon Names | Onyx | Undocumented Commands | xypcre
[ this user is asleep ]

TheQwerty
Posts: 4373
Joined: 03 Aug 2007 22:30

Re: Proper script writing: throwing errors within UDFs

Post by TheQwerty »

It really depends on what the function is doing.

One way:

Code: Select all

function crappyFunction($a) {
  $badCondition = ($a == '' || $a != ''); // Whatever your test expression is, and you could just put it in the if instead. ;)
  if ($badCondition) {
    Assert false, 'Bad happened.', true;
    return ''; // or -1, or another value that makes sense.
  }

  return 'all good';
}
Another would be to replace the assert with an echo and use the undocumented bits (icon 4,7,8, or 9 are okay options).

I prefer to avoid popping up a dialog though by documenting assumptions and returning error codes - putting the decision and work on the caller instead.

When it comes to returning errors we've got options:
false (Empty String or 0)
-1
Something like WriteFile/Exists: 0|msgOrReturnValue
Pass a variable via reference instead:

Code: Select all

// Returns a greeting or false (error) if $input is empty.
function hello($input) {
  if ($input == '') {
    Assert false, 'Empty', true';
    return false;
  }
  return "Hello $input";
}

// Sets result to the greeting return false (error) if $input is empty.
function hello(&$result, $input) {
  $result = "Hello $input";
  return $input != '';
}

bdeshi
Posts: 4256
Joined: 12 Mar 2014 17:27
Location: Asteroid B-612
Contact:

Re: Proper script writing: throwing errors within UDFs

Post by bdeshi »

talking of variables, I'm test-driving a global $lasterr mechanism.
Sometimes '' can be a valid return but it can also be the same when an error ocurred. $lasterr can say what really happened.

Code: Select all

function f($var){
  global $lasterr = '';
  $return = replace($var,$var);
  //  processing
  if ($var == 'bad') { $lasterr = 'BADVER'; }
  return $return;
}
"test"
 $f = f('bad');
 if ($lasterr != '') { echo 'f() : I Am ERRor! (a pointless one)'; }
But those conditions may have to be put before/after every command/block for 100% error-catching.

There should be something native and simpler like this.
Icon Names | Onyx | Undocumented Commands | xypcre
[ this user is asleep ]

bdeshi
Posts: 4256
Joined: 12 Mar 2014 17:27
Location: Asteroid B-612
Contact:

Re: Proper script writing: throwing errors within UDFs

Post by bdeshi »

To babble on...

http://www.xyplorer.com/xyfc/viewtopic. ... 22#p122921 I used the aforementioned method here. Works nicely but it breaks down if a function is called from another function. Because the inner function can overwrite the outer's (non-fatal) errors.

Can there be a special error receiver variable or sth?
Say, like this:

Code: Select all

echo $err::int(); //returns the last error triggered from int().
FUNCTION int() {
 //code code
 if !(condition) { $err::() = self('caption') . '() errored'; }
 //^ records an error from this function (the ::() denotes $err var for current function ;) )
 //code code
just a suggestion.
Icon Names | Onyx | Undocumented Commands | xypcre
[ this user is asleep ]

Post Reply