Subject: Re: bug#17296: Uh, wrong?

From: David Kastrup <[email-masked]>
Date: Wed, 04 Jun 2014 06:39:50 +0200

Mark H Weaver <[email-masked]> writes:

> David Kastrup <[email-masked]> writes:
>> So the behavior for length+ on a dotted list is strictly unspecified.
>> It is not even stated "it is an error".
>
> Actually, it is.  At the end of the section that defines the "types"
> such a "clist" and "flist", it states:
>
>   It is an error to pass a circular or dotted list to a procedure not
>   defined to accept such an argument.
>
> While it is true that we are not required to signal an error, I'm wary
> extending 'length+' in this way.  It also effectively extends 'map' and
> 'for-each' to support things like (map + '() 'foo), and thus potentially
> affects many other procedures both inside and outside of Guile that use
> 'map' and 'for-each'.  Once we've done this, users are likely to grow
> dependent on it and we can never go back.

That is true for _any_ particular choice for unspecified behavior.
_Including_ throwing an error as a means of checking input validity.

You are proposing providing functions _not_ defined in srfi-1 at all for
functionality that is clearly desirable even for implementing behavior
required by some functions in srfi-1.  Such functions can either be made
private, requiring the user to write his own, less efficient function
whenever he faces the same problem.  Or they can be provided publicly in
which case it is unlikely that the user will not grow dependent on them
and "we can never go back".

The reference implementation chose the behavior I propose.  The naming
choice of "length+" in srfi-1 has been made in a manner suggesting that
only one such additional length operator is needed as it is rather
generic and not just restricted to circular and dotted lists.

Basically, srfi-1 is sort of a have-one's-cake-and-eat-it-too
specification: the ability to throw errors on dotted lists is explicitly
mentioned as possibly helpful when a user mixes up arguments to
functions like fold, while at the same time there is no framework for
the explicit "accept dotted list also" kind of behavior put forward by
functions like drop-right or take-right.

It is also noteworthy that the reference implementation defines "length"
on dotted lists rather than erroring out, and in general is pretty
lenient regarding using dotted instead of proper lists.

This _is_ an ugly mess.  It is my personal opinion that at least with
regard to length+ we are better off following the reference
implementation.  I don't see the point in having something like

(map + '(1 2) '(1 2 3 . 4))

error out: it did not do so before your patch and definitely has an
obvious result.  I am not enthused over allowing

(map + '(1 2) 5) => '()

while balking at

(map + 5)

but with a single list, the "shortest finite list" clause does not
really come into play, and indeed the "help avoid user error early"
rationale seems particularly applicable.

My first implementation of take-right/drop-right just used "count" as it
does not seem to make sense to talk about dropping n elements from the
end of a dotted list given that even functions like "count" and "length"
are unspecified for dotted lists.

I was, however, surprised to figure out later that this is one area of
srfi-1 where lists were explicitly allowed to be dotted but not
circular.

>> At any rate, what I am getting at is that I was going to submit the
>> following patch as a part of a series fixing other bugs, bugs that I
>> need a working "get the length of a dotted list" operator for.  We
>> don't have any such operator in GUILE, and that's awkward.
>
> It might be helpful to add such a procedure, but I don't think
> 'length+' should be it.

I don't think the entire incoherent mess of what is and what is not
described that makes up srfi-1 should be like it is.  But that's what we
have to deal with.  Following the reference implementation in this
regard seems like the smallest evil to me.  If the standard had kept its
fingers off specifying behavior for _all_ list-like operations
(including the take-right and drop-right operators) we would not be in
this situation.  Whatever escape we choose, people will get to rely on
it.

-- 
David Kastrup