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

special var symbols as function arguments

64 views
Skip to first unread message

Antony

unread,
Apr 29, 2012, 3:20:55 AM4/29/12
to
Hi

I just saw the following code in PAIP while trying to reread it now that
I can read CL :)

(defvar *state* nil ...)
(defvar *ops* ...)
...
(defun gps (*state* goals *ops*)
...)

I have never written code with parameters that are special.

I guess if this works, it works like a normal let binding on the
specials with the values passed to the call.

Do people use this technique?

-Antony

Tim Bradshaw

unread,
Apr 29, 2012, 3:49:19 AM4/29/12
to
On 2012-04-29 07:20:55 +0000, Antony said:

> I guess if this works, it works like a normal let binding on the
> specials with the values passed to the call.

I think it does

>
> Do people use this technique?

I don't: I'd instead say

(defun foo (x)
(let ((*x* x))
...))

Which is more verbose but I think less unexpectd.

Barry Margolin

unread,
Apr 29, 2012, 12:41:19 PM4/29/12
to
In article <jniq50$r8a$1...@speranza.aioe.org>,
It's not too common, but you could imagine something like:

(defun write (object &key
((:stream *standard-output*) *standard-output*)
((:array *print-array*) *print-array*)
((:base *print-base*) *print-base*)
...)
(if *print-escape*
(prin1 object)
(princ object)))

Even if WRITE is the primitive that PRIN1 and PRINC are written in terms
of, it still has to bind all the variables to the corresponding keyword
parameters (for the benefit of things like PRINT-OBJECT methods that get
invoked within it).

Actually, I'm not totally sure this is valid. The spec says that
supplied keywords cause the corresponding variable to be bound, but if a
keyword parameter isn't supplied, the corresponding variable has the
same value as it did when WRITE was invoked. My code above meets that
requirement, but it does so by dynamically binding the variable to its
value.

The difference becomes apparent if a function invoked during the WRITE
assigns one of these variables. With the binding in place, the variable
is restored to its previous value when WRITE returns.

--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***

Madhu

unread,
Apr 29, 2012, 10:44:48 PM4/29/12
to

* Barry Margolin <barmar-6BD03F....@news.eternal-september.org> :
Wrote on Sun, 29 Apr 2012 12:41:19 -0400:

| (defun write (object &key
| ((:stream *standard-output*) *standard-output*)
| ((:array *print-array*) *print-array*)
| ((:base *print-base*) *print-base*)
| ...)
| (if *print-escape*
| (prin1 object)
| (princ object)))
|
| Even if WRITE is the primitive that PRIN1 and PRINC are written in terms
| of, it still has to bind all the variables to the corresponding keyword
| parameters (for the benefit of things like PRINT-OBJECT methods that get
| invoked within it).
|
| Actually, I'm not totally sure this is valid. The spec says that
| supplied keywords cause the corresponding variable to be bound, but if a
| keyword parameter isn't supplied, the corresponding variable has the
| same value as it did when WRITE was invoked. My code above meets that
| requirement, but it does so by dynamically binding the variable to its
| value.

The spec's statement "the value of the corresponding printer control
variable is the same as it was at the time write was invoked.", would be
vacuous if it was not meant to imply that the specified printer
variables were going to rebound dynamically by WRITE, (even when not
named as a keyword parameter)

| The difference becomes apparent if a function invoked during the WRITE
| assigns one of these variables. With the binding in place, the variable
| is restored to its previous value when WRITE returns.

I cannot imagine unconditionally assigning a global printer variable in
the innards of the printer as being anything but a bug.

PRINT-OBJECT cautions that "In general, the printer and the print-object
methods should not rebind the print control variables as they operate
recursively through the structure, but this is
implementation-dependent."

[A better example than WRITE for the OP would be the stream argument to
the PPRINT-LOGICAL-BLOCK macro. I think LW has some compliance issues
with the pprint-* functions, most likely related to the issue you
brought up above.]

--- Madhu

Barry Margolin

unread,
Apr 30, 2012, 10:01:54 AM4/30/12
to
In article <m3fwbms...@leonis4.robolove.meer.net>,
I thought it could just be a reminder that WRITE must NOT set or bind
them to default values. When I was writing the above sample code, I
almost left out all the defaults -- that would have violated this part
of the spec.

>
> | The difference becomes apparent if a function invoked during the WRITE
> | assigns one of these variables. With the binding in place, the variable
> | is restored to its previous value when WRITE returns.
>
> I cannot imagine unconditionally assigning a global printer variable in
> the innards of the printer as being anything but a bug.
>
> PRINT-OBJECT cautions that "In general, the printer and the print-object
> methods should not rebind the print control variables as they operate
> recursively through the structure, but this is
> implementation-dependent."
>
> [A better example than WRITE for the OP would be the stream argument to
> the PPRINT-LOGICAL-BLOCK macro. I think LW has some compliance issues
> with the pprint-* functions, most likely related to the issue you
> brought up above.]

If the CL designers weren't trying to maintain consistency with the way
MACLISP and Zetalisp did this, what they might have done was throw out
all these variables, and use an opaque object analogous to RANDOM-STATE
to hold all the printer/reader parameters.
0 new messages