by John Cowan, Lassi Kortela, and Harold Ancell
This SRFI is currently in withdrawn status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-198@nospamsrfi.schemers.org
. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.
editor's summary of reasons for withdrawal: The authors disagreed on the specifics of the representation. (See email archive.) This SRFI had originally been motivated by the need for error reporting in SRFI 170, but SRFI 170 now includes an abstraction sufficient to support that without SRFI 198.
This SRFI provides means to construct, return or signal, and extract information from Scheme interfaces with "foreign" systems such as the POSIX API, databases, and libraries.
'convention
key requires a better name, and it's
not 'set
.
'sub-convention
will follow the new name.
'convention
key should be required for all status
and error objects.
'message
be replaced by the
shorter 'text
?
'source-filename
, 'line-number
,
and 'column-number
be in the SRFI's list of standard
keys, or in Schemeregistry?
They increase its surface by one half.
R6RS and R7RS-large have ambitions to become comprehensive ecosystems useful for developing real-world applications. This necessitates the development of many interfaces to "foreign" systems, ranging from direct Foreign Function Interfaces (FFIs) to low level assembler and C libraries, including APIs at that level such as POSIX, to protocols such as TCP/IP, all the way to client-server systems such as databases running in their own separate processes.
This SRFI provides a comprehensive framework for placing data about
the status of an interaction with a foreign system into an object,
starting with conventions to partition collections of them,
such as 'errno
, 'sqlstate
, and
'generic-c-lib
, to localize them, and to report them.
Sometimes it will make sense to simply return a status object, but
an often preferred method for errors is to raise an exception, as in
SRFI
170, in which procedures never return error codes nor use an
analogue of the POSIX errno
variable to
indicate system-call-level errors.
Thus procedures can return useful values, and the programmer can assume that if a foreign interface procedure returns, it succeeded. This greatly simplifies the flow of the code from the programmer's point of view.
The universe of foreign statuses is divided into distinct collections
named conventions based on their source.
The conventions 'status
and 'error
are
reserved for generic situations, such as sanity error checking before
a foreign interface is invoked.
Example conventions and sub-conventions include:
'errno | POSIX errnos | |
---|---|---|
'sqlstate | 'postgresql | The PostgreSQL database |
'generic-c-lib | 'libsodium | The libsodium cryptography library |
POSIX errnos are a familiar error system with a
moderate degree of structure, and were the initial inspiration for
this SRFI.
PostgreSQL is a representative SQL RDBMS with a richer set of SQLSTATE
data that can be transmitted to the user, and its client/server
organization is a useful counterpoint to using an FFI.
libsodium has a typical simple UNIX™ style C API that returns 0
on success and -1 on error, with no inherent structure.
The 'generic-c-lib
convention is suitable for many of these
libraries.
This SRFI uses property lists (plists). They are simple lists of alternating keys and values, such as:
('key1 "value1" 'key2 "value2")
(foreign-status? object)
→ boolean (procedure)
Returns #f unless object is a SRFI 198 status object.
(foreign-status? "This is not an foreign status object") ⇒ #f (foreign-status? (make-foreign-status <argument>)) ⇒ #t
(foreign-status-ref foreign-status-object key)
→ value or #f
(procedure)
Returns the value in a foreign status object associated with key , or
#f
if key is not in the object.(foreign-status-ref <foreign-status-object> <key not in object>) ⇒ #f (foreign-status-ref <POSIX-foreign-error-object> 'convention) ⇒ errno
(foreign-status-keys foreign-status-object)
→ list (procedure)
Returns all the keys in a foreign status object in a list.
(foreign-status-keys <POSIX-foreign-error-object>)⇒ (convention errno number name scheme-procedure foreign-interface message args heritage)(foreign-status-keys <PostgreSQL-wire-foreign-status-object>)⇒ (convention sub-convention sqlstate category class-text condition-name scheme-procedure foreign-interface message args)(foreign-status-keys <libsodium-foreign-status-object>)⇒ (convention sub-convention scheme-procedure foreign-interface message)
(foreign-status->plist foreign-status-object)
→ plist (procedure)
Returns all the key/value pairs in a foreign status object as a plist, the
'convention
key is guaranteed to be the first one. It is an error to mutate the plist.(foreign-status->plist <POSIX-foreign-error-object>)⇒ (convention errno number 2 name ENOENT scheme-procedure open-file foreign-interface open message "open-file called open: errno/ENOENT: No such file or directory" args ("not-a-valid-filename" 0 428) heritage . "SRFI 170")(foreign-status->plist <PostgreSQL-wire-foreign-status-object>)⇒ (convention sqlstate sub-convention postgresql sqlstate "28P01" category exception class-text "Invalid Authorization Specification" condition-name invalid_password scheme-procedure open-database-connection foreign-interface query-message message "open-database-connection: 28P01: incorrect password" args ("localhost" 5432 "ecb" "ecb"))(foreign-status->plist <libsodium-foreign-status-object>)⇒ (convention generic-c-lib sub-convention libsodium scheme-procedure generate-key foreign-interface sodium-init message "generate-key: ecb-generate-key could not initialize sodium library\n")
(make-foreign-status convention-value plist)
→ foreign-status-object (procedure)
(raise-foreign-error convention-value plist)
→ undefined (procedure)
These procedures are handed a value for the convention key, and a plist, and return an abstract data type object. It is an error to pass non-symbols as keys in the plist, if the plist does not have an even number of elements, or if the
'convention
key/value pair is not in the object. If the plist argument is malformed, an error is signaled. Except for small memory implementations, these procedures must preserve the malformed argument for end users as the value of the'args
key.A recommended approach to handle a malformed argument is to create a status object with either
'status
or'error
as the value of the'convention
key, make the argument the value of the'args
key, and supply an informative'message
.
raise-foreign-error
constructs a foreign-error-object likemake-foreign-status
, and raises an exception in a manner suitable for the Scheme implementation it is running on. In a R6RS or R7RS system following SRFI 35, or in a system supporting SRFI 18, raising an exception means to callraise
on the object. In a system only supporting SRFI 23, raising an exception means callingerror
with areason
string andirritants
following it.(make-foreign-status 'status '()))⇒ foreign-status-object(raise-foreign-error errno '(number 2 name ENOENT scheme-procedure open-file foreign-interface open message "open-file called open: errno/ENOENT: No such file or directory" arguments ("not-a-valid-filename" 0 428) heritage "SRFI 170")⇒ undefined(make-foreign-status generic-c-lib '(scheme-procedure generate-key foreign-interface sodium-init message "generate-key: ecb-generate-key could not initialize sodium library\n")⇒ foreign-status-object(raise-foreign-error 'error '()))⇒ undefined
convention
:
The only mandatory key/value pair, it is used to divide the universe
of foreign interfaces. For more information see the text after the
Specification heading.
sub-convention
:
To further subdivide large conventions such as 'generic-c-lib
.
scheme-procedure
:
The Scheme procedure in which the status object is created.
If there is no Scheme code interposed between the the user and a FFI,
it can be omitted or have a value of #f
.
If the plist argument to create a status object is malformed, its
value should be 'make-foreign-status
.
foreign-interface
:
The specific part of the foreign interface that was called, and
responded with a status.
For a library, the name of the library function that was called
is suggested.
message
:
A message suitable for human understanding of an interface status.
In the construction of the error message, implementers are encouraged
to include relevant information from the above fields and the args
field below.
Implementations on small-memory systems can reasonably omit message
strings.
args
:
The arguments handed to the Scheme procedure in which the status
object is created.
For login functions, you want to omit reporting and logging plaintext
passwords, and login names are also dangerous because users will
sometimes accidentally enter their password first.
For cryptographic libraries, the same for secret and private keys and
plaintext data.
inner
:
For nesting of a lower level status object.
source-filename
:
A string containing a filename that contained the source code that
generated the status.
line-number
:
The line number in the above 'source-filename
of the
beginning of the call to make-foreign-status
or
raise-foreign-error
.
column-number
:
The column in the line-number above.
An old Chibi Scheme sample implementation of this SRFI can be found in the srfi directory of the SRFI's repository, it will be updated when the API settles down.
Thanks to Olin Shivers and all the Scheme implementers who have
followed his work; this SRFI was inspired by scsh's
errno-error
facility. Thanks also to all the
participants in the SRFI 170 and SRFI 198 mailing lists.
Copyright © 2020 John Cowan, Lassi Kortela, and Harold Ancell
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.