[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

"Its the little things that count. Hundreds of 'em." -- Cliff Shaw



; FILE:		Portability-Proposal
; IMPLEMENTS:	Proposal for suggested library function interface
; AUTHOR:	Ken Dickey
; DATE:		1989 February 19
; LAST UPDATED: 1989 March 17
; HISTORY:
; STATUS:	DRAFT (#1)


PREFACE:

The number of Scheme implementations is rapidly growing.  This
document is an attempt to deal with portability issues so that
applications can be made source-portable with a single compatability
file across differing Scheme implementations.  A recommended standard
library interface is included, with the recognition that not all
functions make sense for all implementations (e.g. the THE-CURRENT-TIME
function for embedded applications lacking real-time clock support). 

The main portability issues addressed here deal with the ability to
programatically query an implementation and fill in the gaps between
the implementation supplied library and an application.  Specifically,
to provide baseline functionality, specialize machine independent to
implementation specific functions, and allow implementation-dependent
optimizations.  

Baseline functionality consists of augmenting an implementation's
library to include all functions required by an application.  For
example, if hash-tables are not provided by the implementation, they
may be provided by the application.  However, hash-tables provided by
an implementation may be significantly more efficient than those an
application might provide and are to be preferred if offered.

Specializing machine independent to implementation specific functions
requires mapping an application defined interface to idiosyncratic
implementation, operating system, or hardware features.  For example,
an application may typically map conventionalized to idiosyncratic
line drawing functions. 

Implementation dependent optimizations can have a major impact on
application performance.  Writing portable applications of significant
size requires allowing the use of some optimizations where they are
available.  A typical example is allowing a compiled implementation to
consider certain definitions as constant so that folding or code
inlining optimizations may be performed.


===========================================================================

=======================
IMPLEMENTATION QUERIES:
=======================

========
FUNCTION: (IMPLEMENTATION-INFORMATION) 
========

RETURNS: A proper list of the form:

  (<name> <version> <MACHINE> <CPU> <OS> <FS> . <supports>)

Each object returned is a symbol or #f.  It is recommended that
symbols be in mixed case (as if created with STRING->SYMBOL). 

EXAMPLE: (implementation-information) -->
(BogusScheme 1.0 Valhalla-9000 68080 GNUnix GNUfs Complex Reals X21)

NOTES: Case is used for readability and uniqueness.  <Supports>
options can be checked with memq. <Version> can be parsed after
SYMBOL->STRING conversion (see string ports). 


========
FUNCTION: (SCHEME-IMPLEMENTATION)
========

RETURNS: a proper list of the form (<name> <version>), where <name> and
<version> are symbols.



===========================================================================
================
FORMATTED OUTPUT
================

========
FUNCTION: (FORMAT <port> <format-string> . <args>)
========

RESULT: returns unconsumed <args> or a string; has side effect of
printing according to <format-string>.  If <port> is #t the output is
to the current input port.  If <port> is #f, a formatted string is
returned as the result of the call.  Otherwise <port> must be an
output port.  <format-string> must be a string.  Characters are output
as if the string were output by the DISPLAY function with the
exception of those prefixed by a tilde (~) as follows:

~a  any: display the object (as for humans).
~s  slashified: write the object (as for parsers).
~d  decimal: the integer argument is output in decimal format.
~x  hexadecimal: the integer argument is output in hexadecimal format.
~o  octal: the integer argument is output in octal format.
~b  binary: the integer argument is output in binary format.
~p  plural: if the argument is greater than 1, a lower case 's' is printed.
~c  character: the next argument is displayed as a character.
~_  space: output a space character.
~%  newline: output a newline character.
~&  freshline: unless at the beginning of a line, same as ~%, else ignored.
~|  page seperator: output a page seperator.
~~  tilde: output a tilde.
~t  tab: output a tab charcter.
~g  glorify: pretty print the argument (typically an s-expression).
~?  indirection: take the next argument as a format string and consume
    further arguments as appropriate, then continue to process the current
    format string.

========
FUNCTION: (PRETTY-PRINT <sexp> . <port>)
          (PRETTY-PRINT <sexp> <port> . <width>)
========

RETURNS: Unspecified.  Side effect it to output the <sexp> in an
implementation dependent manner. 


===========================================================================
==============
ERROR HANDLING
==============

========
FUNCTION: (RESET)
========

RETURNS: No, it never returns.  In implementations which interact with
the user via a top-level repl (read eval print loop), this function
has the effect of returning to the top-level repl.  Other actions are
implementation dependent.


========
FUNCTION: (FATAL-ERROR <message> . <irritants>)
========

RETURNS: No, it never returns.  This function typically has the side
effect of FORMATting the <message>--which should be a format string
to the current output port.  Any <irritants> unconsumed by format are
DISPLAYed to current output port.  This is a fatal error.  In
implementations which interact with the user via a top-level repl, a
RESET is performed.  Other actions are implementation dependent, but
may include process termination. 

EXAMPLE:
> (+ 2 (fatal-error "this is an ~a with extra arguments" 'error 1 2 3))
= this is an ERROR with extra arguments 1 2 3
>

========
FUNCTION: (ERROR <message> . <irritants>)
========

RETURNS: Implementation dependent.  This behaves as FATAL-ERROR as far as
output of the <message> and <irritants>, but is possably continuable in
implementations providing an interactive inspector or other error
handling. 


========
FUNCTION: (INSPECT . <obj>)
========

RETURNS: It depends.  If <obj> is specified, it is the default return
value, else #f is the default.  What is actually returned is usually
up to user discretion.  This command invokes an interactive inspector
in the invoking enviromnent.  If an <obj> argument is present, it is
the initial object of the inspection. 


========
FUNCTION: (TRACE . <identifiers>)
========

RETURNS: Unspecified.  Identifiers must have values.  If an identifier
designates a function, that function is traced on entry and exit.


========
FUNCTION: (UNTRACE . <identifiers>)
========

RETURNS: Unspecified.  Removes the trace side effect on traced
identifiers.  With no arguments, untraces all traced identifiers.



===========================================================================
======
SYNTAX
======

============
SPECIAL FORM: (ALIAS <alias> <original>)
============

RETURNS: Unspecified.  Has the side effect of creating an alias for
the original when it occurs in the call position.  Both arguments must
be identifiers.  <Original> must exist at time of call.

EXAMPLEs: (alias herald comment)  (alias debug inspect)


============
SPECIAL FORM: (COMMENT . <any>)
============

RESULT: The comment syntax is read as if by READ and discarded.  The
effect is interpreted or compiled as whitespace.


============
SPECIAL FORM: (UNLESS <test> <expressions>...)
============

RESULT: If <test> is #f, acts as (BEGIN <expressions>...), else
returns #t. 


============
SPECIAL FORM: (WHEN <test> <expressions>...)
============

RESULT: If <test> is #t, acts as (BEGIN <expressions>...), else
returns #f. 


============
SPECIAL FORM: (COMMENT-WHEN <test> <exp> . <exps>)
============

RESULT: If <test> is #f, then acts as COMMENT else acts as BEGIN (which
is flattened into the current contour).



===========================================================================
====
TIME
====

========
FUNCTION: (THE-CURRENT-DATE)
========

RETURNS: A list of 3 fixnums: (<year> <month> <day>) where <year> is
based on the Julian calendar and <month> <day> are based on 1.

EXAMPLE: (the-current-date) --> (2001 1 23)


========
FUNCTION: (THE-CURRENT-TIME)
========

RETURNS: A list of 3 fixnums: (<hour> <minute> <second>) in 24-hour format.

EXAMPLE: (the-current-time) --> (13 23 30)


========
FUNCTION: (RUNTIME)
========

RETURNS: An approximation to the number of microseconds the current
process has been running.


========
FUNCTION: (UPTIME)
========

RETURNS: An approximation to the number of seconds the since the
system was booted.


===========================================================================
============
STRING PORTS
============

========
FUNCTION: (OPEN-INPUT-STRING <string>)
========

RETURNS: An input port.

NOTES: Useful to READ.


========
FUNCTION: (GET-OUTPUT-STRING <string-port>)
========

RETURNS: A string.  <String-port> must have been created by
OPEN-OUTPUT-STRING. Has the logical side effect of reseting the
string-port to the empty string.

========
FUNCTION: (OPEN-OUTPUT-STRING)
========

RETURNS: An output port.

NOTES: Useful to WRITE and PORT->STRING.


========
FUNCTION: (STRING-PORT? <port>)
========

RETURNS: #t if <port> is a string port, else #f.



===========================================================================
==========
BINARY I/O
==========

========
FUNCTION: (WRITE-BYTE <value> . <port>)
========

RETURNS: Unspecified.  Side effect is to output <value>, which must be
a number in the range 0..255, in machine (binary) format.


========
FUNCTION: (READ-BYTE <value> . <port>)
========

RETURNS: The EOF-object or a fixnum in the range 0..255.



===========================================================================
============
BYTE VECTORS
============

========
FUNCTION: (BYTE-VECTOR <value>...)
========

RETURNS: A byte-vector of the same length as the number of values
supplied.  Each value must be a number in the range 0..255.


========
FUNCTION: (BYTE-VECTOR-REF <bv> <index>)
========


========
FUNCTION: (BYTE-VECTOR-SET! <bv> <index> <new-value>)
========


========
FUNCTION: (BYTE-VECTOR->STRING <bv>)
========


========
FUNCTION: (STRING->BYTE-VECTOR <string>)
========


========
FUNCTION: (BYTE-VECTOR->LIST <bv>)
========


========
FUNCTION: (LIST->BYTE-VECTOR <string>)
========


========
FUNCTION: (BYTE-VECTOR? <obj>)
========

RETURNS: #t if <obj> is a byte-vector, else #f.



===========================================================================
===========
DEFINITIONS
===========

========
FUNCTION: (BOUND? <identifier>)
========

RETURNS: #t if <identifier> is bound in the environment of the call,
else #f.


========
FUNCTION: (DEFINE-IF-UNBOUND <name> <exp>)
          (DEFINE-IF-UNBOUND (<name> <args>) <exp>)
========

NOTES: If <name> is unbound, the definition is as per DEFINE, else as
per COMMENT.


========
FUNCTION: (DEFINE-IF-IMPLEMENTATION <implementation> <name> <exp>)
          (DEFINE-IF-IMPLEMENTATION <implementation> (<name> <args>) <exp>)
========

NOTES: If <implementation> is eq? to (CAR (IMPLEMENTATION-INFORMATION))
then definition is as per DEFINE, else as per COMMENT.


===========================================================================
==========
STRUCTURES
==========

============
SPECIAL-FORM: (DEFINE-STRUCTURE <structure-name> <field> ...)
============

RESULT: Defines a disjoint record type with a named set of fields.
The following are defined: 
  predicate 				<structure-name>?
  constructor				MAKE-<structure-name> 
  a setter for each field 		SET-<structure-name>-<field>!  
  and an accessor for each field 	<structure-name>-<field>
,
Fields may be initialized if of the form: (<field-name> <exp>), where
<exp> is evaluated once in the environment of the define-structure
form. Uninitialized fields default value is #f.

EXAMPLE: (define-structure quux bar (baz 20)) has the effect of
defining MAKE-QUUX, QUUX?, QUUX-BAR, SET-QUUX-BAR!, QUUX-BAZ,
and SET-QUUX-BAZ!.
  (quux-bar (make-quux)) --> #f
  (quux-baz (make-quux)) --> 20


===========================================================================
====
MISC:
====

========
FUNCTION: (RANDOM <limit> . <seed>)
========

RETURNS: A number between zero (inclusive) and <limit> (exclusive).
The argument(s) must be numbers.  An approximation to a uniform
distribution is used.  The <seed> argument is used to be able to
repeat the same pseudo-random sequence.


========
FUNCTION: (SORT <obj>) 
========

RETURNS: A newly allocated object of the same type as <obj> with
<obj>'s elements sorted.  <Obj> must be a list, vector, string, or
byte-vector.


========
FUNCTION: (SORT! <obj>) 
========

RETURNS: Original <obj> with elements sorted.  <Obj> must be a list,
vector, string, or byte-vector. 


========
FUNCTION: (SUSPEND <filespec>) 
========

RETURNS: Error if suspension was unsuccessful, else implementation
dependent (typically returns to native operating system).  Saves an
approximation to the current state of computation in an implementation
dependent manner to a file denoted by <filespec> which can later be
invoked in an implementation dependent manner.  Note that some system
state (such as the state of open files) may not be restorable.


========
FUNCTION: (AUTOLOAD <name-or-namelist> <filespec>)
========

RETURNS: Unspecified.  Side effect is delayed definition in current
scope.  When a function is initially referenced, it is automagically
loaded before being invoked. <name-or-namelist> must be an identifier
or a list of identifiers which are presumed to denote functions defined
in file referenced by <filespec>.
      


===========================================================================
###########################################################################
===========================================================================
	End Of Interface
===========================================================================
###########################################################################
===========================================================================


===========================================================================
=====
NOTES:
=====

IMPLEMENTATION-INFORMATION returns mixed case symbols--I thought this
would get your attention! 

FORMAT returns unused arguments: this makes format somewhat easier to
write and allows FATAL-ERROR to be defined without a second format
function:
    (define (FATAL-ERROR <format-string> . <args>)
        (let ( (unused-args 
                 (apply format `(#t "~&~?" ,<format-string> ,@<args>))
               )
             )     
          (unless (null? unused-args) 
              (for-each (lambda (arg) (display #\space) (display arg))
                        unused-args)
          )
          (display #\newline)
          (reset) 
    )   )

COMMENT-WHEN: does the job of eval-when, compile-when, etc.  I would
like to avoid the eval-time vs compile-time question for now.  I
definately feel the need for conditional compilation.  What do you
think? 

WHEN, UNLESS: I see these in a lot of code.  I use them.  How about
other very common patterns? 

BOUND?: I know, I know.  But how are we to write DEFINE-IF-UNBOUND
unless we can test somewhere?  Do we keep this as magic? 

DEFINE-IF-<condition>: If we accept COMMENT-WHEN and BOUND?, are these
needed?

SORT: Assumed to do a typed dispatch to LIST-SORT, VECTOR-SORT, etc.  (at
least until we have an object system interface such as Amos provides).

Raw and Cooked I/O {QUUX-NO-HANG}: I have not proposed anything here
because this is a tasking issue.  Either you use READ-CHAR and
CHAR-READY? as specified by R3RS {cooked} or you are dealing with
buffers and interrupts and you have to deal with {raw} rubout
characters yourself.  Binary i/o allows us to implement buffers if we
face the tasking questions {see Interrupts/Handlers, below}.  Once we
have portable, buffered i/o we can write portable editors--just like
real languages. 



===========================================================================
===========
UNADDRESSED: Here are some further topics that should be addressed.
===========  You can add more.  Since I did such a bad job above,
you should be able to come up with a better proposal on one or more of
these.


Interrupts/Handlers {We need these as abstract services.
		    I would be real pleased if Will Clinger and Kent
		    Dybvig to got together to propose something (hint)}

Storage Recycling (GC), pre- and post-gc hooks.

Tables, Hashing, [Populations]

File Seeking {The Pascal Standard has a reasonable file specification}

Foreign Function Interface -- {Some say not a real language without it!}

Errorset, Programatic error handling.

File-System Objects and Structured File-Names (as in T or CL)

Numeric Precision & Numerics in general

Syntactic Extensions



===========================================================================
================
GENERAL COMMENTS
================

R3RS is a good job of language specification.  But a language without
a reasonably large library of standard functions will not be taken
seriously.  I consider the above to be just short of barely adequate.
My hope is to come to a concensus in time to get a reasonable library
appendix in the IEEE Scheme Standard.  I could use some help.

Thanks in advance,
-Ken				kend@mrloog.LA.TEK.COM
==================================E=O=F====================================