Error handling

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, LCMark

Locked
FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 9802
Joined: Sat Apr 08, 2006 7:05 am
Location: Los Angeles
Contact:

Error handling

Post by FourthWorld » Thu Feb 12, 2015 11:18 pm

In LiveCode we have two very different ways of discovering when our code doesn't work:

1. Sometimes we have to check "the result"
2. Sometimes an execution error is thrown
2a. Sometimes an execution error is reported with a scriptError message (desktop, mobile)
2b. Sometimes an execution error is reported with scriptExecutionError (Server)

Why is it that attempting to convert a date requires checking the result, while attempt to decode an array throws an execution error? And why are there two different messages for execution errors depending on which engine our script happens to be running under at the time?

Could v8 be an opportunity to consider having just one way to handle errors?

A while back I submitted a request for one possible way to do this, with a function called scriptError:
http://quality.runrev.com/show_bug.cgi?id=13573

I'm not necessarily married to that, and maybe there are better options we could consider.

Let's brainstorm some ideas.

It may turn out that the best possible solution is to continue teaching newcomers a variety of "sometimes" rules and hope they remember them all.

And maybe they're not "sometimes" rules at all, but governed by some overarching principle currently unknown to me and most of my peers which if explained might allow us to predict how we need to handle errors for any command without having to look it up in the Dictionary.

But maybe there's a simpler, more unified way to handle errors.

What would you like to see for error handling?
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn

phaworth
Posts: 592
Joined: Thu Jun 11, 2009 9:51 pm

Re: Error handling

Post by phaworth » Fri Feb 13, 2015 10:16 pm

Great idea Richard. Another area where different tests have to be done to check for errors is database handling so I hope that will get cleaned up too. That includes the fact that you get a runtime error if the database id is invalid thus denying you the change to terminate gracefully.
Pete

dave.kilroy
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 858
Joined: Wed Jun 24, 2009 1:17 pm
Location: Plymouth, UK
Contact:

Re: Error handling

Post by dave.kilroy » Fri Feb 13, 2015 11:49 pm

This is a great idea Richard, and very timely. I usually have to check in the dictionary as to whether I should be checking 'the result' or 'it' - and sometimes even have to experiment in code to see what each produces

I remembered, searched for and found, this thread (http://forums.livecode.com/viewtopic.ph ... r+handling) from late 2013 where runrevmark was saying that error handling in LiveCode needed to be sorted out - but that the refactoring project had to be completed first - I suspect that error handling has often been put off "just until..." (plus ça change, plus c’est la même chose)

Just like personal hygiene, it can be ok to leave spending time on error handling for a while - but as time goes by it becomes an increasingly good idea to focus on it for a bit :)

Kind regards

Dave
"...this is not the code you are looking for..."

monte
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 1564
Joined: Fri Jan 13, 2012 1:47 am
Contact:

Re: Error handling

Post by monte » Wed Feb 18, 2015 12:35 am

I believe there's a general rule to throw an error if the problem is something that can be worked around via script and to set the result if otherwise. I agree that something other than the result that could be used by functions would be nice on the other hand I guess there's a risk we'd just be adding another place to look for errors...
LiveCode User Group on Facebook : http://FaceBook.com/groups/LiveCodeUsers/

LCMark
Livecode Staff Member
Livecode Staff Member
Posts: 1206
Joined: Thu Apr 11, 2013 11:27 am

Re: Error handling

Post by LCMark » Wed Feb 18, 2015 11:07 am

Yes @monte is correct there is (in theory) a 'general rule' that errors are thrown when it is something exceptional and should not happen (e.g. because of a programmatic error); and then 'the result' is set if it is something the scripter really needs to handle. This rule has kind of been inferred from context - from the cases where the result or errors were thrown in existing code. The problem is that it is not possible to really make it 100% precise as it relies on a certain amount of subjectiveness and context.

For example, the database id one is clearly a case where it is programatic error (sorry @phaworth). Database Ids do not go away unless you explicitly close them, so if you attempt to use one after you've closed the connection then that's a fault in the script - also there is a function which allows you to check what database ids are valid so there's never really an excuse ;)

In contrast, opening a file is something which might always fail regardless of how much you tried to guard against it (you can't control those darn cosmic rays after all!).

An example where this rule isn't really followed is the 'convert' command - I can find no rationale this apart from 'that is how it was implemented originally' (and unfortunately it is just one of those cases which is plain wrong - regardless of context and subjectiveness!).

In terms of the subjectiveness of the rule - then a good example is file access. If you are opening a file your application needs to run (a 'resource file') then it seems reasonable that if that fails then it is an exceptional circumstance and so should throw; but if you are opening a file the user has asked you to, then you need to handle the failure case (the user might have mistyped something).

Moving forward then it would be the ideal that there is one way to handle errors and any such method needs to make it easy to deal with both the 'exceptional case' and the 'local case'.

In particular, one can make the general (and I believe true) statement - if an error occurs then failure to handle that error somewhere results in incorrect code execution. Therefore in order to write correct code you need to handle all errors somewhere, and failure to handle an error should result in a 'panic' - this is precisely what an exception handling mechanism gives you and thus is perhaps preferable over anything which uses side-line return values (unless of course you are forced to process the side-line return values, and failure to do so results in a panic, in which case it is entirely equivalent, but much less convenient for most cases).

So if we were to move to a single exception-based model for error handling, the question becomes how can we make this easier to use?

The fact is that sometimes it is necessary to process an error locally (which you can easily do with 'the result'), and sometimes it is easier to handle an error non-locally (which you can do with 'try/catch'). One thought I've had along these lines for a while is to introduce a 'try to' statement prefix and 'the error' expression. The idea here would be that you can 'try to <command>' and if '<command>' throws an error it gets caught and is then accessible in 'the error' (one could also use 'try ; <commands> ; end try' in a similar way). Here 'the error' would always be the last error that was caught by a 'try to' in the current handler. Essentially:

Code: Select all

try to <domycommand>
if the error is "panic" then
  answer "Don't Panic!" -- ideally in pink
end if
Would be equivalent to:

Code: Select all

try
  <domycommand>
catch tError
end try
if tError is "panic" then
  answer "Don't Panic!" -- ideally in pink
end if
Now you could argue that this is kind of pointless as it is just syntactic sugar - except for the fact it directly models the rough implementation of a split between local and non-local errors which we have at the moment - and does so in a way which allows the developer to account for subjectiveness in what an error might mean. For example, the open file command does not throw at the moment so you see code like this:

Code: Select all

open file tMyFile for text read
if the result is not empty then
  -- handle failure to open file
end if
If we move to just exceptions then this would become the slightly less concise:

Code: Select all

try
  open file tMyFille for text read
catch tError
  -- handle failure to open file
end try
If we had 'try to' and 'the error' then the original form is almost preserved verbatim:

Code: Select all

try to open file tMyFile for text read
if the error is not empty then
  -- handle failure to open file
end if
The difference between this and 'the result' form though is the general case where you don't attempt to handle a potential error - the exception generated would be propagated and if not handled would cause a panic - i.e. potential incorrect code execution as a result of not handling an error cannot occur as the code terminates as soon as the unhandled error occurs. Also the fact it is a specific 'the error' syntax for accessing the error information means that it lends itself to more specific syntax - rather than 'the result' which is just a value.

LCMark
Livecode Staff Member
Livecode Staff Member
Posts: 1206
Joined: Thu Apr 11, 2013 11:27 am

Re: Error handling

Post by LCMark » Tue Mar 10, 2015 10:52 am

Straw-poll:

What should I infer from the lack of discussion after my last post...

a) General disinterest in error handling

b) Tacit agreement that the above suggestions seem like a 'good idea' (in principal at least)

:)

dave.kilroy
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 858
Joined: Wed Jun 24, 2009 1:17 pm
Location: Plymouth, UK
Contact:

Re: Error handling

Post by dave.kilroy » Tue Mar 10, 2015 11:08 am

Mark apologies for not responding to your post earlier.

I've just re-read it and in my view you've suggested a really nice way forward which would allow me to use the same approach to finding if there is an error, finding out what the error is and then dealing with it. Any slight changes in how I account for errors at the moment would be well worth not having to spend time figuring out where an error will raise it's head in any particular situation.

Could you just clarify that I'll still be able to throw errors in your new system?

Dave
"...this is not the code you are looking for..."

LCMark
Livecode Staff Member
Livecode Staff Member
Posts: 1206
Joined: Thu Apr 11, 2013 11:27 am

Re: Error handling

Post by LCMark » Tue Mar 10, 2015 11:19 am

@dave.kilroy: Hehe - no problem - just thought I'd bump the thread to see if it got any more traction.

Yes - my suggestion is about unifying the error handling mechanism. So, you wouldn't ever use 'the result' to indicate an error you'd use throw. You could then choose whether you wanted to handle using try/catch, or try to - the latter giving you 'the result' like checking code, but saving 'the result' for what it should be - the result of a computation. (the other important thing here is that because it is exception based, the error would remember where it had come from - something the result cannot do).

dave.kilroy
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 858
Joined: Wed Jun 24, 2009 1:17 pm
Location: Plymouth, UK
Contact:

Re: Error handling

Post by dave.kilroy » Tue Mar 10, 2015 11:27 am

Sounds great - I used to code with .NET and am used to (and like) an exception based approach :)
"...this is not the code you are looking for..."

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 7214
Joined: Sat Apr 08, 2006 8:31 pm
Location: Minneapolis MN
Contact:

Re: Error handling

Post by jacque » Tue Mar 10, 2015 6:39 pm

runrevmark wrote:Straw-poll:

What should I infer from the lack of discussion after my last post...

a) General disinterest in error handling

b) Tacit agreement that the above suggestions seem like a 'good idea' (in principal at least)

:)
c) Don't know.

What would happen to "the result" then in existing code? This is related to your other post about whether to dump backward compatibility I suppose.
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

LCMark
Livecode Staff Member
Livecode Staff Member
Posts: 1206
Joined: Thu Apr 11, 2013 11:27 am

Re: Error handling

Post by LCMark » Tue Mar 10, 2015 6:56 pm

I don't think my forum post suggested dumping backwards compatibility necessarily - just trying to find a means to marshal LiveCode Script forward into the new century in a way that allows everyone to benefit and be happy :)

The result would be what it currently it is - 'the result' of the computation the function is meant to perform.

The difference is you wouldn't get error information in the result - that would be provided via a sideline mechanism (try/catch, of 'the error' - if 'try to' is implemented).

I've noticed a lot over the years that it is easy to cause bugs in programs because 'the result' sometimes contains error information in a way that overlaps the results of functions and commands. For example. the revdb commands return 'revdberr,...' in the result... This would be fine except that it is perfectly possible for some of the revDB APIs to return 'revdberr,...' as a non-error result (think of a table with two text columns with one row, the first column containing 'revdberr' and the second containing '...').

Basically if 'try to' were implemented then code written like this:

Code: Select all

get revdb_dosomething()
if item 1 of the result is "revdberr" then
  ... oh dear an error ...
end if
Would become:

Code: Select all

try to get revdb_dosomething()
if the error is not empty then
  ... oh dear an error ...
end if
... Do stuff without any false-positive error results ...

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 9802
Joined: Sat Apr 08, 2006 7:05 am
Location: Los Angeles
Contact:

Re: Error handling

Post by FourthWorld » Tue Mar 10, 2015 7:24 pm

I like everything about where this is going, except for having to type "try to" before every command.

Could that be implicit? I'm imagining your example working just as described with only:

Code: Select all

get revdb_dosomething()
if the error is not empty then
  ... oh dear an error ...
end if
... Do stuff without any false-positive error results ...
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn

LCMark
Livecode Staff Member
Livecode Staff Member
Posts: 1206
Joined: Thu Apr 11, 2013 11:27 am

Re: Error handling

Post by LCMark » Tue Mar 10, 2015 8:19 pm

@FourthWorld: What my suggestion is trying to do is unify two different approaches to error handling - one where you rely on exceptions (try/catch), and one where you want to check for errors after each command (currently 'the result', but more generally with this suggestion 'the error'). Remember try/catch is still there which would be the way to get the error from a group of commands (btw, this is still just an idea - it might not actually work to well on real code).

Many commands and functions will only raise errors in truly exceptional circumstances (most will if you run out of memory for example). Some, however, raise errors some of which indicate there is a serious problem and some which indicate something that requires further refinement - opening a file is a good example of this (however, the distinction is contextual). In general i/o errors will come about because a serious problem (e.g. hard-drive meltdown - but not necessarily the primary drive and so not absolutely catastrophic, so it isn't going to bring down the system) but for whatever reason (due to race-conditions implicit in multi-tasking environments) you cannot ever guarantee however many checks you do to see if a file can be opened, that you can.

So, I'd probably suggest that there is a command prefix 'try to', and also a command grouping form 'try / end try':

Code: Select all

try to get myErroneousFunction()
-- the error might be non-empty here
try
  get myErroneousFunction()
  get mySecondEquallyErroneousFunction()
end try
-- the error might be non-empty here
The advantage here is that you can aggregate the processing of a result from a group of commands.

If you include a catch clause, then the implicit assumption would be that you want to handle a specific error, but not all of them:

Code: Select all

try
  open file tFoo for read
  write tData to file tFoo
  close file tFoo
catch file did not open error
  -- alert the user their preferred file can't be processed
end try
-- all other presumably more catastrophic errors will propagate upwards
The syntax may not be quite right here - there would be quite a big difference between 'try/end try' and 'try/catch/end try' which is a concern.

This is a good reason why I posted the suggestion here for comment :)

To give an example of something which shows that error-handling is truly contextual... Out-of-memory errors are something you really don't want to have to deal with on every single line of your code but they can happen. In most cases if you are out-of-memory there is very little you can do - your app has to basically go into 'a save as much as I can before I bail' type mode but there are situations where not having enough memory to perform an operation does not mean your app is terminally fated. Let's say you are doing some operation which the fast path for requires a huge amount of memory, then you want to try that first and if you don't have enough memory then you may want to try a slower, but much less memory hungry approach:

Code: Select all

try
  ... load lots of data ...
  ... process data in memory ...
end try

if the error is out of memory then
  ... revert to slower, but guaranteed  approach
else if the error is not empty then
  ... oh dear something else went wrong ...
  throw the error
end if

... everyone is happy, the operation succeeded, it just took a little longer...
Perhaps the above example is best handled in a different way with a different formalism - but it is an example of the criticality of errors in context.

(I should say I'm imagining the above in a context where we have flexible syntax and so we can do things like 'the error is out of memory').

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 7214
Joined: Sat Apr 08, 2006 8:31 pm
Location: Minneapolis MN
Contact:

Re: Error handling

Post by jacque » Tue Mar 10, 2015 10:21 pm

The result would be what it currently it is - 'the result' of the computation the function is meant to perform.
I wasn't clear. I meant, what would happen to current code that still checks "the result" for errors? That's why I mentioned the other thread. It sounds like this would have to be a clean break that only new projects could use. I'm just wondering how we'd need to adapt.
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

LCMark
Livecode Staff Member
Livecode Staff Member
Posts: 1206
Joined: Thu Apr 11, 2013 11:27 am

Re: Error handling

Post by LCMark » Wed Mar 11, 2015 9:45 am

@jacque: Apologies - any change to error handling would have to come alongside a compatibility mode or something similar - although the 'try to' syntax (if it has any merit) would make the transformation of existing code easy. The revDB example I gave initially above shows the pattern...

Any code which relies on the result, must be relying on the result from a previous statement somewhere so you put 'try to' in front of that statement and then use 'the error' rather than 'the result' to check for an error.

Locked

Return to “Engine Contributors”