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

[Scheme-reports] Fwd: Poll: intentions concerning the R7RS "small" language

Sorry, accidentally sent this to the implementors list.
Please keep any discussion on the scheme-reports


---------- Forwarded message ----------
From: Alex Shinn <alexshinn@x>
Date: Sun, Aug 21, 2011 at 8:05 PM
Subject: Re: Poll: intentions concerning the R7RS "small" language

On Sat, Aug 13, 2011 at 5:04 AM, Andy Wingo <wingo@x> wrote:
> At some point I would like to consider having "unspecified values" be
> generally implemented as `(values)', in the language of the R6RS.  The
> R7RS has currently chosen the old "an unspecified value" language, which
> could make Guile incompatible with R7RS (and indeed R5RS, as you have
> noted).  I think that the right thing to do is to allow implementors to
> consider this choice and decide on their own.  Users who rely on `(if #f
> #f)' producing a single value can use implementations that choose the
> single-valued model.  That is my opinion, but it is where I would like
> to take Guile.

For clarity, I assume you mean the R6RS specification, which
allows an "unspecified number of unspecified values".  Returning
explicitly zero values was considered, but as it breaks both
R5RS and R6RS compatibility didn't seem like a serious

The concern is that there's a non-trivial amount of R5RS code
which assumes a single value is returned, and it's not clear
just how extensive this code is or how easily it can be changed.

The specific idiom (let ((undef (if #f #f))) ...) to get at the impl's
void value I've seen a lot.  It doesn't even work reliably in R5RS,
but in practice works in most implementations.  It's arguably bad
style, and the sort of thing we should discourage.

There are other instances where a single value is assumed, many
of which were discussed on the list.  John only listed the straw-man
example (define x (set! y 30)), but in a macro expansion where
you are expanding only definitions (suitable for internal define) and
need to use mutation, this is a natural solution.  Just define x as
some dummy variable.

Analogously, I've often used dummy variables in let* to enable

 (let* ((foo ...)
         (dummy (print "foo is: " foo))
         (bar ...))

All of these I would consider borderline cases, and assuming
they aren't too extensive I wouldn't be too concerned with
breaking them.

The other general "class" of examples is where the programmer
assumes there are no instances of multiple values in some
context (such as a module or file, or perhaps their entire codebase).
In this case they can write things like

 (define-syntax time
   (syntax-rules ()
     ((time expr)
      (let* ((start (current-seconds))
              (res expr))
        (report-time start)

then use this in that context (_not_ as a general utility for
others to use) without worrying about the non-single value

In short, this is a user who probably hates MV, never uses
it himself, never uses any APIs which provide MV, and yet
by changing the specification in the way you propose suddenly
his (reasonable from his perspective) code stops working.

And that's what makes a lot of people hate MV - it's not
a feature you can just ignore, it pervades the whole language.

But these holdouts are relatively few, and likely stick to
their implementations which will continue to return a single
value.  In practice this change will only make their code
non-portable, not break it.

So we've re-opened this issue in the fourth ballot.  I
haven't yet decided myself how I'll vote.


Scheme-reports mailing list