Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

(read-from-string "#.(values) 42")

12 views
Skip to first unread message

Pascal Bourguignon

unread,
Sep 21, 2006, 2:14:45 PM9/21/06
to

Considering:

2.2 Reader Algorithm

The reader macro function may return zero values or one value. If
one value is returned, then that value is returned as the result
of the read operation; the algorithm is done. If zero values are
returned, then step 1 is re-entered.


2.4.8.6 Sharpsign Dot

#.foo is read as the object resulting from the evaluation of the
object represented by foo. The evaluation is done during the read
process, when the #. notation is encountered. The #. syntax
therefore performs a read-time evaluation of foo.


Function EVAL

eval form => result*

results---the values yielded by the evaluation of form.


Therefore, I'd expect (read-from-string "#.(values) 42") to return 42.


sbcl 0.9.12, cmucl 19c and alegro cl 8.0 return 1 as expected.

clisp 2.39, ecl 0.9g and gcl 2.6.7 return NIL, surprizingly.


Could we agree that when *read-supress* is NIL,
(read-from-string "#.(values) 42") should return 42?

% clall \
'(let ((*read-suppress* nil)) (read-from-string "#.(values) 42"))' \
'(let ((*read-suppress* t )) (read-from-string "#.(values) 42"))'

------------------------------------------------------------------------
CLISP 2.39 (2006-07-16) (built 3364813332) (memory 3364813914)


(LET ((*READ-SUPPRESS* NIL)) (READ-FROM-STRING "#.(values) 42"))
--> NIL ;
10


(LET ((*READ-SUPPRESS* T)) (READ-FROM-STRING "#.(values) 42"))
--> NIL ;
10

------------------------------------------------------------------------
SBCL 0.9.12


(LET ((*READ-SUPPRESS* NIL))
(READ-FROM-STRING "#.(values) 42"))
--> 42 ;
13


(LET ((*READ-SUPPRESS* T))
(READ-FROM-STRING "#.(values) 42"))
--> NIL ;
10

------------------------------------------------------------------------
CMU Common Lisp 19c (19C)


(LET ((*READ-SUPPRESS* NIL))
(READ-FROM-STRING "#.(values) 42"))
--> 42 ;
13


(LET ((*READ-SUPPRESS* T))
(READ-FROM-STRING "#.(values) 42"))
--> NIL ;
11

------------------------------------------------------------------------
GNU Common Lisp (GCL) GCL 2.6.7


(LET ((*READ-SUPPRESS* NIL)) (READ-FROM-STRING "#.(values) 42"))
--> NIL ;
10


(LET ((*READ-SUPPRESS* T)) (READ-FROM-STRING "#.(values) 42"))
--> NIL ;
10

------------------------------------------------------------------------
ECL 0.9g


(LET ((*READ-SUPPRESS* NIL))
(READ-FROM-STRING "#.(values) 42"))
--> NIL ;
11


(LET ((*READ-SUPPRESS* T))
(READ-FROM-STRING "#.(values) 42"))
--> NIL ;
11

------------------------------------------------------------------------
International Allegro CL Free Express Edition 8.0 [Linux (x86)] (Jun 6, 2006 16:01)


(LET ((*READ-SUPPRESS* NIL)) (READ-FROM-STRING "#.(values) 42"))
--> 42 ;
13


(LET ((*READ-SUPPRESS* T)) (READ-FROM-STRING "#.(values) 42"))
--> NIL ;
11

------------------------------------------------------------------------

--
__Pascal Bourguignon__ http://www.informatimago.com/
You never feed me.
Perhaps I'll sleep on your face.
That will sure show you.

Kalle Olavi Niemitalo

unread,
Sep 21, 2006, 5:30:44 PM9/21/06
to
Pascal Bourguignon <p...@informatimago.com> writes:

> 2.4.8.6 Sharpsign Dot
>
> #.foo is read as the object resulting from the evaluation of the
> object represented by foo. The evaluation is done during the read
> process, when the #. notation is encountered. The #. syntax
> therefore performs a read-time evaluation of foo.

I think the wording "the object" can be interpreted to mean
the primary value will be used.

Possibly no real program cares what #.(values) does.
However, something like #.(floor 65536 pi) may occur in a program.
The result of reading this syntax may now be undefined in principle,
but implementations agree that only the primary value gets used.
If you modified CLISP to make #. propagate all values,
then such expressions would begin failing:

*** - READ from #<INPUT CONCATENATED-STREAM #<INPUT STRING-INPUT-STREAM>
#<IO TERMINAL-STREAM>>: dispatch macro character definition for #\.
after #\# may not return 2 values, only one value.

So you would have to either remove this check from CLISP
or onerously require users to write #.(values (floor 65536 pi)).

An EXPLICITLY-VAGUE option may be the safest one.
Users who want a specific behaviour can define their own reader macros.

Rob Warnock

unread,
Sep 22, 2006, 1:32:03 AM9/22/06
to
Kalle Olavi Niemitalo <k...@iki.fi> wrote:
+---------------

| Possibly no real program cares what #.(values) does.
+---------------

No, but it certainly cares what "#-(and) (dont read me)" does, e.g.:

cmu> (read-from-string "#-(and) (dont read me) :read-me")

:READ-ME
31
cmu>

It was my understanding that the whole "#.(values)" functionality
is there specifically so feature expressions will work [or at least
was put there with them in mind].

Or said another way, given that you have to have a way for "#+" and
"#-" to suppress things, the principle of orthogonal design suggests
allowing *all* readmacros to use the same mechanism, if they so choose.


-Rob

-----
Rob Warnock <rp...@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607

Kalle Olavi Niemitalo

unread,
Sep 22, 2006, 2:59:50 AM9/22/06
to
rp...@rpw3.org (Rob Warnock) writes:

> Or said another way, given that you have to have a way for "#+" and
> "#-" to suppress things, the principle of orthogonal design suggests
> allowing *all* readmacros to use the same mechanism, if they so choose.

Sure, if the #. readmacro returns no values for some input, then
READ must keep reading, as if #+(or)t had been seen. I don't
think anybody contested that.

The issue was whether the #. readmacro should return the same
multiple values it gets from EVAL, and how requiring this might
hurt compatibility.

Rob Warnock

unread,
Sep 22, 2006, 4:06:23 AM9/22/06
to
Kalle Olavi Niemitalo <k...@iki.fi> wrote:
+---------------
| The issue was whether the #. readmacro should return the same
| multiple values it gets from EVAL, and how requiring this might
| hurt compatibility.
+---------------

Uh... If you look at the "Subject:", you'll see that the original
issue was actually some implementations [which the OP listed] that
return NIL for (READ-FROM-STRING "#.(VALUES) 42") instead of 42!!

[I'm not sure how/where the "spreading multiple values" sidetrack
crept in...]

Pascal Bourguignon

unread,
Sep 22, 2006, 10:46:41 AM9/22/06
to
rp...@rpw3.org (Rob Warnock) writes:

> Kalle Olavi Niemitalo <k...@iki.fi> wrote:
> +---------------
> | The issue was whether the #. readmacro should return the same
> | multiple values it gets from EVAL, and how requiring this might
> | hurt compatibility.
> +---------------
>
> Uh... If you look at the "Subject:", you'll see that the original
> issue was actually some implementations [which the OP listed] that
> return NIL for (READ-FROM-STRING "#.(VALUES) 42") instead of 42!!
>
> [I'm not sure how/where the "spreading multiple values" sidetrack
> crept in...]

That's because reader macros can return 0 or 1 value.

Indeed, if they return two or more values, only the first one is kept
and returned by READ. The question is what happens when they return 0
values. The reader algorithm specifies what happens. But in some
implementations, #. doesn't do the right thing.


Still, I don't see any advantage of having implementations diverge on
this point. It would be preferable if all implementation returned the
same for: (read-from-string "#.(values) 42") [and I'd prefer it to be 42].

On the other hand, we could say that #. is implementation specific and
nothing prevents programs that want to be portable to provide their own
implementation of this reader macro.

--
__Pascal Bourguignon__ http://www.informatimago.com/

Until real software engineering is developed, the next best practice
is to develop with a dynamic system that has extreme late binding in
all aspects. The first system to really do this in an important way
is Lisp. -- Alan Kay

Ron Garret

unread,
Sep 22, 2006, 4:26:25 PM9/22/06
to
In article <87bqp83...@thalassa.informatimago.com>,
Pascal Bourguignon <p...@informatimago.com> wrote:

> Still, I don't see any advantage of having implementations diverge on
> this point. It would be preferable if all implementation returned the
> same for: (read-from-string "#.(values) 42") [and I'd prefer it to be 42].

Why? (values) is equivalent to NIL is all other contexts (except those
specifically designed to accept multiple values). Why should #. be any
different?

rg

Pascal Bourguignon

unread,
Sep 22, 2006, 4:50:32 PM9/22/06
to
Ron Garret <rNOS...@flownet.com> writes:

To be consistent with #+ and #-, because it's called in a context
where it is already expected to get 0 or 1 values, and because to have
it return NIL you have to write more code.

#. is specified to do that:

(defun reader-dispatch-macro-read-eval (stream sub-char arg)
(declare (ignore sub-char arg))
(if *read-eval*
(eval (read stream t nil t))
(error 'reader-error :stream stream)))

The implementations who return NIL for it have to write more complex
code, like:

(defun reader-dispatch-macro-read-eval (stream sub-char arg)
(declare (ignore sub-char arg))
(if *read-eval*
(values (eval (read stream t nil t)))
(error 'reader-error :stream stream)))


With a well behavied #., instead of writing:

#+(cl:if (cl-user::some-condition-p) '(and) '(or)) something

we could write:

#.(if (some-condition-p) 'something (values))


--
__Pascal Bourguignon__ http://www.informatimago.com/

Nobody can fix the economy. Nobody can be trusted with their finger
on the button. Nobody's perfect. VOTE FOR NOBODY.

Christophe Rhodes

unread,
Sep 22, 2006, 4:50:44 PM9/22/06
to
Ron Garret <rNOS...@flownet.com> writes:

Because the reader is specified to treat read macros which return 0
values specially? That would seem to be a good reason to suggest that
the read macro for #. to preserve the zero-value-ness, if any.

Christophe

Geoffrey Summerhayes

unread,
Sep 22, 2006, 4:53:38 PM9/22/06
to

That would disallow users from creating a reader macro that could
discard it's input. If you want to give that ability, #.(values) should
do
the same.

Think of it as empowerment.

---
Geoff

Barry Margolin

unread,
Sep 22, 2006, 6:57:50 PM9/22/06
to
In article <87slij1...@thalassa.informatimago.com>,
Pascal Bourguignon <p...@informatimago.com> wrote:

The problem may be that you need this extra code to prevent it from
returning more than 1 value in the following case:

(read-from-string "#.(values 1 2)")

The spec says that reader macros are only permitted to return 0 or 1
values.

So to get it to return 0 values in the #.(values) case, but prevent 2+
values, you need even *more* code:

(defun read-dispatch-macro-read-eval (stream sub-char arg)


(declare (ignore sub-char arg))
(if *read-eval*

(let ((values (values-list (eval (read stream t nil t)))))
(if values
(car values)
(values)))
(error 'reader-error :stream stream)))

--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***

Pascal Bourguignon

unread,
Sep 22, 2006, 7:15:27 PM9/22/06
to
Barry Margolin <bar...@alum.mit.edu> writes:
> The problem may be that you need this extra code to prevent it from
> returning more than 1 value in the following case:
>
> (read-from-string "#.(values 1 2)")
>
> The spec says that reader macros are only permitted to return 0 or 1
> values.
>
> So to get it to return 0 values in the #.(values) case, but prevent 2+
> values, you need even *more* code:
>
> (defun read-dispatch-macro-read-eval (stream sub-char arg)
> (declare (ignore sub-char arg))
> (if *read-eval*
> (let ((values (values-list (eval (read stream t nil t)))))
> (if values
> (car values)
> (values)))
> (error 'reader-error :stream stream)))

Well, usually the limits on the number of return values are enacted on
the receiving side.

(let ((values (multiple-value-list (funcall reader-macro))))
(when (null values) (go :step-1))
(return-from read (first values)))


--
__Pascal Bourguignon__ http://www.informatimago.com/

This is a signature virus. Add me to your signature and help me to live.

Barry Margolin

unread,
Sep 22, 2006, 7:30:34 PM9/22/06
to
In article <87odt74...@thalassa.informatimago.com>,
Pascal Bourguignon <p...@informatimago.com> wrote:

> Barry Margolin <bar...@alum.mit.edu> writes:
> > The problem may be that you need this extra code to prevent it from
> > returning more than 1 value in the following case:
> >
> > (read-from-string "#.(values 1 2)")
> >
> > The spec says that reader macros are only permitted to return 0 or 1
> > values.
> >
> > So to get it to return 0 values in the #.(values) case, but prevent 2+
> > values, you need even *more* code:
> >
> > (defun read-dispatch-macro-read-eval (stream sub-char arg)
> > (declare (ignore sub-char arg))
> > (if *read-eval*
> > (let ((values (values-list (eval (read stream t nil t)))))
> > (if values
> > (car values)
> > (values)))
> > (error 'reader-error :stream stream)))
>
> Well, usually the limits on the number of return values are enacted on
> the receiving side.
>
> (let ((values (multiple-value-list (funcall reader-macro))))
> (when (null values) (go :step-1))
> (return-from read (first values)))

Probably, but the spec doesn't require this. It says that read macros
may return 0 or 1 values. So it's an error for a reader macro to return
more than 1 value, and there's no requirement for the implementation to
handle this properly.

Of course, since the reader and the #. macro are both part of the
implementation, they can take advantage of internal knowledge of each
other. If the reader is as you describe, #. can simply do (eval (read)).

Ron Garret

unread,
Sep 27, 2006, 1:57:06 AM9/27/06
to
In article <1158958417.8...@e3g2000cwe.googlegroups.com>,
"Geoffrey Summerhayes" <sum...@hotmail.com> wrote:

> Ron Garret wrote:
> > In article <87bqp83...@thalassa.informatimago.com>,
> > Pascal Bourguignon <p...@informatimago.com> wrote:
> >
> > > Still, I don't see any advantage of having implementations diverge on
> > > this point. It would be preferable if all implementation returned the
> > > same for: (read-from-string "#.(values) 42") [and I'd prefer it to be 42].
> >
> > Why? (values) is equivalent to NIL is all other contexts (except those
> > specifically designed to accept multiple values). Why should #. be any
> > different?
>
> That would disallow users from creating a reader macro that could
> discard it's input.

No it wouldn't, it would just disallow the #. reader macro from
discarding its input, which seems like the Right Thing to me.

rg

Alan Crowe

unread,
Sep 27, 2006, 9:34:18 AM9/27/06
to
Ron Garret <rNOS...@flownet.com> writes:

These questions don't make sense. Superficially they appeal
to the notion that computer programming languages should be
uniform: similar constructs should do similar things,
similar operations should be expressed in similar ways.

Computer programming languages are artifacts and
tools. Their designers intend them to be useful. So the
notion of similarity appropriate to making a computer
programming language uniform is similarity of purpose. It
only makes sense to ask "Why should #. be any different from
contructs with a similar purpose?" If you don't say what you
think the purpose is, you aren't saying anything at all.

Well, what do I think is the purpose of

Upon encountering a macro character, the Lisp reader
calls its reader macro function, which parses one
specially formatted object from the input stream. The
function either returns the parsed object, or else it
returns no values to indicate that the characters
scanned by the function are being ignored (e.g., in the
case of a comment). Examples of macro characters are
backquote, single-quote, left-parenthesis, and
right-parenthesis.

I think the idea is to permit macro characters that
side-effect the read time environment (or not - but comments
are built in) but do not contribute anything to the
expression being read.

What is the purpose of #. ? It obviously includes

For an object that does not have a convenient printed
representation, a form that computes the object can be
given using the #. notation.

because that is explicit in the spec, but it has other uses
as well. It lets you run code at read time, just like a
macro character does. Since it has a similar purpose it
should work in a similar way. Given that macro characters
let you do this:

CL-USER> (set-macro-character #\! (lambda(stream char)
(declare (ignore char))
(write (read stream))))

T

CL-USER> '(1 2 ! "Half Way!" 3 4)
"Half Way!"
(1 2 "Half Way!" 3 4)

CL-USER> (set-macro-character #\! (lambda(stream char)
(declare (ignore char))
(write (read stream))
(values)))

T

CL-USER> '(1 2 ! "Half Way!" 3 4)
"Half Way!"
(1 2 3 4)

Then the doctrine of uniformity dictates that #. should
behave in a similar way.

CL-USER> '(1 2 #.(write "Half way!") 3 4)
"Half way!"
(1 2 "Half way!" 3 4)

CL-USER> '(1 2 #.(progn (write "Half way!")
(values))
3 4)
"Half way!"
(1 2 3 4)

The doctrine of orthogonality dictates the same
point. Whether code that is run at read time contributes to
the data structure or not should be independent of how it
was invoked, whether read macro or #.

Another way of thinking about it is to spot that #. is in a
sense the same kind of construct as eval-when. They are both
escape hatches, #. from the reader, eval-when from the file compiler.

#.(progn (this)(that))

is like

(eval-when (:compile-toplevel :load-toplevel)
(this)
(that))

because it runs code and contributes to the data structure
being read/object file being written

while

#.(progn (this)(that)(values))

is like

(eval-when (:compile-toplevel)
(this)
(that))

because it runs code without adding anything to the data
structure being read/object file being written.

#.(values) doesn't put a nil in the data structure being
read, to be the same as (eval-when (:compile-toplevel))
which doesn't put irritating crud in the object file.

Alan Crowe
Edinburgh
Scotland

Geoffrey Summerhayes

unread,
Sep 27, 2006, 11:54:00 AM9/27/06
to

Ron Garret wrote:
> In article <1158958417.8...@e3g2000cwe.googlegroups.com>,
> "Geoffrey Summerhayes" <sum...@hotmail.com> wrote:
>
> > Ron Garret wrote:
> > > In article <87bqp83...@thalassa.informatimago.com>,
> > > Pascal Bourguignon <p...@informatimago.com> wrote:
> > >
> > > > Still, I don't see any advantage of having implementations diverge on
> > > > this point. It would be preferable if all implementation returned the
> > > > same for: (read-from-string "#.(values) 42") [and I'd prefer it to be 42].
> > >
> > > Why? (values) is equivalent to NIL is all other contexts (except those
> > > specifically designed to accept multiple values). Why should #. be any
> > > different?
> >
> > That would disallow users from creating a reader macro that could
> > discard it's input.
>
> No it wouldn't, it would just disallow the #. reader macro from
> discarding its input, which seems like the Right Thing to me.

Yes it would, the best you could do would be to write a reader
macro that replaced the input with NIL, because the only way
to return zero values is (values) and you've disallowed that.

The only way for "The reader macro function may return zero
values or one value." to work is if the reader is aware of multiple
values.

---
Geoff

Ron Garret

unread,
Sep 27, 2006, 1:16:59 PM9/27/06
to
In article <861wpx1...@cawtech.freeserve.co.uk>,
Alan Crowe <al...@cawtech.freeserve.co.uk> wrote:

> Ron Garret <rNOS...@flownet.com> writes:
>
> > In article <87bqp83...@thalassa.informatimago.com>,
> > Pascal Bourguignon <p...@informatimago.com> wrote:
> >
> > > Still, I don't see any advantage of having implementations diverge on
> > > this point. It would be preferable if all implementation returned the
> > > same for: (read-from-string "#.(values) 42") [and I'd prefer it to be 42].
> >
> > Why? (values) is equivalent to NIL is all other contexts (except those
> > specifically designed to accept multiple values). Why should #. be any
> > different?
> >
> > rg
>
> These questions don't make sense.

[Much snippage]

I would have put it slightly differently and simply said that reader
macros ARE a context specifically designed to accept multiple values.

But your point is well taken.

rg

Ron Garret

unread,
Sep 27, 2006, 1:22:42 PM9/27/06
to
In article <1159372440.2...@m7g2000cwm.googlegroups.com>,
"Geoffrey Summerhayes" <sum...@hotmail.com> wrote:

> Ron Garret wrote:
> > In article <1158958417.8...@e3g2000cwe.googlegroups.com>,
> > "Geoffrey Summerhayes" <sum...@hotmail.com> wrote:
> >
> > > Ron Garret wrote:
> > > > In article <87bqp83...@thalassa.informatimago.com>,
> > > > Pascal Bourguignon <p...@informatimago.com> wrote:
> > > >
> > > > > Still, I don't see any advantage of having implementations diverge on
> > > > > this point. It would be preferable if all implementation returned
> > > > > the
> > > > > same for: (read-from-string "#.(values) 42") [and I'd prefer it to be
> > > > > 42].
> > > >
> > > > Why? (values) is equivalent to NIL is all other contexts (except those
> > > > specifically designed to accept multiple values). Why should #. be any
> > > > different?
> > >
> > > That would disallow users from creating a reader macro that could
> > > discard it's input.
> >
> > No it wouldn't, it would just disallow the #. reader macro from
> > discarding its input, which seems like the Right Thing to me.
>
> Yes it would, the best you could do would be to write a reader
> macro that replaced the input with NIL, because the only way
> to return zero values is (values) and you've disallowed that.

No, I've only disallowed it in the #. reader macro. I've not disallowed
it in any other reader macro.

> The only way for "The reader macro function may return zero
> values or one value." to work is if the reader is aware of multiple
> values.

I think you're conflating two different issues. One is whether reader
macros in general can return zero values and thereby not contribute
anything to the data structure being read. That they can do this is not
in dispute (otherwise #+ and #- would not work).

What is in dispute is whether the #. reader macro specifically should
avail itself of this capability, i.e. whether the reader macro function
for #. should be (eval (read stream)) or (identity (eval (read
stream))). That is a design issue for which reasonable arguments exist
on both sides IMHO.

rg

Geoffrey Summerhayes

unread,
Sep 27, 2006, 2:17:40 PM9/27/06
to

Ron Garret wrote:
> In article <1159372440.2...@m7g2000cwm.googlegroups.com>,

>
> I think you're conflating two different issues. One is whether reader
> macros in general can return zero values and thereby not contribute
> anything to the data structure being read. That they can do this is not
> in dispute (otherwise #+ and #- would not work).
>
> What is in dispute is whether the #. reader macro specifically should
> avail itself of this capability, i.e. whether the reader macro function
> for #. should be (eval (read stream)) or (identity (eval (read
> stream))). That is a design issue for which reasonable arguments exist
> on both sides IMHO.

IMO, adding another inconsistency when none is needed is just
annoying: (values) works in all reader macros except #.(values)
I'd much prefer it to work as Pascal has outlined, after all if I want
NIL, I can write #.nil, it saves keystrokes. :-)

---
Geoff

Barry Margolin

unread,
Sep 27, 2006, 3:41:00 PM9/27/06
to
In article <1159381060....@d34g2000cwd.googlegroups.com>,
"Geoffrey Summerhayes" <sum...@hotmail.com> wrote:

> Ron Garret wrote:
> > In article <1159372440.2...@m7g2000cwm.googlegroups.com>,
> >
> > I think you're conflating two different issues. One is whether reader
> > macros in general can return zero values and thereby not contribute
> > anything to the data structure being read. That they can do this is not
> > in dispute (otherwise #+ and #- would not work).
> >
> > What is in dispute is whether the #. reader macro specifically should
> > avail itself of this capability, i.e. whether the reader macro function
> > for #. should be (eval (read stream)) or (identity (eval (read
> > stream))). That is a design issue for which reasonable arguments exist
> > on both sides IMHO.
>
> IMO, adding another inconsistency when none is needed is just
> annoying: (values) works in all reader macros except #.(values)

What does this mean? What other reader macros allow the end user to
tell the macro how many values it should return? #. is unique in this
regard, so you can't reason by analogy.

What should #.(values 1 2 3) do?

Ron Garret

unread,
Sep 27, 2006, 3:53:48 PM9/27/06
to
In article <1159381060....@d34g2000cwd.googlegroups.com>,
"Geoffrey Summerhayes" <sum...@hotmail.com> wrote:

> Ron Garret wrote:
> > In article <1159372440.2...@m7g2000cwm.googlegroups.com>,
> >
> > I think you're conflating two different issues. One is whether reader
> > macros in general can return zero values and thereby not contribute
> > anything to the data structure being read. That they can do this is not
> > in dispute (otherwise #+ and #- would not work).
> >
> > What is in dispute is whether the #. reader macro specifically should
> > avail itself of this capability, i.e. whether the reader macro function
> > for #. should be (eval (read stream)) or (identity (eval (read
> > stream))). That is a design issue for which reasonable arguments exist
> > on both sides IMHO.
>
> IMO, adding another inconsistency when none is needed is just
> annoying: (values) works in all reader macros except #.(values)

Huh? You mean #\(values) works? #'(values)? You must be using a
different definition of the word "works" than most people.

The interesting case IMO is not #.(values) but rather:

(1 2 #.(foo) 4 5)

Personally I think it would be useful to be able to assume
unconditionally that the above reads as a list of length 5. Another
example:

(let ((x #.(foo)) ...)

I think it's useful that the above not break if foo happens to return
zero values.

rg

Geoffrey Summerhayes

unread,
Sep 27, 2006, 4:43:10 PM9/27/06
to

Barry Margolin wrote:
> In article <1159381060....@d34g2000cwd.googlegroups.com>,
> "Geoffrey Summerhayes" <sum...@hotmail.com> wrote:
>
> > Ron Garret wrote:
> > > In article <1159372440.2...@m7g2000cwm.googlegroups.com>,
> > >
> > > I think you're conflating two different issues. One is whether reader
> > > macros in general can return zero values and thereby not contribute
> > > anything to the data structure being read. That they can do this is not
> > > in dispute (otherwise #+ and #- would not work).
> > >
> > > What is in dispute is whether the #. reader macro specifically should
> > > avail itself of this capability, i.e. whether the reader macro function
> > > for #. should be (eval (read stream)) or (identity (eval (read
> > > stream))). That is a design issue for which reasonable arguments exist
> > > on both sides IMHO.
> >
> > IMO, adding another inconsistency when none is needed is just
> > annoying: (values) works in all reader macros except #.(values)
>
> What does this mean? What other reader macros allow the end user to
> tell the macro how many values it should return? #. is unique in this
> regard, so you can't reason by analogy.

Well there's the argument that #+ and #- return zero or one values
depending on conditions that an end user can determine.

If you're not convinced that's a valid argument, what about #!, #?,
#[, #], #{, and #} ?

Should the end user be allowed to create his own read-time conditional
macro like #+? If so, why should #.(values) do the same thing as #.nil?

> What should #.(values 1 2 3) do?

I'd prefer 1 over 1 2 3 or an error. All implementations I tested
seem to agree in this case, thank goodness. De facto standard.

2.2 could really do with a rewrite to make both issues clearer, but
I feel Pascal's interpretation is closer to the original intent.

---
Geoff

Christophe Rhodes

unread,
Sep 27, 2006, 4:44:37 PM9/27/06
to
Ron Garret <rNOS...@flownet.com> writes:

> (let ((x #.(foo)) ...)
>
> I think it's useful that the above not break if foo happens to return
> zero values.

It doesn't break under either interpretation of #.'s behaviour in
these circumstances.

Christophe

Ron Garret

unread,
Sep 27, 2006, 6:35:16 PM9/27/06
to
In article <sqd59hc...@cam.ac.uk>,
Christophe Rhodes <cs...@cam.ac.uk> wrote:

Hm, good point. OK, let's try that again. How about:

(defconstant x #.(foo))

rg

Pascal Bourguignon

unread,
Sep 27, 2006, 6:46:05 PM9/27/06
to
Barry Margolin <bar...@alum.mit.edu> writes:
> What should #.(values 1 2 3) do?

There doesn't seem to be any ambiguity here, all implementations return 1:


[pjb@thalassa lisp]$ clall '(read-from-string "#.(values 1 2 3)")'

------------------------------------------------------------------------
CLISP 2.39 (2006-07-16) (built 3364813332) (memory 3364813914)


(READ-FROM-STRING "#.(values 1 2 3)")
--> 1 ;
16

------------------------------------------------------------------------
SBCL 0.9.12


(READ-FROM-STRING "#.(values 1 2 3)")
--> 1 ;
16

------------------------------------------------------------------------
CMU Common Lisp 19c (19C)


(READ-FROM-STRING "#.(values 1 2 3)")
--> 1 ;
16

------------------------------------------------------------------------
GNU Common Lisp (GCL) GCL 2.6.7


(READ-FROM-STRING "#.(values 1 2 3)")
--> 1 ;
16

------------------------------------------------------------------------
ECL 0.9g


(READ-FROM-STRING "#.(values 1 2 3)")
--> 1 ;
16

------------------------------------------------------------------------
International Allegro CL Free Express Edition 8.0 [Linux (x86)] (Jun 6, 2006 16:01)


(READ-FROM-STRING "#.(values 1 2 3)")
--> 1 ;
16

------------------------------------------------------------------------

[pjb@thalassa lisp]$


--
__Pascal Bourguignon__ http://www.informatimago.com/

CAUTION: The mass of this product contains the energy equivalent of
85 million tons of TNT per net ounce of weight.

Pascal Bourguignon

unread,
Sep 27, 2006, 6:48:34 PM9/27/06
to
Ron Garret <rNOS...@flownet.com> writes:
> The interesting case IMO is not #.(values) but rather:
>
> (1 2 #.(foo) 4 5)

I'd prefer it to be able to handle:

'(1 2 #.(if some-condition-p (value 3) (values)) 4 5)


> Personally I think it would be useful to be able to assume
> unconditionally that the above reads as a list of length 5. Another
> example:
>
> (let ((x #.(foo)) ...)
>
> I think it's useful that the above not break if foo happens to return
> zero values.

There's no breakage. Both:

(let ((x)) ...)

(let ((x 'some-value)) ...)

are valid.

--
__Pascal Bourguignon__ http://www.informatimago.com/

CAUTION: The mass of this product contains the energy equivalent of

Ron Garret

unread,
Sep 27, 2006, 9:10:06 PM9/27/06
to
In article <878xk5x...@thalassa.informatimago.com>,
Pascal Bourguignon <p...@informatimago.com> wrote:

> Ron Garret <rNOS...@flownet.com> writes:
> > The interesting case IMO is not #.(values) but rather:
> >
> > (1 2 #.(foo) 4 5)
>
> I'd prefer it to be able to handle:
>
> '(1 2 #.(if some-condition-p (value 3) (values)) 4 5)

Why not:

`(1 2 ,@#.(if some-condition-p (list 3) nil) 4 50

rg

Barry Margolin

unread,
Sep 27, 2006, 11:04:59 PM9/27/06
to
In article <878xk5x...@thalassa.informatimago.com>,
Pascal Bourguignon <p...@informatimago.com> wrote:

> Ron Garret <rNOS...@flownet.com> writes:
> > The interesting case IMO is not #.(values) but rather:
> >
> > (1 2 #.(foo) 4 5)
>
> I'd prefer it to be able to handle:
>
> '(1 2 #.(if some-condition-p (value 3) (values)) 4 5)
>
>
> > Personally I think it would be useful to be able to assume
> > unconditionally that the above reads as a list of length 5. Another
> > example:
> >
> > (let ((x #.(foo)) ...)
> >
> > I think it's useful that the above not break if foo happens to return
> > zero values.
>
> There's no breakage. Both:
>
> (let ((x)) ...)
>
> (let ((x 'some-value)) ...)
>
> are valid.

How about

(let ((x '#.(foo))) ...)

which is likely to be what you'd want to write (unless you know that FOO
always returns a self-evaluating object).

Pascal Bourguignon

unread,
Sep 28, 2006, 1:05:02 AM9/28/06
to
Ron Garret <rNOS...@flownet.com> writes:

The question is not ,@. As far as I know, all the implementation
behave the same for ,@.

The question is that implementations behave differently for #.(values).

We're trying to find what the standard mandates or wanted to mandate
with this respect.


--
__Pascal Bourguignon__ http://www.informatimago.com/

NEW GRAND UNIFIED THEORY DISCLAIMER: The manufacturer may
technically be entitled to claim that this product is
ten-dimensional. However, the consumer is reminded that this
confers no legal rights above and beyond those applicable to
three-dimensional objects, since the seven new dimensions are
"rolled up" into such a small "area" that they cannot be
detected.

Ron Garret

unread,
Sep 28, 2006, 1:33:41 AM9/28/06
to
In article <87odt0w...@thalassa.informatimago.com>,
Pascal Bourguignon <p...@informatimago.com> wrote:

> Ron Garret <rNOS...@flownet.com> writes:
>
> > In article <878xk5x...@thalassa.informatimago.com>,
> > Pascal Bourguignon <p...@informatimago.com> wrote:
> >
> >> Ron Garret <rNOS...@flownet.com> writes:
> >> > The interesting case IMO is not #.(values) but rather:
> >> >
> >> > (1 2 #.(foo) 4 5)
> >>
> >> I'd prefer it to be able to handle:
> >>
> >> '(1 2 #.(if some-condition-p (value 3) (values)) 4 5)
> >
> > Why not:
> >
> > `(1 2 ,@#.(if some-condition-p (list 3) nil) 4 50
>
> The question is not ,@. As far as I know, all the implementation
> behave the same for ,@.

Yes, which makes it a reliable substitute for the behavior you say you
want from #.


> The question is that implementations behave differently for #.(values).
>
> We're trying to find what the standard mandates or wanted to mandate
> with this respect.

That is simple to answer:

2.4.8.6 Sharpsign Dot

#.foo is read as THE OBJECT resulting from the evaluation of the object
represented by foo.

(Emphasis added.)

I take this to mean that the reader macro function for the #. reader
macro will always return a value (even if the form it evaluates doesn't).

rg

Pascal Bourguignon

unread,
Sep 28, 2006, 4:39:59 AM9/28/06
to
Ron Garret <rNOS...@flownet.com> writes:
> That is simple to answer:
>
> 2.4.8.6 Sharpsign Dot
>
> #.foo is read as THE OBJECT resulting from the evaluation of the object
> represented by foo.
>
> (Emphasis added.)
>
> I take this to mean that the reader macro function for the #. reader
> macro will always return a value (even if the form it evaluates doesn't).

Not so simple, if 3 of the 6 implementations I tested, including
Allegro 8.0, implement otherwise.

--
__Pascal Bourguignon__ http://www.informatimago.com/

"Our users will know fear and cower before our software! Ship it!
Ship it and let them flee like the dogs they are!"

Ron Garret

unread,
Sep 28, 2006, 1:04:43 PM9/28/06
to
In article <87k63ow...@thalassa.informatimago.com>,
Pascal Bourguignon <p...@informatimago.com> wrote:

> Ron Garret <rNOS...@flownet.com> writes:
> > That is simple to answer:
> >
> > 2.4.8.6 Sharpsign Dot
> >
> > #.foo is read as THE OBJECT resulting from the evaluation of the object
> > represented by foo.
> >
> > (Emphasis added.)
> >
> > I take this to mean that the reader macro function for the #. reader
> > macro will always return a value (even if the form it evaluates doesn't).
>
> Not so simple, if 3 of the 6 implementations I tested, including
> Allegro 8.0, implement otherwise.

You keep bouncing back and forth between three different issues: 1) what
the standard says, 2) what implementations do, and 3) what they ought to
do.

The question you posed most recently (which you snipped) concerned the
first of these three:

"We're trying to find what the standard mandates or wanted to mandate
with this respect."

What implementations do is irrelevant to that question. The could all
be doing it wrong and that wouldn't change the fact that it was wrong.

rg

Pascal Bourguignon

unread,
Sep 28, 2006, 1:12:54 PM9/28/06
to
Ron Garret <rNOS...@flownet.com> writes:

If the standard wasn't ambiguous, the implementations wouldn't diverge.

If the majority of the implementation went into the same dirrection,
there'd would be a concensus in the correct interpretation of the
standard.

Unfortunately, we're apparently in a case where 50% of the
implementaters interpreted one way and 50% the other way.

So what ought they do?

As a user of lisp implementation, my choice would go to one that
intreprets the standard as I do, in this case, #. should return the
values returned by the form it evaluates, nothing more, nothing less.

If enough users agree with me, we may have enough weight to ask the
bad implementations to change their intepretation, and consitute a
de-facto interpretation of the standard, therefore being one step
closer to a CL-2020 standard.


--
__Pascal Bourguignon__ http://www.informatimago.com/

This is a signature virus. Add me to your signature and help me to live.

Barry Margolin

unread,
Sep 28, 2006, 1:32:30 PM9/28/06
to
In article <87fyebv...@thalassa.informatimago.com>,
Pascal Bourguignon <p...@informatimago.com> wrote:

> Unfortunately, we're apparently in a case where 50% of the
> implementaters interpreted one way and 50% the other way.
>
> So what ought they do?
>
> As a user of lisp implementation, my choice would go to one that
> intreprets the standard as I do, in this case, #. should return the
> values returned by the form it evaluates, nothing more, nothing less.

As a user, if there's an ambiguity in the spec, you should avoid
depending on any particular interpretation. Treat it as if the spec
explicitly says that the consequences are undefined, since that's
effectively what it is.

If the standards body were still active you could file a request for
their interpretation, and then pass their reply on to implementors who
don't conform. But AFAIK the CL standardization committee is moribund,
so the best you can do is try to convince implementors that your
interpretation is the right one, and in the meanwhile just avoid that
aspect of the language.

Ron Garret

unread,
Sep 28, 2006, 4:04:12 PM9/28/06
to
In article <87fyebv...@thalassa.informatimago.com>,
Pascal Bourguignon <p...@informatimago.com> wrote:

> Ron Garret <rNOS...@flownet.com> writes:
>
> > In article <87k63ow...@thalassa.informatimago.com>,
> > Pascal Bourguignon <p...@informatimago.com> wrote:
> >
> >> Ron Garret <rNOS...@flownet.com> writes:
> >> > That is simple to answer:
> >> >
> >> > 2.4.8.6 Sharpsign Dot
> >> >
> >> > #.foo is read as THE OBJECT resulting from the evaluation of the object
> >> > represented by foo.
> >> >
> >> > (Emphasis added.)
> >> >
> >> > I take this to mean that the reader macro function for the #. reader
> >> > macro will always return a value (even if the form it evaluates doesn't).
> >>
> >> Not so simple, if 3 of the 6 implementations I tested, including
> >> Allegro 8.0, implement otherwise.
> >
> > You keep bouncing back and forth between three different issues: 1) what
> > the standard says, 2) what implementations do, and 3) what they ought to
> > do.
> >
> > The question you posed most recently (which you snipped) concerned the
> > first of these three:
> >
> > "We're trying to find what the standard mandates or wanted to mandate
> > with this respect."
> >
> > What implementations do is irrelevant to that question. The could all
> > be doing it wrong and that wouldn't change the fact that it was wrong.
>
> If the standard wasn't ambiguous, the implementations wouldn't diverge.

The standard is not ambiguous. It says very clearly and unambiguously
that "#.foo is read as THE OBJECT resulting from the evaluation of the
object represented by foo." In English, the article "the" in
conjunction with a singular noun implies one and only one.

> If the majority of the implementation went into the same dirrection,
> there'd would be a concensus in the correct interpretation of the
> standard.

Yes, but that consensus would be wrong.

> Unfortunately, we're apparently in a case where 50% of the
> implementaters interpreted one way and 50% the other way.
>
> So what ought they do?

They ought to follow the standard.

> As a user of lisp implementation, my choice would go to one that
> intreprets the standard as I do, in this case, #. should return the
> values returned by the form it evaluates, nothing more, nothing less.

But that's not what the standard says. Leaving aside the fact that
reader macros don't "return" anything (reader macro functions return
things) the standard specifically does NOT say, as you wish it did, that
#. "returns the values returned by the form" (whatever that might mean).
The standard says what it says and the meaning is quite unambiguous.

> If enough users agree with me, we may have enough weight to ask the
> bad implementations to change their intepretation, and consitute a
> de-facto interpretation of the standard, therefore being one step
> closer to a CL-2020 standard.

If enough users disagree with you the same end could be achieved.

rg

Duane Rettig

unread,
Sep 28, 2006, 6:23:27 PM9/28/06
to
Ron Garret <rNOS...@flownet.com> writes:

> In article <87fyebv...@thalassa.informatimago.com>,
> Pascal Bourguignon <p...@informatimago.com> wrote:
>
>> If the standard wasn't ambiguous, the implementations wouldn't diverge.
>
> The standard is not ambiguous. It says very clearly and unambiguously
> that "#.foo is read as THE OBJECT resulting from the evaluation of the
> object represented by foo." In English, the article "the" in
> conjunction with a singular noun implies one and only one.

I agree with this reading of the spec. I haven't kept up with this
thread, so I'm not sure if others arguing for ambiguity are citing the
third paragraph of 2.1.4.4 or not; but clearly, 2.4.8.6 is more
specific, and thus it stands.

Now; what does the standard say about #.(values) ? Absolutely
nothing. It talks about the object returned from #., but it does not
provide any guidance on what to do if no object is returned by the
evaluation, either with a statement of Exceptional Situations or
with a description.

So what does this mean? It means that a conforming program cannot
count on a particular behavior for this situation.

>> If the majority of the implementation went into the same dirrection,
>> there'd would be a concensus in the correct interpretation of the
>> standard.
>
> Yes, but that consensus would be wrong.

I agree.

>> Unfortunately, we're apparently in a case where 50% of the
>> implementaters interpreted one way and 50% the other way.
>>
>> So what ought they do?
>
> They ought to follow the standard.

This is not an implementation issue; it is a usage issue. Conforming
programs can't assume what isn't promised.

>> As a user of lisp implementation, my choice would go to one that
>> intreprets the standard as I do, in this case, #. should return the
>> values returned by the form it evaluates, nothing more, nothing less.
>
> But that's not what the standard says. Leaving aside the fact that
> reader macros don't "return" anything (reader macro functions return
> things) the standard specifically does NOT say, as you wish it did, that
> #. "returns the values returned by the form" (whatever that might mean).
> The standard says what it says and the meaning is quite unambiguous.
>
>> If enough users agree with me, we may have enough weight to ask the
>> bad implementations to change their intepretation, and consitute a
>> de-facto interpretation of the standard, therefore being one step
>> closer to a CL-2020 standard.
>
> If enough users disagree with you the same end could be achieved.

Or perhaps the standard is fine in this case and we must shift focus
on programs not counting on a particular behavior.

--
Duane Rettig du...@franz.com Franz Inc. http://www.franz.com/
555 12th St., Suite 1450 http://www.555citycenter.com/
Oakland, Ca. 94607 Phone: (510) 452-2000; Fax: (510) 452-0182

Barry Margolin

unread,
Sep 28, 2006, 8:14:46 PM9/28/06
to
In article <rNOSPAMon-63273...@news.gha.chartermi.net>,
Ron Garret <rNOS...@flownet.com> wrote:

> In article <87fyebv...@thalassa.informatimago.com>,
> Pascal Bourguignon <p...@informatimago.com> wrote:
> > If the standard wasn't ambiguous, the implementations wouldn't diverge.
>
> The standard is not ambiguous. It says very clearly and unambiguously
> that "#.foo is read as THE OBJECT resulting from the evaluation of the
> object represented by foo." In English, the article "the" in
> conjunction with a singular noun implies one and only one.

But that implication assumes that foo always evaluates to one and only
one object. If foo is (values), THE OBJECT has no reference -- it's
like THE KING OF ENGLAND.

So maybe it's not the implications that are wrong -- perhaps #.(values)
and #.(values 1 2 3) are not valid syntax, and it doesn't matter what
implementations do with them.

Pascal Bourguignon

unread,
Sep 29, 2006, 5:00:41 AM9/29/06
to
Barry Margolin <bar...@alum.mit.edu> writes:

> In article <87fyebv...@thalassa.informatimago.com>,
> Pascal Bourguignon <p...@informatimago.com> wrote:
>
>> Unfortunately, we're apparently in a case where 50% of the
>> implementaters interpreted one way and 50% the other way.
>>
>> So what ought they do?
>>
>> As a user of lisp implementation, my choice would go to one that
>> intreprets the standard as I do, in this case, #. should return the
>> values returned by the form it evaluates, nothing more, nothing less.
>
> As a user, if there's an ambiguity in the spec, you should avoid
> depending on any particular interpretation. Treat it as if the spec
> explicitly says that the consequences are undefined, since that's
> effectively what it is.
>
> If the standards body were still active you could file a request for
> their interpretation, and then pass their reply on to implementors who
> don't conform. But AFAIK the CL standardization committee is moribund,
> so the best you can do is try to convince implementors that your
> interpretation is the right one, and in the meanwhile just avoid that
> aspect of the language.

Indeed, that's exactly what I'm doing here.

You see, last time I raised such a question to my favorite
implementors, they asked me to raise it in c.l.l to see what the
concensus was.

--
__Pascal Bourguignon__ http://www.informatimago.com/

You're always typing.
Well, let's see you ignore my
sitting on your hands.

Pascal Bourguignon

unread,
Sep 29, 2006, 5:03:16 AM9/29/06
to
Ron Garret <rNOS...@flownet.com> writes:

Indeed. I'm of the opinion that a standard specification should
specify, to be of any use. Therefore, if CL specifies anything for
#.(values), right now, half the implementations are wrong.


--
__Pascal Bourguignon__ http://www.informatimago.com/

"You question the worthiness of my code? I should kill you where you
stand!"

Pascal Bourguignon

unread,
Sep 29, 2006, 5:08:44 AM9/29/06
to
Barry Margolin <bar...@alum.mit.edu> writes:

> In article <rNOSPAMon-63273...@news.gha.chartermi.net>,
> Ron Garret <rNOS...@flownet.com> wrote:
>
>> In article <87fyebv...@thalassa.informatimago.com>,
>> Pascal Bourguignon <p...@informatimago.com> wrote:
>> > If the standard wasn't ambiguous, the implementations wouldn't diverge.
>>
>> The standard is not ambiguous. It says very clearly and unambiguously
>> that "#.foo is read as THE OBJECT resulting from the evaluation of the
>> object represented by foo." In English, the article "the" in
>> conjunction with a singular noun implies one and only one.
>
> But that implication assumes that foo always evaluates to one and only
> one object. If foo is (values), THE OBJECT has no reference -- it's
> like THE KING OF ENGLAND.
>
> So maybe it's not the implications that are wrong -- perhaps #.(values)
> and #.(values 1 2 3) are not valid syntax, and it doesn't matter what
> implementations do with them.

If they weren't valid syntax, wouldn't it be nice if ALL the
implementations raised an error in such a case?

Or perhaps the rule that (values) in a call site where one value is
expected still gives NIL should apply and then then implementations
who read NIL for #.(values) are right, and the other are wrong?
Perhaps that's what the standard says?


--
__Pascal Bourguignon__ http://www.informatimago.com/

"You question the worthiness of my code? I should kill you where you
stand!"

Ron Garret

unread,
Sep 29, 2006, 2:36:40 PM9/29/06
to
In article <barmar-3442A1....@comcast.dca.giganews.com>,
Barry Margolin <bar...@alum.mit.edu> wrote:

> In article <rNOSPAMon-63273...@news.gha.chartermi.net>,
> Ron Garret <rNOS...@flownet.com> wrote:
>
> > In article <87fyebv...@thalassa.informatimago.com>,
> > Pascal Bourguignon <p...@informatimago.com> wrote:
> > > If the standard wasn't ambiguous, the implementations wouldn't diverge.
> >
> > The standard is not ambiguous. It says very clearly and unambiguously
> > that "#.foo is read as THE OBJECT resulting from the evaluation of the
> > object represented by foo." In English, the article "the" in
> > conjunction with a singular noun implies one and only one.
>
> But that implication assumes that foo always evaluates to one and only
> one object.

No it doesn't. It assumes that "the object" really means "the principal
value." There is ample precedent for making this assumption. For
example, the standard says:

"The form (LET ...) first evaluates the expressions init-form-1,
init-form-2, and so on, in that order, saving the resulting values. Then
all of the variables varj are bound to the corresponding values;"

It is universally agreed that "the resulting values" means the resulting
principal values even though the standard does not explicitly say so.
So unless you wish to entertain the possibility that:

(let ((x (values 1 2)) y) (list x y))

might return (1 2) you need to apply a little common sense.

> So maybe it's not the implications that are wrong -- perhaps #.(values)
> and #.(values 1 2 3) are not valid syntax, and it doesn't matter what
> implementations do with them.

That is possible, but there are at least two reasons to reject that
interpretation: first, if it were true then the behavior of #.(foo)
would be unpredictable in the case where you don't have control over the
behavior of foo. That is by any rational measure undesirable, and is
IMO grounds for rejecting that interpretation. Second, syntactic
correctness ought to be as much as possible a static property of the
program text. That ship has already sailed in CL with the introduction
of reader macros, but there's no reason to choose an interpretation that
introduces gratuitous dynamic errors with no payoff.

rg

Ron Garret

unread,
Sep 29, 2006, 6:18:45 PM9/29/06
to
In article <o0ejtvl...@franz.com>, Duane Rettig <du...@franz.com>
wrote:

> So what does this mean? It means that a conforming program cannot
> count on a particular behavior for this situation.

That is manifestly true since it is an objective fact that different
implementations handle this case differently. However, I think everyone
would agree that not being able to count on things is, all else being
equal, a Bad Thing. So we can make the world a better place by agreeing
on one behavior or the other. I am trying to argue that interpreting
"the object returned by" as "the principal value of" is consistent with
both the letter and spirit of the standard, and that it is the only
interpretation with those properties. It should therefore be the
preferred interpretation.

> Or perhaps the standard is fine in this case and we must shift focus
> on programs not counting on a particular behavior.

But that's bad because it means that to use the #. macro reliably you
must do more than just avoid #.(values), you must avoid #.(foo) for any
function foo that might return zero values.

rg

Ron Garret

unread,
Sep 29, 2006, 6:24:35 PM9/29/06
to

> In article <rNOSPAMon-63273...@news.gha.chartermi.net>,
> Ron Garret <rNOS...@flownet.com> wrote:
>
> > In article <87fyebv...@thalassa.informatimago.com>,
> > Pascal Bourguignon <p...@informatimago.com> wrote:
> > > If the standard wasn't ambiguous, the implementations wouldn't diverge.
> >
> > The standard is not ambiguous. It says very clearly and unambiguously
> > that "#.foo is read as THE OBJECT resulting from the evaluation of the
> > object represented by foo." In English, the article "the" in
> > conjunction with a singular noun implies one and only one.
>
> But that implication assumes that foo always evaluates to one and only
> one object. If foo is (values), THE OBJECT has no reference -- it's
> like THE KING OF ENGLAND.

This just occurred to me:

No, it is not like the king of England because the existence (or not) of
the KofE is not under our control. But the existence of The Object
returned by a reader macro function IS under our control. We can
therefore cause The Object to exist in a way that we cannot cause the
KofE to exist. The standard's use of the phrase "the object" implies
that it requires us to do exactly that.

Another important thing to note: in #.(foo), foo is NOT the reader-macro
function for the #. reader macro. The reader-macro function for #. must
call foo to do its job (in this case), but they are not the same thing.
Just because foo returns zero values does not mean that the reader-macro
function for #. has to.

rg

Duane Rettig

unread,
Sep 29, 2006, 7:42:55 PM9/29/06
to
Ron Garret <rNOS...@flownet.com> writes:

> In article <o0ejtvl...@franz.com>, Duane Rettig <du...@franz.com>
> wrote:
>
>> So what does this mean? It means that a conforming program cannot
>> count on a particular behavior for this situation.
>
> That is manifestly true since it is an objective fact that different
> implementations handle this case differently.

Not only is it manifestly true, but it is also explicitly true.
1.5.2: Conforming Programs (bullet 1): "Conforming code shall use only
those features of the language syntax and semantics that are either
specified in this standard or defined using the extension mechanisms
specified in the standard."

> However, I think everyone would agree that not being able to count
> on things is, all else being equal, a Bad Thing.

But all things aren't equal; they seem to be divided by 50%
manifestly, and in fact the standard says that you can't count on
things that it hasn't said you can count on. There are reasons for
this, of course, but I as an implementor would not agree to waste time
changing the behavior of something that is undefined except by either a
standardization effort to define it, or a very good reason to why such
a behavior guarantee is needed (Note again as I stated in my last
message that I haven't kept up on this thread; it may be that good
reasons have been given, but I'm personaly not interested in this
particular issue, only the meta-issue that it represents).

> So we can make the world a better place by agreeing
> on one behavior or the other.

Ahh, a standardization effort! Well, for this class of issue, where
clarification an otherwise very good spec on yet another minor point
is needed, you should add it to the list:

http://www.cliki.net/Proposed%20ANSI%20Revisions%20and%20Clarifications

> I am trying to argue that interpreting
> "the object returned by" as "the principal value of" is consistent with
> both the letter and spirit of the standard, and that it is the only
> interpretation with those properties. It should therefore be the
> preferred interpretation.

Again, I'm not concerned about the particular point you're making,
though I understand of course that you are - I am concerned with the
larger issue of pseudo-standardization. There are a lot of other
issues, though, that may or may not be of equal relevance to more or
less people (see above), and it is not a trivial process to force
agreement even amongst users, let alone vendors. That is in fact the
whole pain and victory of a standardization effort.

>> Or perhaps the standard is fine in this case and we must shift focus
>> on programs not counting on a particular behavior.
>
> But that's bad because it means that to use the #. macro reliably you
> must do more than just avoid #.(values), you must avoid #.(foo) for any
> function foo that might return zero values.

As you said in another message, foo is not the character macro here,
but the function which the character macro calls. So if you want to
write portable programs, and can legislate to users who are willing
to go along with it, then you can have everyone wrap (values...)
around the call, as in #.(values (foo))

CL-USER(1): (defun foo () (values))
FOO
CL-USER(2): (foo)
CL-USER(3): (values (foo))
NIL
CL-USER(4):

In that way you don't have to wait for vendors to respond (or not) to
your mini-standardization effort, and you can then have your
portability as soon as you get fellow users to code that way.

Ron Garret

unread,
Sep 29, 2006, 7:47:49 PM9/29/06
to
In article <o0y7s2p...@franz.com>, Duane Rettig <du...@franz.com>
wrote:

> > So we can make the world a better place by agreeing

> > on one behavior or the other.
>
> Ahh, a standardization effort!

Damn, Duane, nothing gets past you does it? ;-)

> So if you want to
> write portable programs, and can legislate to users who are willing
> to go along with it, then you can have everyone wrap (values...)
> around the call, as in #.(values (foo))

Yeah, but that's annoying. Still, your point is well taken.

rg

Barry Margolin

unread,
Sep 29, 2006, 7:56:46 PM9/29/06
to
In article <87y7s3t...@thalassa.informatimago.com>,
Pascal Bourguignon <p...@informatimago.com> wrote:

> Barry Margolin <bar...@alum.mit.edu> writes:
>
> > In article <rNOSPAMon-63273...@news.gha.chartermi.net>,
> > Ron Garret <rNOS...@flownet.com> wrote:
> >
> >> In article <87fyebv...@thalassa.informatimago.com>,
> >> Pascal Bourguignon <p...@informatimago.com> wrote:
> >> > If the standard wasn't ambiguous, the implementations wouldn't diverge.
> >>
> >> The standard is not ambiguous. It says very clearly and unambiguously
> >> that "#.foo is read as THE OBJECT resulting from the evaluation of the
> >> object represented by foo." In English, the article "the" in
> >> conjunction with a singular noun implies one and only one.
> >
> > But that implication assumes that foo always evaluates to one and only
> > one object. If foo is (values), THE OBJECT has no reference -- it's
> > like THE KING OF ENGLAND.
> >
> > So maybe it's not the implications that are wrong -- perhaps #.(values)
> > and #.(values 1 2 3) are not valid syntax, and it doesn't matter what
> > implementations do with them.
>
> If they weren't valid syntax, wouldn't it be nice if ALL the
> implementations raised an error in such a case?

Sure. But there are lots of errors that implementations aren't required
to diagnose.

Joerg Hoehle

unread,
Oct 2, 2006, 12:23:47 PM10/2/06
to nobody
Hi,

I'm in favour of having all CL "standardize" or converge on what's
perceived as useful behaviour by the community. It helps portability
(at least of new software), which many people here think is a great
asset of CL.

The question is, what's the most valueable behaviour to converte to?

I wouldn't want to debate whether #. "skip" behaviour can be derived
from the wording of the CLHS (or ANSI-CL spec).

What I'd like to question is the merits of choosing the one over the
other. Why is "ignore" better than the opposite?
Is it just a matter of shouting the loudest right now in this thread?
We've had this #. topic here and there in comp.lang.lisp already.


Barry Margolin <bar...@alum.mit.edu> writes:


> > Ron Garret <rNOS...@flownet.com> wrote:
> > > Personally I think it would be useful to be able to assume
> > > unconditionally that the above reads as a list of length 5. Another
> > > example:
> > > (let ((x '#.(foo)) ...)

[quote added above]

> > > I think it's useful that the above not break if foo happens to return
> > > zero values.

> How about
> (let ((x '#.(foo))) ...)
> which is likely to be what you'd want to write (unless you know that FOO
> always returns a self-evaluating object).

So that's a clear, correct and understandable concern against the "skip" case.

I can myself come up with a case in favour of the "skip" case, e.g.
CLISP's (FFI:DEF-CALL-OUT ... [(:library ...)] #)
Whether the (:library #) clause is present or not leads to completely
different behaviour. #.(values)-as-ignore would be useful in that context.

What else is there to put up for the judges?
Pros? Cons?

Regards,
Jorg Hohle
Telekom/T-Systems Technology Center

Pascal Costanza

unread,
Oct 2, 2006, 1:12:26 PM10/2/06
to
Joerg Hoehle wrote:

> What else is there to put up for the judges?
> Pros? Cons?

I haven't followed the discussion in this thread, so maybe this is
completely irrelevant. But in my experience, one good principle in
language design is this: If you have two design choices, check which of
the two allows expressing the respective other. If one isn't capable of
doing what the other does, choose the other one. In this way, you serve
more potential users, especially in cases where it's not clear what the
"obvious right way" (tm) is.


Pascal

--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/

Pascal Bourguignon

unread,
Oct 2, 2006, 1:54:01 PM10/2/06
to
Pascal Costanza <p...@p-cos.net> writes:

> Joerg Hoehle wrote:
>
>> What else is there to put up for the judges?
>> Pros? Cons?
>
> I haven't followed the discussion in this thread, so maybe this is
> completely irrelevant. But in my experience, one good principle in
> language design is this: If you have two design choices, check which
> of the two allows expressing the respective other. If one isn't
> capable of doing what the other does, choose the other one. In this
> way, you serve more potential users, especially in cases where it's
> not clear what the "obvious right way" (tm) is.


That's what I think too.

Assuming the function f returns 0 or 1 value,
we may want to read:


With the behavior of allegro,sbcl,cmucl:

nothing when f returns 0 value
the value when f returns 1 value

#.(f)


nil when f returns 0 value
the value when f returns 1 value

#.(values (f))


With the behavior of clisp,gcl,ecl:

nothing when f returns 0 value
the value when f returns 1 value

#+(cl:if (cl:null (cl:multiple-value-list (cl-user::f)))
'(or) '(and))
#.(values (f))

;; which can be done only when f is a pure function
;; (without side effect)


;; Perhaps something like:
#+(cl:progn
(cl:defparameter cl-user::*rt-values*
(cl:multiple-value-list (cl-user::f)))
(cl:if (cl:null cl-user::*rt-values*)
'(or) '(and)))
#.(first *rt-values*)
;; when f has side-effects.


nil when f returns 0 value
the value when f returns 1 value

#.(f)

(when the function returns two or more values, there's no ambiguity
apparently, since all the implementations I have read the same thing,
the first value:


[pjb@thalassa pjb]$ clall '(read-from-string "#.(values 1 2) 42")'

------------------------------------------------------------------------
CLISP 2.39 (2006-07-16) (built 3364813332) (memory 3364813914)


(READ-FROM-STRING "#.(values 1 2) 42")
--> 1 ;
14

------------------------------------------------------------------------
SBCL 0.9.12


(READ-FROM-STRING "#.(values 1 2) 42")
--> 1 ;
15

------------------------------------------------------------------------
CMU Common Lisp 19c (19C)


(READ-FROM-STRING "#.(values 1 2) 42")
--> 1 ;
15

------------------------------------------------------------------------
GNU Common Lisp (GCL) GCL 2.6.7


(READ-FROM-STRING "#.(values 1 2) 42")
--> 1 ;
14

------------------------------------------------------------------------
ECL 0.9g


(READ-FROM-STRING "#.(values 1 2) 42")
--> 1 ;
15

------------------------------------------------------------------------
International Allegro CL Free Express Edition 8.0 [Linux (x86)] (Jun 6, 2006 16:01)


(READ-FROM-STRING "#.(values 1 2) 42")
--> 1 ;
15

------------------------------------------------------------------------

)


--
__Pascal Bourguignon__ http://www.informatimago.com/

READ THIS BEFORE OPENING PACKAGE: According to certain suggested
versions of the Grand Unified Theory, the primary particles
constituting this product may decay to nothingness within the next
four hundred million years.

Ron Garret

unread,
Oct 2, 2006, 3:44:26 PM10/2/06
to
In article <4ocvjpF...@individual.net>,
Pascal Costanza <p...@p-cos.net> wrote:

> Joerg Hoehle wrote:
>
> > What else is there to put up for the judges?
> > Pros? Cons?
>
> I haven't followed the discussion in this thread, so maybe this is
> completely irrelevant. But in my experience, one good principle in
> language design is this: If you have two design choices, check which of
> the two allows expressing the respective other. If one isn't capable of
> doing what the other does, choose the other one. In this way, you serve
> more potential users, especially in cases where it's not clear what the
> "obvious right way" (tm) is.

This is not about capability, it is about invariance. Either
possibility can easily "do" what the other one does at the expense of
some additional typing. What this is about is what one can or cannot
count on. Can I count on e.g.:

(defconstant x #.(foo))

not producing a syntax error, or do I have to always remember to write:

(defconstant x #.(values (foo)))

IMHO allowing #. to read as nothing is not a feature but a pitfall, not
unlike those for which C++ is often and rightly derided.

rg

P.S. I note in passing that on the criterion above, *combination-hook*
is an improvement on CL's design, and that your objections to
*combination-hook* are of exactly the same form as my objections to #.
reading as nothing. The difference is that adding *combination-hook*
cannot cause currently correct code to break, whereas allowing #. to
read as nothing can.

Pascal Costanza

unread,
Oct 2, 2006, 4:09:37 PM10/2/06
to
Ron Garret wrote:
> In article <4ocvjpF...@individual.net>,
> Pascal Costanza <p...@p-cos.net> wrote:
>
>> Joerg Hoehle wrote:
>>
>>> What else is there to put up for the judges?
>>> Pros? Cons?
>> I haven't followed the discussion in this thread, so maybe this is
>> completely irrelevant. But in my experience, one good principle in
>> language design is this: If you have two design choices, check which of
>> the two allows expressing the respective other. If one isn't capable of
>> doing what the other does, choose the other one. In this way, you serve
>> more potential users, especially in cases where it's not clear what the
>> "obvious right way" (tm) is.
>
> This is not about capability, it is about invariance. Either
> possibility can easily "do" what the other one does at the expense of
> some additional typing. What this is about is what one can or cannot
> count on. Can I count on e.g.:
>
> (defconstant x #.(foo))
>
> not producing a syntax error, or do I have to always remember to write:
>
> (defconstant x #.(values (foo)))
>
> IMHO allowing #. to read as nothing is not a feature but a pitfall, not
> unlike those for which C++ is often and rightly derided.

As I said, I haven't followed the discussion, so I cannot judge this.

Geoffrey Summerhayes

unread,
Oct 2, 2006, 5:24:54 PM10/2/06
to
Ron Garret wrote:
> In article <4ocvjpF...@individual.net>,
>
> This is not about capability, it is about invariance. Either
> possibility can easily "do" what the other one does at the expense of
> some additional typing. What this is about is what one can or cannot
> count on. Can I count on e.g.:
>
> (defconstant x #.(foo))
>
> not producing a syntax error, or do I have to always remember to write:
>
> (defconstant x #.(values (foo)))
>
> IMHO allowing #. to read as nothing is not a feature but a pitfall, not
> unlike those for which C++ is often and rightly derided.

Given the current variation in implementations, expecting a no value
return not to break code is obviously problematic.

I also find it difficult to accept that a function that can return no
values used in a defconstant #. pairing can really be considered
correct, or at the very least, good code under either interpretation.

It would be nice to have a way of mimicking a <user-created
reader macro that may return no values> when readtable
modifications are difficult to make and maintain due to other
packages in play. Sorry about that sentence. :-(

For instance, under normal circumstances the package could
use #!, but if it found the dispatch in use by another package,
it could switch to #. and be capable of still writing a readable
form that behaved identically.

The alternative would be to specify an additional reader macro
that behaved exactly like #. except for its behaviour when it
returns no values.

---
Geoff

Alan Crowe

unread,
Oct 4, 2006, 12:33:04 PM10/4/06
to
Ron Garret <rNOS...@flownet.com> writes:

> This is not about capability, it is about invariance. Either
> possibility can easily "do" what the other one does at the expense of
> some additional typing. What this is about is what one can or cannot
> count on. Can I count on e.g.:
>
> (defconstant x #.(foo))
>
> not producing a syntax error, or do I have to always remember to write:
>
> (defconstant x #.(values (foo)))
>

You really want that syntax error. If you had meant x to be
nil you would have written (defconstant x nil). What you've
done is remember foo as

(defun foo (stuff)
(setf *remember* (compute-foo stuff)))

but for some reason foo is actually

(defun foo (stuff)
(setf *remember* (compute-foo stuff))
(values))

The invarience that you care about is (eql x *remember*)
Having (defconstant x #.(foo)) shaft you with an unexpected
nil is a loss.

Alan Crowe
Edinburgh
Scotland

0 new messages