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

"nested" #- and #+

10 views
Skip to first unread message

Barry Margolin

unread,
Feb 8, 1999, 3:00:00 AM2/8/99
to
In article <31274498...@naggum.no>, Erik Naggum <er...@naggum.no> wrote:
> can Common Lisp be easily conditionalized for various systems? a local
> programmer sent me some code that stood out as particularly ugly to both
> of us, and I thought "this really can't be it". so it occurred to me
> that #- and #+ should "nest", in that #-foo bar is like whitespace when
> (featurep :foo), which seems to imply that
>
>#-foo #+zot bar #-zot quux
>
> should be skipped entirely when (featurep :foo). if this is valid, then
> we should be able to write conditionalizations like this:

They sometimes seem to nest, but I'm not sure if it can be generalized. I
remember Kent once working this out.

In the above example, if feature FOO is true the following possibilities
ensue:

1) ZOT is true: The recursive read returns BAR, and this will be tossed by
the outer #- reader. It will then proceed to read '#-zot quux', which will
be skipped because the ZOT feature is true, and will then go on to whatever
is next.

2) ZOT is false: The recursive read will skip over '#+zot bar', then return
QUUX because the ZOT feature is false. The outer reader will ignore this result

Notice that the effect is what you said, but how it arrived there is
different in the two cases. In one case the outer #- reader performed a
skip that's performed by the inner #+ reader in the other case. Note that
it was important that *READ-SUPPRESS* *not* suppress the interpretation of
#+ and #- for this to work.

>#+allegro (allegro-specific) #-allegro
>#+cmucl (cmucl-specific) #-cmucl
>#+lucid (lucid-specific) #-lucid
>(unknown-system)
>
> instead of the maintenance nightmare
>
>#+allegro (allegro-specific)
>#+cmucl (cmucl-specific)
>#+lucid (lucid-specific)
>#-(or allegro cmucl lucid) (unknown-system)
>
> I read the standard to say that "nesting" should work. is it reasonable?

I think it should. But beware that there's no easy way to "parenthesize";
as with some languages that don't have an "endif" construct, it's easy to
obfuscate and end up with mismatches if you're not careful.

In retrospect, it would have been more Lisp-like if the syntax of #+/#-
had been:

#+<feature> (<then-result> <optional-else-result>)

Then the above would be:

#+allegro ((allegro-specific)
#+cmucl ((cmucl-specific)
#+lucid ((lucid-specific)
(unknown-system))))

Notice that the editor's indentation and paren matcher would then work with
the programmer to ensure proper nesting.

--
Barry Margolin, bar...@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Don't bother cc'ing followups to me.

Erik Naggum

unread,
Feb 8, 1999, 3:00:00 AM2/8/99
to
can Common Lisp be easily conditionalized for various systems? a local
programmer sent me some code that stood out as particularly ugly to both
of us, and I thought "this really can't be it". so it occurred to me
that #- and #+ should "nest", in that #-foo bar is like whitespace when
(featurep :foo), which seems to imply that

#-foo #+zot bar #-zot quux

should be skipped entirely when (featurep :foo). if this is valid, then
we should be able to write conditionalizations like this:

#+allegro (allegro-specific) #-allegro


#+cmucl (cmucl-specific) #-cmucl
#+lucid (lucid-specific) #-lucid
(unknown-system)

instead of the maintenance nightmare

#+allegro (allegro-specific)
#+cmucl (cmucl-specific)
#+lucid (lucid-specific)
#-(or allegro cmucl lucid) (unknown-system)

I read the standard to say that "nesting" should work. is it reasonable?

#:Erik
--
Y2K conversion simplified: Januark, Februark, March, April, Mak, June,
Julk, August, September, October, November, December.

Kent M Pitman

unread,
Feb 9, 1999, 3:00:00 AM2/9/99
to
Erik Naggum <er...@naggum.no> writes:

> I read the standard to say that "nesting" should work. is it reasonable?

I hope so. Long ago working on Macsyma, I can remember very complicated
conditionals with things like

#+Maclisp #+PDP10 ...
#-PDP10 ...
#-Maclisp #+LispM #+Symbolics ...
#-Symbolics ...
#-LispM #+(or Franz NIL) ...
#-(or Franz NIL) ...

or whatever. I always used them in balanced pairs to avoid making an error.
More and more though these days I tend to go for:

(defmacro questionable-frob (&rest args)
(or #+implementation-A `(implem-a:frob ,@args)
#+implementation-B `(implem-b:frob ,@args)
#+(or implementation-C implementation-D)
`(implem-c-or-d:frob , @args)
(error "~S is not implemented." 'questionable-frob)))

We have talked over and over again about making a syntax giving the power
that people always mean when they desperately request a #+Else. For example,
#[ feature-exp-1 exp-1 feature-exp-2 exp-2 else default-exp ]
But for some reason we have never done it. Never quite enough pain to force
it I guess.

Howard R. Stearns

unread,
Feb 9, 1999, 3:00:00 AM2/9/99
to
I think Erik (as clarified by Barry) is correct, but I want to "let the
record show" that there is a related issue that is often misunderstood.
Consider

(read-from-string "(0 #+foo #+bar 1 2 3 4)")

where neither :foo nor :bar are present in *features*.

This should return (0 3 4), but historically, some implementations have
returned (0 2 3 4). We can argue about why this is so, but the safe
point is that users should remember is that this use of the construct
might not be portable and should problably be avoided.

Here's why I think the 2 should be skipped: When the reader determines
that :foo is not present, it recursively skips the next form, which is
read with *read-suppress* true. Then this reader tries to read "#+bar
1 2 ..." and finding that :bar is not present, it reads and skips the
1. Finally it reads the 2, which can then be ignored from the recursion
which was skipping the form after #+foo.

I suspect, but don't know for sure, that those implementors who wrote
code which returned the 2 handled the #+ specially when *read-suppress*
was already true. Perhaps this was out of an attempt to provide the
convenienence that Kent was talking about. (Any comments from Franz? I
don't know if 5.0 still does this...)

Erik Naggum wrote:
>
> can Common Lisp be easily conditionalized for various systems? a local
> programmer sent me some code that stood out as particularly ugly to both
> of us, and I thought "this really can't be it". so it occurred to me
> that #- and #+ should "nest", in that #-foo bar is like whitespace when
> (featurep :foo), which seems to imply that
>
> #-foo #+zot bar #-zot quux
>
> should be skipped entirely when (featurep :foo). if this is valid, then
> we should be able to write conditionalizations like this:
>
> #+allegro (allegro-specific) #-allegro
> #+cmucl (cmucl-specific) #-cmucl
> #+lucid (lucid-specific) #-lucid
> (unknown-system)
>
> instead of the maintenance nightmare
>
> #+allegro (allegro-specific)
> #+cmucl (cmucl-specific)
> #+lucid (lucid-specific)
> #-(or allegro cmucl lucid) (unknown-system)
>

> I read the standard to say that "nesting" should work. is it reasonable?
>

Erik Naggum

unread,
Feb 11, 1999, 3:00:00 AM2/11/99
to
* Barry Margolin <bar...@bbnplanet.com>

| In the above example, if feature FOO is true the following possibilities
| ensue:
|
| 1) ZOT is true: The recursive read returns BAR, and this will be tossed
| by the outer #- reader. It will then proceed to read '#-zot quux', which
| will be skipped because the ZOT feature is true, and will then go on to
| whatever is next.
|
| 2) ZOT is false: The recursive read will skip over '#+zot bar', then
| return QUUX because the ZOT feature is false. The outer reader will
| ignore this result
|
| Notice that the effect is what you said, but how it arrived there is
| different in the two cases. In one case the outer #- reader performed a
| skip that's performed by the inner #+ reader in the other case. Note
| that it was important that *READ-SUPPRESS* *not* suppress the
| interpretation of #+ and #- for this to work.

the way I figured this would work is close to what you describe, but I'm
trying to figure out what the value of *READ-SUPPRESS* should be at all
times. I found it instructive to view it like a hardware signal:

#+foo #+bar foobar #-bar foo #-foo #+bar bar #-bar nil
__ _________ ___ ___
none _____/ \__/ \__/ \___________/ \__________
#-/#+ [ ] [ ] [ ] [ ] [ ] [ ]
[----------------------] [---]
[------]

______ __ ______ ___
FOO ___________/ \_______________/ \__/ \__/ \
[------] [-------------------]
[---]

__ _________ ___ ___
BAR _____/ \__/ \__/ \_____________________/ \
[----------------------] [---]
[---]

___ __ ______ ___
FOO and BAR ________________________/ \_____/ \__/ \__/ \
[---] [-------------------]
[---]

in terms of bindings, *READ-SUPPRESS* is bound to true when the feature-
expression is false, and to false by the #- and #+ reader macro function
when reading the feature expression. the important issue here is that
the feature expression not read as NIL, but maintains the prevailing
value when reading the following expression when the feature expression
is satisfied.

Kálmán Réti

unread,
Feb 15, 1999, 3:00:00 AM2/15/99
to

"Howard R. Stearns" wrote:

(Any comments from Franz? I
don't know if 5.0 still does this...)

It does, at least on a Dec Alpha. MCL also returns the 2.

Reini Urban

unread,
Feb 16, 1999, 3:00:00 AM2/16/99
to
BTW: if anybody is interested, i'm working with a lisp (autolisp) that
has no #- and #+ reader macros. even no macros at all!
so for writing my autolisp standard library i had to implement a
workaround by using a perl preprocessor.

it uses this very ugly syntax:

;;; process this normally
;|#- ACOMP|;
(if (not special)
(defun special (x)
(std-%load-verbose-print (append '("declared special: ") x))))
;|END #- ACOMP|;
;;; omit this in plain alisp, but add it when ACOMP is on
;|#+ ACOMP (special '(*FOPEN*)) END #+ ACOMP|;

btw: autolisp uses ;| |; as inline comments.
this way it works with plain autolisp, but when preprocessed and putting
on the ACOMP feature switch with stdlib-pp -v=ACOMP
it creates

(special '(*FOPEN*))

in a special directory for this feature.

i needed it absolutely to maintain portable sources, so the effort is
worth the ugly syntax, readability and terrible handling.
we have a bunch of different autolisp versions, uncompiled and compiled,
with some obsure features and possible optimizations.
e.g. ACOMP is an old xlisp-based byte-code compiler, not taking inline
comments, but processing SPECIAL with a list of dynamic variables.
the perl script as at
=> http://xarch.tu-graz.ac.at/autocad/stdlib/utils/stdlib-pp.pl
it is very lispy :)

back to the story:
nested comments also created headaches for me, the planned --nested
switch is not supported yet. (no recursive parser func yet)

with nesting the code would be much shorter. i could have avoided
repetitions. but it didn't seem to be more readable, at least to me.
with my terrible syntax (needing the end marker and open or closed
comments) i got also confused, mixing them sometimes up, confusing the
preprocessor and introduced some hard-to-find bugs.

because i know the precedence of my features in advance i actually did
some nesting, but this is very obscure and i think it shouldn't be
supported. (in my perl only, of course)
now it only works if the outer level has lower precedence.
hmm, but i'll probably think it over.

In other places i rewrote READ-FROM-STRING to support #+ and #- as in
Common Lisp (this time nested) but it is awfully slow. so this is only
usable for my testsuite, not for production code.
=> http://xarch.tu-graz.ac.at/autocad/stdlib/test/STDLIB.TST (simple)
or http://xarch.tu-graz.ac.at/autocad/stdlib/samples/READER.LSP (better)


Erik Naggum <er...@naggum.no> wrote:
> can Common Lisp be easily conditionalized for various systems? a local
> programmer sent me some code that stood out as particularly ugly to both
> of us, and I thought "this really can't be it". so it occurred to me
> that #- and #+ should "nest", in that #-foo bar is like whitespace when
> (featurep :foo), which seems to imply that
>
>#-foo #+zot bar #-zot quux
>
> should be skipped entirely when (featurep :foo). if this is valid, then
> we should be able to write conditionalizations like this:
>
>#+allegro (allegro-specific) #-allegro
>#+cmucl (cmucl-specific) #-cmucl
>#+lucid (lucid-specific) #-lucid
>(unknown-system)
>
> instead of the maintenance nightmare
>
>#+allegro (allegro-specific)
>#+cmucl (cmucl-specific)
>#+lucid (lucid-specific)
>#-(or allegro cmucl lucid) (unknown-system)
>
> I read the standard to say that "nesting" should work. is it reasonable?

---
Reini Urban
http://xarch.tu-graz.ac.at/autocad/news/faq/autolisp.html

0 new messages