Subject: Re: [SWIPL] Type error vs. silent failure

From: Jan Wielemaker <[email-masked]>
Date: Fri, 26 Oct 2001 13:01:25 +0200

Gernot,

> [ Sorry, must have been discussed in the past, but couldn't find anything ]

Not on this list, but in general, I assume it must be.

> Is there any rational behind      
>    nth1(a, [a,b,c], X).
> failing silently and
>    length([a,b,c], a).
> giving a type error?

Not really, apart from the fact that length is part of the ISO standard
and the standard prescribes the tests to be made and the exceptions they
should raise, while nth1/3 isn't.

Without a standard, behaviour isn't defined.  Ok, there is some de-facto
standard that says what nth1 must be doing, but there is little de-facto
standard on how to handle things for which it wasn't designed
(get/generate the nth-element).

Additionally, length/2 is written in C and nth1 in Prolog.  In Prolog
code doing type-checks and throwing errors must often be coded
explicitely while omiting the check makes the predicate simply fail.
In foreign code life is different.  One often has to make a type-check
to avoid a plain crash of the program on a type-error and with a branch
in the code throwing an error is about as simple as just failing.

Having a look at the code, one could probably have done better; now
the two cases check for integer 1-st argument or unbound.

> The question is not whether one an tweek SWI-Prolog (or some other Prolog)
> to behave one way or the other, but what I can savely assume
> as a programmer when writing a portable program (as much as possible).

Prolog knows only `exception' without distinguishing between them. XPCE
for example separates the errors in errors caused by the context and
errors from the programmer. Problems opening a file is a typical example
of a thing that `can happen'. Sending a message to something that isn't
an object is an error of the programmer. The first, when left uncaught
is reported in an application-user-friendly way, while the second throws
the system into the debugger to be programmer-friendly way.

I'm inclided to program in the same manner in Prolog.  I use catch/3
around open/3 to deal with the possibility that the file might not
exist.  I'll also deal with catch on is/2 if the formula was entered
by the user.  To avoid an error in length/2 I'll always check for the
type myself if I know one of the arguments may not be acceptable to
length/2.  If an exceptions happens anyway I know I made a mistake.

Only in some really performance-critical situations I sometimes estimate
whether using catch/3 or checking is more efficient.  Note that catch/3
is not cheap for many reasons.  The call is a meta-call, you have to
push the goal, template and recovery onto the stack and if an exception
happens another expensive unwinding and meta-call must take place.  So,
in 99% of the cases checking is more attractive from this perspective.

Next is coding:
	
	catch(nth1(N, List, E), error(type_error(_), _), fail)

isn't really pretty, but 

	catch(nth1(N, List, E), _, fail).

May give some undesired results.  Maybe nth1/3 isn't around and your
goal now fails silently rather then with an error.  Maybe the system
runs out of stack, but this code will silently fail!

	Regards --- Jan