Subject: bug#15117: 24.3.50; doc of `(forward|backward)-*': state return value

From: Drew Adams <[email-masked]>
Date: Mon, 10 Feb 2014 22:43:08 -0800 (PST)

> > Motion functions are not what is typically meant by a
> > side-effect function.

In Emacs, in the sense of modifying buffer contents.  That was
what I meant.  No, I was not clear enough.  But it doesn't really
matter.  That is anyway *not* a criterion I use for whether a Lisp
function should have a defined and documented return value.

My criterion for that is just whether such a value is useful and
can be counted on.  If so, then I say we should let users know that
they can count on it.  Simple as that.

> Why not? Functions intended to move the point are as prototypically
> side-effect functions as you can get. That goto-char returns
> POSITION is a moderately useful, but not-at-all necessary commodity.
> goto-char moving the point as a side effect is its whole raison d'être.

Agreed; it is.  And the resulting position is thus an important part
of its effect.  And it is handy to use that value directly.  It always
has been.  There is nothing special about this.  And nothing special
about `goto-char' or `skip-chars-forward' vs `forward-char'.  That's
the point.

Are you arguing not to document `goto-char's return value, as well?
And so to discourage its use?  After all, one doesn't need to depend
on it - it's certainly enough to depend on the side effect and then
call `point' to get the new position.

If so, go for it.  Then what have you gained?  Greater liberty
for the implementation to change?  Bof.  More readable code?  Bof.
Code that is more functional or side-effect free?  Certainly not.

> > They do not change the contents of the buffer, for
> > example, in the sense of `buffer-modified-p'.
> 
> Why would you restrict the definition of "side effects" to
> changing the buffer?

I don't, actually.  Whether something constitutes a "side effect"
is relative.

This is what I wrote, which engendered the current excitement:

 If, for some special (good) reason, code should not rely on the
 return value of some function, then this fact should be stated
 explicitly in the doc: "This function is used only for its side
 effects; the return value is undefined."  This is Lisp, not C -
 return values are the norm, not the exception.

I was suggesting boilerplate text similar to what we often write
for functions, such as `mapc', where we point out that the return
value is not to be relied on.

We mention side effects here because if the return value is not
to be depended on then what else is there, besides the side effect?
Nada.  We let users know that side effects are (necessarily) the
"whole raison d'être" in that case.

That is precisely what the Common Lisp doc does, for example:
call attention to the relatively *few* cases where the return
value is *not* to be counted on.  Lisps have always tended to
provide reasonable return values as a general rule.  Regardless,
BTW, of whether a given function happens to perform side effects.

It is not because a function performs side effects that its
return value should not be counted on (and so documented).

It is because the return value of a given function should not
be counted on that it should not be documented (actually, it
should be documented that the return value cannot be counted
on).  And such functions are therefore used for side effect only.

There are certain Common Lisp "functions" for which no return
value is documented, and which are _called out as such_,
explicitly.  (And the doc typically says something like what
I said above: Use this for its side effects only; do not count
on its return value being anything in particular (it can vary
among implementations etc.)

Such functions are the exception to the rule - in spite of the
fact that most Common Lisp "functions" can have side effects.
And such an exception is often for reasons of implementation -
in particular, to allow different implementors more freedom of
implementation.  (Common Lisp, unlike GNU Emacs, is intended
to have multiple implementations, including for unforeseen
situations and uses.)

So really the question has nothing particularly to do with side
effects, beyond the concerns just mentioned.  I should not have
mentioned not-even-modifying-buffer-contents in this context.

It's all about what we want for programmers.  Should they get
a useful return value for the given function or not?  That's
the only question.

Consider `when', for instance.  I, for one, adopt the convention
often used with Common Lisp of NOT using the return value.  Why?
To signal the programmer intention that what is happening is for
the side effects and not for the return value - i.e., that in
that particular context, the return value is not important. IOW,
this is to help readers of the code; nothing more.

That convention makes sense for `when' and `unless' especially
because there are alternatives to signal just the opposite
programmer intention: I use `if', `and', or `or' when the
return value is significant, precisely to show that, for
readability.

If you were to argue that we should not document the return
value of `when' or `unless' you would get no argument from
me.  (Well, actually, I would again suggest saying explicitly
that one should not count on the return value.)

This, in spite of the fact that `if', `and', and `or' can,
just like `when' and `unless', be used in code that produces
side effects.  It's really not about side effects at all.

(I find it ironic that some of those who've jumped on this
to scream that programmers should not be able to count on
the return value of `forward-sexp' nevertheless count on
the return value of `when' in the code they write, something
I won't do.)

So I am not against documenting return values for some, even
most, functions that perform side effects, including effects
that might modify the buffer, if it can be shown that:
(a) there is no special benefit (e.g. wrt implementation or
for users) to *not* guaranteeing a known return value for
users or (b) there is no particularly useful value to return.

In the case of the motion functions, there is a useful value
to return: the destination position.  And my question about
that is "Why not?".  I've seen no response to that question,
so far.  Why not?

> `recenter' has no documented return value, and does not
> modify the buffer. Would you deny that it exists to recenter
> as a side effect?

No more than I would deny that `goto-char' or `skip-chars-forward'
exists to move point.  I don't see why that prohibits providing
the new `point' (or perhaps even the starting position) as a
useful return value, however.

I'm not sure the resulting position is particularly useful in
the case of `recenter', but if you proposed returning it and
documenting that, I might not object.  Why not?  I don't have
a great reason why not for `recenter' - do you?

Let's be clear.  No one is proposing that additional side
effects be introduced anywhere here!  This is not
pure-function-vs-procedure.  These are all procedures.
They move point.  The position attained is in most cases
a reasonable return value, and costs little or nothing to
return.  So why not?  That's all.

It is natural to return a value readily available from the
implementation.  I would not propose that a definition go
out of its way to obtain a useful value to return in such
cases.  But it seems obvious to me that there is no a priori
reason for a simple motion function *not* to return a known
value such as the position moved to.

I gave several examples of motion functions where we already
do that.  Why do we?  Why shouldn't we?

Look at those functions.  See if you would really argue that
we should not document their return values and let users
depend on them.  See if you want to shout "side effects!"
or some other battle cry as a reason for making such a change.

Then tell me what we would gain by that.  Just what do we
gain by not returning the new position or not telling users
that we return it?

That's really the only question here.  And I haven't heard a
single argument about that yet.  Forget about whether this or
that function performs side effects.  Please answer the
question of why we should not let users write code that
counts on the moved-to position as a return value.