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

Re: logical operations in if-implements



Sorry for the long wait but only now am I catching up on the mail
concerning SRFI-0.  Here goes:

Per Bothner <bothner@xxxxxxxxxx> noted the analogy between the
if-implements form and C's #ifdef and #if preprocessor directives, and
suggested that if-implements be generalized to permit either:

1) and, or and not combinations such as (if-implements (and SRFI-3 SRFI-5) A B)

or even

2) a Scheme side-effect free expression as the if-implements predicate
which would be evaluated at macro expansion time (in a special
compile-time namespace).

The first part of this proposal adds no power, just convenience for
the user.  This convenience could also be provided by a macro (defined
in another SRFI?) which expands into if-implements forms.  I don't
actually see much of a need for it (except for "not" but please supply
compelling examples to convince me otherwise) and I don't like
overloading "and", "or" and "not".

The second part of this proposal is too hairy for my taste.  How do
you define precisely the sublanguage of Scheme which constitutes
"side-effect free" expressions?  Can you use set! on local variables?
eq??  delay?  call-with-current-continuation? exceptions?  Before you
know it you have to be so restrictive that you are left with a
crippled, probably ill-defined, unappealing sublanguage that needs its
own interpreter.  Also for this to work:

	(if-implements (and SRFI-123 (= foo-version 200)) work-around)

this sublanguage must treat unbound variables (such as the SRFI-123)
specially so that they evaluate to #f.  Yuck!

Let me repeat myself... it is important that the if-implements form
have a clear, unambiguous semantics.  This will allow all of us to
build on top of it instead of around it.  Also I think the
if-implements form should be easy to implement so that it doesn't add
much to the interpreter's or compiler's size (I'm thinking of an
interpreter/compiler which checks the syntax of the if-implements form
and reports appropriate error messages...).


Dave, Mike, and Shriram (The SRFI Editors) have come up with a counter
proposal which allows the program to request that a specific feature
be available and allows the program to test that a feature is
available (using COND-IMPLEMENTS a multiway if-implements).  The feature
requested can affect the reader's syntax (IMPORT-READER-SYNTAX) and/or
the macro syntax and environment bindings (IMPORT-IMPLEMENTATION).
Three forms are proposed:

  (COND-IMPLEMENTS (<feature-test> <body>)... (ELSE <body>))
  (IMPORT-IMPLEMENTATION <feature-id>)
  (IMPORT-READER-SYNTAX <feature-id>)

where <feature-test> is a <feature-id> or a combination with "and",
"or", "not".  COND-IMPLEMENTS is *not* analogous to COND because it
can choose any of the clauses for which a <feature-test> checks out.
I just don't see how this non-determinism can actually be helpful in
real programs.  There is not even the guarantee that identical
COND-IMPLEMENTS expressions will take the same branch.  Please provide
some convincing examples...  Apart from this peculiarity the
COND-IMPLEMENTS form could be built on top of the if-implements form
as a macro.

An important question for the IMPORT-IMPLEMENTATION and
IMPORT-READER-SYNTAX forms is their "execution time" with respect to
the test performed by the COND-IMPLEMENTS form.  Consider:

  (COND-IMPLEMENTS (SRFI-123 foo))
  (IMPORT-IMPLEMENTATION SRFI-123)

For this to work, the interpreter/compiler must process the
IMPORT-IMPLEMENTATION form before the COND-IMPLEMENTS form.  Because
IMPORT-IMPLEMENTATION can only appear at toplevel this apparently can
be done easily in a processing phase that is between "reading" and
"macro-expansion" which just checks toplevel forms.  But what is
really meant by "toplevel"...  which of these would be OK if found at
toplevel (sic!):

1) (begin (define x 1) (IMPORT-IMPLEMENTATION SRFI-100))

2) (include "foo.scm") ; if "foo.scm" contains (IMPORT-IMPLEMENTATION SRFI-100)

3) (my-import SRFI-100) ; if my-import is a macro that expands to an
                        ; IMPORT-IMPLEMENTATION form.

4) (COND-IMPLEMENTS (SRFI-200 (IMPORT-IMPLEMENTATION SRFI-100)))

The problem is that all of these require that macro-expansion be done
*before* IMPORT-IMPLEMENTATION forms can be processed.  So either
these uses of IMPORT-IMPLEMENTATION are disallowed (which I find to be
inelegant) or an iterative process, similar to one for finding
fixpoints, is used (which I find to be difficult to specify and
implement).

Moreover what happens if there are two *separately* compiled files and
one contains an (IMPORT-IMPLEMENTATION SRFI-100) and the other a
(COND-IMPLEMENTS (SRFI-100 foo))...  Either

1) the "compiler" basically does nothing... it reads the source and
delays macro-expansion, code-generation, etc to link time (where a
"real" global compilation is done), the advantage here is that
the COND-IMPLEMENTS tests are globally consistent.

2) the COND-IMPLEMENTS tests are only consistent on a file by file
basis, which is not very elegant.

The IMPORT-READER-SYNTAX has similar binding-time problems, and
additionally some systems already treat the first datum of a file
specially.  For example, for Gambit-C, if the first datum of a file is
the "script object" #! (as in: #! /usr/local/bin/gambit) then the file
is treated as a Scheme script (the first line is ignored and the
command line arguments visible to the script are computed specially
from the command line arguments).

The question I ask is why should all of this be in SRFI-0?  Why not
leave it to some other SRFI, so that SRFI-0 can be lean and simple.
In particular, I see lots of overlap in functionality between
IMPORT-IMPLEMENTATION/IMPORT-READER-SYNTAX and a module system, so its
probably best to work on a general module system SRFI than on the
relatively crippled IMPORT-IMPLEMENTATION/IMPORT-READER-SYNTAX.

Marc