Go Card Error Handling

dunbarx at aol.com dunbarx at aol.com
Sat Jun 25 10:29:35 EDT 2016


I am a HC'er from way back.


But it seems like the "correct" way is to throw an error in all cases, simply as a matter of purity and consistency.


That legacy stacks might break is a point, but then, how would they break? In other words, how could this arise? Likely a user entered an invalid card reference somewhere, or a card was deleted.


The old way is that the code notes the result (or does not), does something with that condition (or not) and either continues or throws its own error notification. By continues, I mean fails to access a card and ignores that case.


But if the process always stops dead if a "normal" error is now built in, legacy code would only break where  it did not matter if accessing a non-existent card made no difference at all. So would that be unreconcilable in all cases, that is, might the user find himself in a trap he could not extricate from? That is the reason for leaving the old way alone.


Craig Newman



-----Original Message-----
From: Mark Waddingham <mark at livecode.com>
To: How to use LiveCode <use-livecode at lists.runrev.com>
Sent: Fri, Jun 24, 2016 1:09 pm
Subject: Re: Go Card Error Handling

Thanks Dar and Jacque,

That puts it nicely in context. I'd class this behavior, then, as being 
for 'HyperCard compatibility'.

LiveCode does have a slightly different model from HyperCard though, 
which is why it is perhaps a behavior which should be reviewed at some 
point. Indeed, it actually suggests there are a few other places where 
the error behavior for stacks and cards aren't quite right.

For example, the engine will try to load a stack from disk if a 
reference 'stack "mystack"' isn't in memory - in this case *this* is 
file I/O and such should probably set the result rather than throw an 
error.

When the engine does have a stack in memory, going to a card cannot fail 
due to file I/O (as all objects in a stack are in memory all the time) 
and thus a non-existant card should throw an error. Indeed, you can 
check whether a card exists before accessing it by checking 'the 
cardNames'.

Indeed, this does suggest that *perhaps* the fact that you can do:

    go stack <named_of_stack_in_memory>

Or

    go stack <stack filename>

Suggests that these are two distinct operations and a 'cleaner' model 
would be perhaps to have:

    load stack <stack filename>

To load a stack from disk which, as it involves file I/O, should set the 
result.

And, furthermore, make:

    go stack <name_of_stack>

Only succeed if the named stack is in memory, if it is not then it 
should throw an error.

I'm minded to think here that there is actually a nice separation here. 
In any applications there are stackfiles which can be considered to be 
an intrinsic part of the application, and then all other stackfiles. The 
former will typically have named references somewhere (usually in the 
stackfiles property of another stack), or be included in the description 
of what the application consists of (i.e. the stackfiles which are 
included with a standalone).

The distinction here is between stackfiles for which their non-existence 
should be considered an application failure (just as if a dynamic 
library is not present for a native app, the app will usually not work) 
and stackfiles which the application manipulates (like any other data 
file).

 From an error handling point of view, these present two entirely 
different cases.

For operations which you should always expect to succeed *or* can 
guarantee will succeed by a preceding check in code, the correct error 
approach is to throw.

For operations which could fail and you cannot 'precheck' for failure, 
the correct error approach is to set the result.

To put it slightly more abstractly:

An operation should throw an error for all errors which occur as a 
result of 'system failure' (for some definition of system) which the 
application has done all it can to ensure it cannot happen. In this 
case, if you include a set of stackfiles in your standalone application, 
and one of them fails to load then you can reasonably take this to be an 
'exceptional' circumstance - the problem will be due to something you 
(as a programmer) can in no-way control. (For example, if one of the 
stackfiles on disk is corrupted).

An operation should set the result for all errors which occur which 
cannot be checked for beforehand - typically this will be because there 
is a time-of-check to time-of-use problem. In this case, if you have a 
stackfile which is not considered directly part of the application and 
is perhaps chosen by the user - or indirectly by the user - then it is 
impossible to check before you try and load the stackfile that the 
operation will succeed. Certainly you can check that the stackfile 
exists before you try to load it using 'there is a file', but since OSes 
are pre-emptive, in between doing that check and trying to load it, 
another process could have done something to invalidate the check.

Of course, in the above the assumption we are making is that the 
'stackfiles which are part of the application' are not amenable to being 
fettled with by other processes - in the sandboxed model (such as you 
get on iOS and Android) this is enforced, in unsandboxed worlds you have 
to squint a bit to convince yourself that this is actually a reasonable 
thing to assume. (After all, if you go into an installed applications 
folder on any platform and start deleting arbitrary files from them, you 
can't really expect them to function at all!).

So, anyway, my question has been answered :)

Warmest Regards,

Mark.

-- 
Mark Waddingham ~ mark at livecode.com ~ http://www.livecode.com/
LiveCode: Everyone can create apps

_______________________________________________
use-livecode mailing list
use-livecode at lists.runrev.com
Please visit this url to subscribe, unsubscribe and manage your subscription preferences:
http://lists.runrev.com/mailman/listinfo/use-livecode




More information about the use-livecode mailing list