open(File, Mode, Stream)
has the following error defined:
The argument
- f)
Stream
is not a variable
—type_error(variable, Stream)
Stream
should be unified with a
stream-term (7.10.2), more specifically (7.10.2.1):
A standard-conforming program shall make no assumptionsIt is therefore possible for a standard conforming processor to reuse stream-terms for different mutually exclusive file operations. This can be observed in many processors such as SICStus 3, SWI, YAP.
about the form of the stream-term, except that:It is implementation dependent whether or not the pro-
- a) It is a ground term.
- b) It is not an atom.
- c) It uniquely identifies a particular stream during the
time that the stream is open.
cessor uses the same stream-term to represent different
source/sinks at different times.
YAP version Yap-6.0.0 ?- open(t, write, S), close(S), open(t, write, S). ERROR!! TYPE ERROR- open(t,write,$stream(3)): expected unbound variable, got $stream(3) ?- open(t, write, S), close(S), open(t, write, S2), S == S2. S = S2 = '$stream'(3) ? ; noWhereas the first query produces the required
type_error(variable,S)
, the second clearly shows
that success could have been possible.
In all other situations, type errors mean semantically failure. Type errors are signaled in situations "where the type of an argument or one of its components is incorrect but not a variable" (7.12.2 b). This particular case is the only exception. In fact, the intention of type errors was to replace silent failures previously found in most systems by more meaningful messages. So only in situations where a silent failure (or another erroneous outcome) would happen otherwise, type errors appear appropriate. Clearly, this is not the case here.
An implementation that did guarantee unique identifiers was Quintus Prolog according to Richard O'Keefe. Uniqueness was guaranteed as long as identifiers were referenced within the system. Nevertheless, even such an implementation profits from an error for an instantiated stream as it would prevent opening a file that can no longer be closed explicitly.
The error classification of 13211-1 (7.12.2) has turned out to be surprisingly robust, even for unanticipated cases. It seems that the particular situation is the only one where an existing error needs a new error class.
open/4,3
(8.11.5) in an existing standard. However, this kind of error is also
needed in the following areas:
gensym/2
frequent implementation specific built-in
predicate.
library(error): must_be/2
Error reporting library by Wielemaker and O'Keefe
[user] ?- exception_handler(arg(a,f(1),_), error(type_error(_,_),_), fail).Which is different from
catch/3
as it traps the exception in the
context where it occurs, not where the catch
goal is called and allows
local repair, replacing the result to that returned by the Handler
Goal (fail).
In the following technical corrigendum Nnn and
nnn_error
should be replaced by an appropriate name for
that error class.
Clause b: Remove variable
from the enumerated set.
Add additional clause k:
nnn_error(Culprit)
where Culprit
is the argument or one of its components
which caused the error.
a type errorby
a nnn error
— type_error(variable, Stream).
by
— nnn_error(Stream).
The only thing that is left open is the precise name of that nnn. We will thus first look at the existing conventions in 13211-1.
An error for unexpected instantations can easily be circumvented in
case no error should be produced. If a goal p(Term)
leads to this error, the error can be prevented by
using p(NewVar), NewVar = Term
.
Error_term | Error situation | Example |
---|---|---|
a)
| An instantiation is expected, but a variable is found instead. | X =.. Y. — instantiation_error.
|
b)
| A term of type ValidType is expected, but Culprit
is found instead.
| X =.. [foo|bar]. — type_error(list, [foo|bar]).
|
c)
| Similarly, a domain is expected. | X =.. []. — domain_error(non_empty_list, []).
|
d)
| The existence of Culprit as an object of
ObjectType is expected, but it does not exist.
| ex_nihilo. — existence_error(procedure, ex_nihilo/0).
|
e)
| The permission of type PermissionType for doing
Operation onto Culprit is expected,
but the permission is not given.
| open('/etc/shadow', read,S). — permission_error(open, source_sink, '/etc/shadow')
|
f)
| A representation for some term is expected, but none
can be provided by the system.
| functor(F, f, 1000). — representation_error(max_arity).
In this case, we expected that f/1000 can be represented.
Systems whose max_arity is smaller than 1000 will produce this error. |
g)
| An (error-free) evaluation is expected,
but Error happened during evaluation.
| X is 1/0. — evaluation_error(zero_divisor).
|
h)
| A resource is expected to be available, but it is not/not enough of it is left. |
length(L,L). — resource_error(stack).
|
i)
| Text of correct syntax is expected for a Prolog text, but some
invalid syntax described by Imp_dep_atom was found
instead.
|
read(X). with "a b".— syntax_error(operator_expected).
|
j)
| A functioning system was expected, but a malfunctioning system is present instead. | Hopefully, this error never happens! |
k)
| A term with property nnn was expected, but the instantiated term
Culprit was found instead.
| open('/dev/zero',read,S), open('/dev/null',read,S). — nnn_error(imp_dep(2314))
|
freeness_error
pro: 8+ The opposite of bound is free.
+ In 13211-1 free is used to refer to free variables of a term with respect to another term (7.1.1.4) - a notion needed for bagof/3 (8.10.2) and setof/3 (8.10.3). So the two uses would not collide.
+ Freeness analysis is a well established notion in the context of (logic) program analysis. It determines which terms are variables at a certain point in time. Freeness analysis is clearly seen as being separate from aliasing analysis.
- The terms "free variable" and "bound variable" have their classical meaning in logic (e.g., all the variables in a clause are bound by the implicit quantifier), so overloading them within the context of logic programming appears problematic.
uninstantiation_error
pro: 23.193 uninstantiated: A variable is uninstantiated
when it is not instantiated.
3.96 instantiated: A variable is instantiated with re-
spect to a substitution if application of the substitution
yields an atomic term or a compound term.A term is instantiated if any of its variables are instantiated.
3.146 read-option: A compound term with uninstanti-
ated * arguments which amplifies the results produced
by the built-in predicate read-term/3 (8.14.1) and the
bootstrapped * built-in predicates based on it (see 7.10.3).
Apart from above terminology entries (3), uninstantiated is used only once: note 3 of the description of bagof/3 (8.10.2.1).Remark: In 7.10.3 the read-options are
variables/1
,variable_names/1
,singletons/1
.
subinstantiation_error
pro: 1underinstantiation_error
.
range_error
A range error occurs when an output argument was supplied with
an illegal value. This is similar to a type error or a domain error, except
that it is a hint that a variable would be a good thing to supply instead;
type and domain errors are associated with input arguments, where a variable
would usually not be a good idea. The exception code associated with a
range error is
range_error(Goal, ArgNo, TypeName, Culprit)
This has the same arguments as a type error. Most built-in predicates
do not raise any range errors. Instead they fail quietly when an output
argument fails to unify.
Note that the situation in Quintus is slightly different to the
situation of unexpected instantiations. This can be seen best by
considering the errors for the Quintus
predicate asserta/2
. If the reference happens to be the
same, no error is produced. While this is quite improbable it is
still possible to guess a reference a priori. Or to print out a
reference and reuse it in another system. In any case, the Quintus
error depends on the success when unifying a term and not only on the
instantiation.
The name range collides with the following uses in 13211-1:1995:
- asserta(+Clause, -Ref)
- Ref
- <db_reference> a database reference which uniquely identifies the newly asserted Clause.
- Description:
- Ref should be uninstantiated; a range exception is signalled if Ref does not unify with its return value. This exception is signalled after the assert has been completed.
- Exceptions:
- range_error if Ref does not unify with the returned database reference.
3.22 byte: An integer in the range [0..255]...
6.3.4 Compound terms - operator notation
...
The priority of an operator is an integer in the range R, where
R = {r, r ∈ Z | 1 ≤ r ≤ 1200}
7.11 Flags
...
Each flag has a permitted range of values; any other
value is a Domain Error (7.12.2 c).
8.17.1.1 set_prolog_flag/2 ...The name collides with ECLiPSe-Prolog's synonymous Domain Error.
a) Associates Value with the flag Flag (7.11), where
Value is a value that is within the implementation
defined range of values for Flag,
unboundness_error
noninstantiation_error
anti_instantiation_error
uniqueness_error
unboundedness_error
variableness_error
variable_error
Also, the name itself might be easily misunderstood, as this might suggest that the error is changeable. (I.e. variable ≈ changeable). Further, what we actually want is not only a free variable (in 13211-1 a variable consistently means a free variable), but a free and unaliased variable.
freevar_error
freesubvar_error
underinstantiation_error
under_instantiation
seems to be problematic, as this can
be easily confused with the frequently used locution "goal under
instantiation".
distinctness_error
cessation_error
noaliasing_error
vacuity_error
unbound_error
representation_error(variable)
type_error(variable, Culprit)
as it does not imply a
semantic failure. On the other hand representation errors shall be
issued if an implementation defined limit has been breached
(7.12.2 f). The promise behind is that in principle this
error would vanish if the implementation improves. This is the case
for integers: By going from a 32-bit system to a 64-bit system a lot
of representation errors will vanish for a processor with bounded
integers. Similarly for character codes going from ASCII to more.
However,
representation_error(variable)
will never vanish as
this is not a limit in the implementation. So the promise behind will
never be fulfilled.
misinstantiation_error
malinstantiation_error
malbinding_error
over_instantiation_error
overbinding_error
hyperbinding_error
hyperinstantiation_error