From: Vladimir V. Zolotych
Subject: (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
Date: 
Message-ID: <3A60929B.A9A11B9D@eurocom.od.ua>
This is a multi-part message in MIME format.
--------------7192B17CB71F3F872B03D515
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

  Hello,

Few questions if you please...

1.
 
Please explain me why I can't write

(DEFMACRO OUTER (X) `(DEFMACRO INNER () `(,X 1 2)))

but should write

(DEFMACRO OUTER (X) `(DEFMACRO INNER () `(,',X 1 2)))

Is there other solution to get X evaluated ?

2.

The next question inspired by reading David B. Lamkins "Successful
Lisp".
What is the significant difference between the following two
versions of the LOOKUP-SIN ? I mean from the point of the resulted code
and efficiency.

a)

(defmacro lookup-sin (radians divisions)
  (multiple-value-bind (table increment)
      (get-sin-table-and-increment divisions)
    `(aref ,table (round ,radians ,increment))))
b)

(defun lookup-sin2 (radians divisions)
  (multiple-value-bind (table increment)
      (get-sin-table-and-increment divisions)
    (aref table (round radians increment))))

The complete source for this example is at the end.

3.

Can you give me examples when omitting

(EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)

causes problems ? Or, in other words, when EVAL-WHEN
is necessary ?

  Thanks.

========================================================================
(defvar *sin-tables* (make-hash-table))

(defun get-sin-table-and-increment (divisions)
  (let ((table (gethash divisions *sin-tables* :none))
        (increment (/ pi 2 divisions)))
    (when (eq table :none)
      (setq table
            (setf (gethash divisions *sin-tables*)
                  (make-array (1+ divisions) :initial-element 1.0)))
      (dotimes (i divisions)
        (setf (aref table i)
              (sin (* increment i)))))
    (values table increment)))

(defmacro lookup-sin (radians divisions)
  (multiple-value-bind (table increment)
      (get-sin-table-and-increment divisions)
    `(aref ,table (round ,radians ,increment))))

(defun lookup-sin2 (radians divisions)
  (multiple-value-bind (table increment)
      (get-sin-table-and-increment divisions)
    (aref table (round radians increment))))

-- 
Vladimir Zolotych                         ······@eurocom.od.ua
--------------7192B17CB71F3F872B03D515
Content-Type: text/x-vcard; charset=us-ascii;
 name="gsmith.vcf"
Content-Transfer-Encoding: 7bit
Content-Description: Card for Vladimir V. Zolotych
Content-Disposition: attachment;
 filename="gsmith.vcf"

begin:vcard 
n:Zolotych;Valdimir V.
x-mozilla-html:FALSE
adr:;;;;;;
version:2.1
·····················@eurocom.od.ua
x-mozilla-cpt:;0
fn:Valdimir V. Zolotych
end:vcard

--------------7192B17CB71F3F872B03D515--

From: Kent M Pitman
Subject: Re: (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
Date: 
Message-ID: <sfwitnj73u1.fsf@world.std.com>
"Vladimir V. Zolotych" <······@eurocom.od.ua> writes:

> Please explain me why I can't write
> 
> (DEFMACRO OUTER (X) `(DEFMACRO INNER () `(,X 1 2)))
> 
> but should write
> 
> (DEFMACRO OUTER (X) `(DEFMACRO INNER () `(,',X 1 2)))
> 
> Is there other solution to get X evaluated ?

No.

[This isn't a homework question is it?  Heh... I *wish* they would have 
 classes that would have homework like this...]

I'm afraid I don't even see the problem.

Think of ",'" as meaning "go out a level doing no interpretation at
the current level".  So ",X" refers to the innermost X, ",',X" refers
to the next outer X, ",',',X" refers to the next outer X and so on.

In old Teco-based Emacs, I had an extension to Lisp mode which made
"," blink the balanced "`" that matches.  (It's pretty easy to implement
by counting the number of attached commas to the left of the given comma
and simulating c-m-u's until that many backquotes are passed.)  No one
seems to have ported that through to modern lisp-based Emacs.  Pity.

To understand why it's necessary to write what you have to write, consider:

 (DEFMACRO OUTER (X) `(DEFMACRO INNER (X) `(,',X ,X 1 2)))

You can see you have access to both X's, which is a real win.

Btw, if your question is why it's not the other way around, counting from
the outside instead of the inside, the answer is "referential transparency".
The current rules allow you to pick up an expression that does not involve
the outer environment and move it elsewhere without changing its meaning.
An example might be:

 (DEFMACRO BAR (X)
   `(DEFMACRO FOO (X) `'(,X)))

which doesn't change its meaning if you pick up the entire expression and
embed it into another macro, as in:

 (DEFMACRO BAZ (X)
   `(DEFMACRO BAR (X)
      `(DEFMACRO FOO (X) `'(,X))))

If the counting was done from the outside inward, moving an expression into
a different nesting level would change all the meanings of all the 
multiply-nested comma elements.

> The next question inspired by reading David B. Lamkins "Successful
> Lisp".
> What is the significant difference between the following two
> versions of the LOOKUP-SIN ? I mean from the point of the resulted code
> and efficiency.
> 
> a)
> 
> (defmacro lookup-sin (radians divisions)
>   (multiple-value-bind (table increment)
>       (get-sin-table-and-increment divisions)
>     `(aref ,table (round ,radians ,increment))))
> b)
> 
> (defun lookup-sin2 (radians divisions)
>   (multiple-value-bind (table increment)
>       (get-sin-table-and-increment divisions)
>     (aref table (round radians increment))))

[This really does feel like it would make great homework.  Are you *sure*
 it's not?]

In (a) the get-sin-table-and-increment is done at "syntax analysis" (a.k.a.
"macro expansion") time.  This implies that the referent for the divisions
variable must be a literal constant since if it involves variable references
[and if it has the same definition as in (b)], it will not have necessary 
access to the lexical environment nor will the function 
get-sin-table-and-increment happen in the right dynamic environment.  But
if get-sin-table-and-increment is a "pure" function (not depending on dynamic
state) and if the argument divisions is indeed always a constant [something
the macro should probably double-check in order to make an informative
error message if the user screws up], then (a) is more efficient and 
desirable.  Otherwise, (b) is the only legal implementation since evaluation
occurs at runtime when the necessary information to complete the evaluation
at all is available.

> The complete source for this example is at the end.
> 
> 3.
> 
> Can you give me examples when omitting
> 
> (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
> 
> causes problems ? Or, in other words, when EVAL-WHEN
> is necessary ?

EVAL-WHEN is needed when its absence will result in an error.

Your question is conceptually equivalent to questions like:

 Can you give me examples when omitting
  (SETQ X 3)
 causes problems? Or, on other words, when is it necessary.

 The answer to the SETQ question is that you should assign X when
 X needs to be assigned and not assign it otherwise.

Evaluation can happen at any number of times.  It might happen in the
compiler, or in the loader, or at execution time.  If you need it done
in the compiler and you fail to do it, you're going to lose and you'd
better fix it with an appropriate EVAL-WHEN (assuming the form is 
at toplevel, the only place EVAL-WHEN will consider the :COMPILE-TOPLEVEL
keyword).  Analogously for load-time and :LOAD-TOPLEVEL.  Code defaultly
executes at :execute time, so the only reason you'd include that is if
you were also including another time and  you wanted the same code to *also*
occur at execute time, or if you wanted to inhibit the code from executing
at toplevel in the compiler or loader (e.g., in a situation where better
code was already being offered in a companion EVAL-WHEN that has 
:compile-toplevl and/or :load-toplevel).

[p.s.  I didn't take the time to look at your included code since it
didn't appear relevant to your questions.]
From: Vladimir V. Zolotych
Subject: Re: (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
Date: 
Message-ID: <3A61A4A6.2C0A0D82@eurocom.od.ua>
This is a multi-part message in MIME format.
--------------F19858F06527A202882F14A3
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Kent M Pitman wrote:

Thanks for help !

> 
> [This really does feel like it would make great homework.  Are you *sure*
>  it's not?]

Depends on what you're calling 'homework'. No one ask me to do that,
also
nobody waits for results. I'm learning Lisp for about few weeks. I'm
reading books those I can get. Things I can't understand alone I can try
to
ask. If I done that wrongly, excuse me. My aim is start using Lisp in my
work (now I've using C++/C).

> Your question is conceptually equivalent to questions like:
> 
>  Can you give me examples when omitting
>   (SETQ X 3)
>  causes problems? Or, on other words, when is it necessary.
> 
>  The answer to the SETQ question is that you should assign X when
>  X needs to be assigned and not assign it otherwise.

There is difference about these two questions (for me). For Q about
SETQ I'd answer 'When flow comes to point where value of X will be used
the result will be wrong'. But I didn't know what will happen
if I omit (EVAL-WHEN...) in construct like 

(EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
  (UNLESS (FIND-PACKAGE -NAME-)
    (MAKE-PACKAGE -NAME-
      :USE '(#+: cltl2 common-lisp
             #-: cltl2 lisp))))
(IN-PACKAGE -NAME-)
.....

Before I ask. Now (thanks to you) I understand better (although
sill not ultimately). I doesn't know something similar in other
languages I worked on.


-- 
Vladimir Zolotych                         ······@eurocom.od.ua
--------------F19858F06527A202882F14A3
Content-Type: text/x-vcard; charset=us-ascii;
 name="gsmith.vcf"
Content-Transfer-Encoding: 7bit
Content-Description: Card for Vladimir V. Zolotych
Content-Disposition: attachment;
 filename="gsmith.vcf"

begin:vcard 
n:Zolotych;Valdimir V.
x-mozilla-html:FALSE
adr:;;;;;;
version:2.1
·····················@eurocom.od.ua
x-mozilla-cpt:;0
fn:Valdimir V. Zolotych
end:vcard

--------------F19858F06527A202882F14A3--
From: Kent M Pitman
Subject: Re: (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
Date: 
Message-ID: <sfw1yu6vw5b.fsf@world.std.com>
"Vladimir V. Zolotych" <······@eurocom.od.ua> writes:

> There is difference about these two questions (for me). For Q about
> SETQ I'd answer 'When flow comes to point where value of X will be used
> the result will be wrong'. But I didn't know what will happen
> if I omit (EVAL-WHEN...) in construct like 
> 
> (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
>   (UNLESS (FIND-PACKAGE -NAME-)
>     (MAKE-PACKAGE -NAME-
>       :USE '(#+: cltl2 common-lisp
>              #-: cltl2 lisp))))

Without the EVAL-WHEN, the first time the system will attempt to evaluate
the UNLESS is at execution time.  (Since it's at top-level, execution time
and load-time are the same thing.)

> (IN-PACKAGE -NAME-)

Since the code from here downward in your file will be read in the -NAME-
package at compie time, but the -NAME- package will not be created until
load time, you will lose.

Packages contain symbols.  All Lisp code is a combination of lists and 
symbols and other constants which must be possible to turn from syntax into
objects at compile time.  Compilation semantics is defined in terms of 
objects.  If the compiler cannot create the symbols -NAME-::FOO and
-NAME-::X because there is no -NAME- package when (DEFUN FOO (X) X)
is read into the compiler, then there will be a read-time error in the
compiler.  To avoid this, one typically does just as you have above: adorn
the UNLESS with an EVAL-WHEN that tells the compiler to also evaluate this
form at compile time.

> Before I ask. Now (thanks to you) I understand better (although
> sill not ultimately). I doesn't know something similar in other
> languages I worked on.

Part of the issue is that in other languages there is not an explicit 
user-manipulable representation of objects.

Part of the issue is that in other languages the separation of "namespaces"
is a lexical matter, not a datastructure matter.  So the compiler can compile
references to undefined packages because the symbol X does not differ between
modules, only the binding associated with X does.  Lisp does this differently.
Lisp does not have a module system.  The reasons for this are complex and
I won't get into them for now, but at some point when you're feeling stronger
on the language semantics if you want to ask, we can talk about that 
separately.

Part of the issue, and the one that irks me the most, is that all of 
programming is a cascade of decision times (system design time, coding time,
read time, compile time, macro expansion time, load time, runtime, etc)
and yet most "static" langauges merely assert that all decisions are best
made at compile time and further that compile and read and macro expansion
time are all pretty much the same.  This forces programmers to make decisions
at wrong times.  Lisp gives you a lot of control of not only where but WHEN
you want your decisions made. That's partly because it's dynamic and partly
because it has notations like #. (in the reader) and EVAL-WHEN and
LOAD-TIME-VALUE and EVAL (in the language) which allow you to give a form
and say when it is to be processed.  This allows you not only to delay
decisions until later if need be, but sometimes to force them to be made
early.  The earlier a decision is made, the faster your program will run, but
the less flexible it will be.  You should always try to make all decisions 
at the earliest time that you have complete and accurate information to make
them correctly, but sometimes that may be very late in the game.  (An example
of places this is done very badly in other languages is method dispatch
in C++ and Java, where static compile-time information is preferred over
runtime dynamic information because it is faster, even if not necessarily
as correct as what Lisp does in CLOS.)

Happy studying.
From: Daniel Barlow
Subject: Re: (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
Date: 
Message-ID: <87vgrhc7pd.fsf@noetbook.telent.net>
"Vladimir V. Zolotych" <······@eurocom.od.ua> writes:

> (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
>   (UNLESS (FIND-PACKAGE -NAME-)
>     (MAKE-PACKAGE -NAME-
>       :USE '(#+: cltl2 common-lisp
>              #-: cltl2 lisp))))

As a random aside, according to the Hyperspec this won't necessarily
work in a conforming implementation - CLTL2 ought not to be in
*FEATURES*, and there's nothing that I can see in the standard to
require that the LISP package exists (unless CLTL1 is defined, anyway)

:cltl2 

      If present, indicates that the implementation purports to
      conform to Common Lisp: The Language, Second Edition.  This
      feature must not be present in any conforming implementation,
              ^^^^^^^^^^^^^^^^^^^
      since conformance to that document is not compatible with
      conformance to this specification. The name, however, is
      reserved by this specification in order to help programs
      distinguish implementations which conform to that document from
      implementations which conform to this specification.



-dan

-- 

  http://ww.telent.net/cliki/ - Link farm for free CL-on-Unix resources 
From: Kent M Pitman
Subject: Re: (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
Date: 
Message-ID: <sfwn1csrjjf.fsf@world.std.com>
Daniel Barlow <···@noetbook.telent.net> writes:

> "Vladimir V. Zolotych" <······@eurocom.od.ua> writes:
> 
> > (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
> >   (UNLESS (FIND-PACKAGE -NAME-)
> >     (MAKE-PACKAGE -NAME-
> >       :USE '(#+: cltl2 common-lisp
> >              #-: cltl2 lisp))))
> 
> As a random aside, according to the Hyperspec this won't necessarily
> work in a conforming implementation - CLTL2 ought not to be in
> *FEATURES*,

Indeed.

Not to mention the fact that you can't put spaces between the package name
and the symbol.  By default, all #+/#- references are read in the keyword
package anyway, so even if it were allowed, it'd be redundant to have the
colon there.  

But Daniel's right that you need to read about what the feature designations
really imply, and to think about what happens if an implementation over which
the HyperSpec has no jurisdiction happens not to adhere to the various wishes
the HyperSpec has...

I might suggest, by the way, that a feature-based way of doing this is not
right given you can more reliably detect what you want by introspection:

 :use '(#.(or (find-package "COMMON-LISP")
	      (find-package "LISP")
	      (error "Neither package COMMON-LISP nor LISP was found.")))

I'm pretty sure that will work in both CLTL1 and CLTL2 (though I didn't test
it).

Btw, a little aside about #+ and #-.  Back in Maclisp days, before packages,
I used to sometimes take advantage of the fact that the Lisp Machine did allow
package prefixes to be followed by whitespace, etc.  foo: on the lispm meant
foo::, since there was no "internal/external" distinction and any symbol could
be referenced with a single colon.  Doing FOO: meant "bind package to FOO and
then call READ" so you could do foo:(a b c) to get (foo:a foo:b foo:c), which
was very handy in patch files.  I really don't know why we didn't keep that
semantics.  But anyway, Maclisp didn't have packages, and so I often wrote:
  #+LISPM MYPACK: DO-SOMETHING
to mean "use MYPACK:DO-SOMETHING on the Lisp Machine and use just
DO-SOMETHING in Maclisp".  That is, Maclisp thought "MYPACK:" was a symbol
and read just that one token in its failing case of #+LISPM, leaving 
DO-SOMETHING unaffected.  The LispM saw MYPACK:DO-SOMETHING as a single thing
when it succeeded.  It was an awful kludge.  But I think about it every time
I see spaces in a packaged symbol name...
From: Nathan Froyd
Subject: Re: (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
Date: 
Message-ID: <slrn960s9c.2km.froydnj@froyd3.laptop.rose-hulman.edu>
In article <·················@eurocom.od.ua>, Vladimir V. Zolotych wrote:
>Few questions if you please...
>
>1.
> 
>Please explain me why I can't write
>
>(DEFMACRO OUTER (X) `(DEFMACRO INNER () `(,X 1 2)))
>
>but should write
>
>(DEFMACRO OUTER (X) `(DEFMACRO INNER () `(,',X 1 2)))
>
>Is there other solution to get X evaluated ?

The reason it has to be that way is because the backquotes nest, so you
have to unquote as many times as you've backquoted to get things to work
right.

There might be another solution, but I'm not sure what it is.

>(defmacro lookup-sin (radians divisions)
>  (multiple-value-bind (table increment)
>      (get-sin-table-and-increment divisions)
>    `(aref ,table (round ,radians ,increment))))

This version would get inserted inline into the source code.  So it
might be faster, but the resulting code might need to be recompiled if
something changed.

>(defun lookup-sin2 (radians divisions)
>  (multiple-value-bind (table increment)
>      (get-sin-table-and-increment divisions)
>    (aref table (round radians increment))))

You could make this inline like the macro above by declaring it inline.
That way you get the speed with none of the issues surrounding macros.
-- 
</nathan>  ·······@rose-hulman.edu  |  http://www.rose-hulman.edu/~froydnj/

Yes, God had a deadline.  So He wrote it all in Lisp.
From: Vladimir V. Zolotych
Subject: Re: (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
Date: 
Message-ID: <3A61E416.BE60A101@eurocom.od.ua>
This is a multi-part message in MIME format.
--------------24D3624EC858B6BC03F147B6
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Nathan Froyd wrote:

> You could make this inline like the macro above by declaring it inline.
> That way you get the speed with none of the issues surrounding macros.

How I can be sure the inline take place ? I've tried two
versions: with (DECLAIM (INLIME FACTORIAL)) and w/o it. But
seen no difference.  I used DISASSEMBLE to see the code.

What I've done in details:

Olla:~/cmucl$ lisp
CMU Common Lisp 18c, running on Olla
Send questions and bug reports to your local CMU CL maintainer, 
or to ··········@cons.org. and ·········@cons.org. respectively.
Loaded subsystems:
    Python 1.0, target Intel x86
    CLOS based on PCL version:  September 16 92 PCL (f)
* (declaim (inline fact2))

EXTENSIONS::%UNDEFINED%
(What is this mean ? )
* (defun fact2 (n) (if (zerop n) 1 (* n (fact2 (1- n)))))

FACT2
* (defun foo () (fact2 5))

FOO
* (compile 'foo)
Compiling LAMBDA NIL: 
Compiling Top-Level Form: 

FOO
NIL
NIL
* (disassemble 'foo)

4802B290:       .ENTRY FOO()                 ; (FUNCTION NIL *)
      A8:       POP   DWORD PTR [EBP-8]
      AB:       LEA   ESP, [EBP-32]

      AE:       TEST  ECX, ECX
      B0:       JNE   L0
      B2:       MOV   EDX, 20                ; No-arg-parsing entry
point
      B7:       MOV   EAX, [#x4802B288]
      BD:       MOV   ECX, 4
      C2:       PUSH  DWORD PTR [EBP-8]
      C5:       JMP   DWORD PTR [EAX+5]
      C8: L0:   BREAK 10                     ; Error trap
      CA:       BYTE  #x02
      CB:       BYTE  #x19                   ;
INVALID-ARGUMENT-COUNT-ERROR
      CC:       BYTE  #x4D                   ; ECX
* 

The same result I'll get when I just do the same except (DECLAIM (INLINE
FACT2)).
May be 

EXTENSIONS::%UNDEFINED%

mean the Lisp I'me using doesn't support inlining ?

Else I can suppose the compiler decides on its own when
do inline and when not.

Please correct me.

-- 
Vladimir Zolotych                         ······@eurocom.od.ua
--------------24D3624EC858B6BC03F147B6
Content-Type: text/x-vcard; charset=us-ascii;
 name="gsmith.vcf"
Content-Transfer-Encoding: 7bit
Content-Description: Card for Vladimir V. Zolotych
Content-Disposition: attachment;
 filename="gsmith.vcf"

begin:vcard 
n:Zolotych;Valdimir V.
x-mozilla-html:FALSE
adr:;;;;;;
version:2.1
·····················@eurocom.od.ua
x-mozilla-cpt:;0
fn:Valdimir V. Zolotych
end:vcard

--------------24D3624EC858B6BC03F147B6--
From: Colin Walters
Subject: Re: (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
Date: 
Message-ID: <874rz2qbam.church.of.emacs@meta.verbum.org>
"Vladimir V. Zolotych" <······@eurocom.od.ua> writes:

> How I can be sure the inline take place ? I've tried two versions:
> with (DECLAIM (INLIME FACTORIAL)) and w/o it. But seen no
> difference.  I used DISASSEMBLE to see the code.
> 
> What I've done in details:
> 
> Olla:~/cmucl$ lisp
> CMU Common Lisp 18c, running on Olla
> Send questions and bug reports to your local CMU CL maintainer, 
> or to ··········@cons.org. and ·········@cons.org. respectively.
> Loaded subsystems:
>     Python 1.0, target Intel x86
>     CLOS based on PCL version:  September 16 92 PCL (f)
> * (declaim (inline fact2))
> 
> EXTENSIONS::%UNDEFINED%
> (What is this mean ? )
> * (defun fact2 (n) (if (zerop n) 1 (* n (fact2 (1- n)))))
> 
> FACT2

Two things here.  First, I'm not sure if the CMUCL toplevel would
respect inline declarations.  Second, it is impossible to inline FACT2
- it is a recursive function.
From: Hartmann Schaffer
Subject: Re: (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
Date: 
Message-ID: <slrn963ltl.qv2.hs@paradise.nirvananet>
In article <·················@eurocom.od.ua>, Vladimir V. Zolotych wrote:
> ...
>How I can be sure the inline take place ? I've tried two
>versions: with (DECLAIM (INLIME FACTORIAL)) and w/o it. But
>seen no difference.  I used DISASSEMBLE to see the code.

well, factorial is a recursive function, which is pretty hard to inline with
finite memory

hs
From: Kent M Pitman
Subject: Re: (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
Date: 
Message-ID: <sfwzoguuhhh.fsf@world.std.com>
"Vladimir V. Zolotych" <······@eurocom.od.ua> writes:

> * (declaim (inline fact2))
> 
> EXTENSIONS::%UNDEFINED%
> (What is this mean ? )

My bet is that the return value of DECLAIM is not defined, yet since 
something is returned from all expressions, they chose to return the
symbol %UNDEFINED% in the EXTENSIONS package as the value they aren't
saying they're going to return. :-)
From: Tim Bradshaw
Subject: Re: (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
Date: 
Message-ID: <ey3vgrhenmo.fsf@cley.com>
* Erik Naggum wrote:

>   I would have expected no values to be returned, not some junk value.
>   If a value has to be returned, isn't nil the canonical useless value?

I remember, I think, asking about this, and being told that some point
was being made -- because the value was unspecified in the spec they
deliberately chose to return something slightly odd, I think as a way
of encouraging a value to be specified or no value (in the (values)
sense) to be specified.

However I may be confusing this with some other case, and in any case
I don't intend any slight to CMUCL implementors past or present.

--tim
From: Kent M Pitman
Subject: Re: (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
Date: 
Message-ID: <sfwg0ilprt9.fsf@world.std.com>
Tim Bradshaw <···@cley.com> writes:

> >   I would have expected no values to be returned, not some junk value.
> >   If a value has to be returned, isn't nil the canonical useless value?
> 
> I remember, I think, asking about this, and being told that some point
> was being made -- because the value was unspecified in the spec they
> deliberately chose to return something slightly odd, I think as a way
> of encouraging a value to be specified or no value (in the (values)
> sense) to be specified.
> 
> However I may be confusing this with some other case, and in any case
> I don't intend any slight to CMUCL implementors past or present.

In the T dialect of Scheme we used to do things like

 (define (something-with-undefined-result)
   (stuff-to-do)
   'something-with-undefined-result-result)

so that bugs could more easily be tracked down.

But the real point is that if you make the result "useful"
there's a risk someone will use it.  Never underestimate the
ingenuity of fools, they say...  NIL may be a canonical useless
result but is also very useful.

Back in Maclisp, TERPRI returned NIL and PRINT returned T.  (The reason
PRINT didn't return its arg was so that if the arg was stack-consed, it
didn't have to heap-cons it just to return it.)  But sometimes you'd see
code like:

  (COND ((AND (PRINT 'TRYING-FOO)
              (NOT (TERPRI))
              (FOO)
	      (PRINT 'TRYING-BAR)
              (NOT (TERPRI))
              (BAR))
          ...))

This used to drive me nuts since (a) someone shouldn't be relying on
these return values at all and (b) (NOT TERPRI) reads wrong since it
doesn't fail to do a newline.
From: ········@hex.net
Subject: Re: (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
Date: 
Message-ID: <hbt86.23476$n5.379352@news6.giganews.com>
Erik Naggum <····@naggum.net> writes:
> * Kent M Pitman <······@world.std.com>
> | My bet is that the return value of DECLAIM is not defined, yet since
> | something is returned from all expressions, they chose to return the
> | symbol %UNDEFINED% in the EXTENSIONS package as the value they aren't
> | saying they're going to return. :-)

>I would have expected no values to be returned, not some junk value.
>If a value has to be returned, isn't nil the canonical useless value?

There's a difference between unintentional uselessness and intentional
uselessness.

The way that some FORTRAN compilers would fill variables with visibly
_awful_ initial values was pretty useful in debugging; it meant that
the programmer would get some hint if the array was not appropriately
initialized.  Or if you accidentally missspelled a variable reference,
the reference to the "wrong thing" would lead to a dramatically wrong
value rather than merely 0.0 [the equivalent to NIL here :-)].

In FORTRAN, someone might use that accidental 0.0 for something, and
get a wrong result.  In Lisp, a NIL value can mean a number of things,
which is at least a _little_ dangerous...
-- 
(reverse (concatenate 'string ········@" "enworbbc"))
<http://www.ntlug.org/~cbbrowne/linux.html>
All syllogisms have three parts, therefore this is not a syllogism.
From: Pierre R. Mai
Subject: Re: (EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
Date: 
Message-ID: <87wvby108d.fsf@orion.bln.pmsf.de>
"Vladimir V. Zolotych" <······@eurocom.od.ua> writes:

> Olla:~/cmucl$ lisp
> CMU Common Lisp 18c, running on Olla
> Send questions and bug reports to your local CMU CL maintainer, 
> or to ··········@cons.org. and ·········@cons.org. respectively.
> Loaded subsystems:
>     Python 1.0, target Intel x86
>     CLOS based on PCL version:  September 16 92 PCL (f)
> * (declaim (inline fact2))
> 
> EXTENSIONS::%UNDEFINED%
> (What is this mean ? )

The ANSI CL standard states that the result of evaluating the declaim
form is undefined, meaning implementations can return whatever values
they like.  CMU CL returns the symbol ext::%undefined%, though it
could just as easily return 42, mostly in order to alert the user to
this fact.

> * (defun fact2 (n) (if (zerop n) 1 (* n (fact2 (1- n)))))
> 
> FACT2
> * (defun foo () (fact2 5))
> 
> FOO
> * (compile 'foo)

In CMU CL only the file-compiler will inline functions, i.e. put all
of the above forms in a file and compile this with compile-file, and
you'll get inlining.  Which brings us to the next problem:  You can't
inline directly-recursive functions, since this would result in an
endless loop at compile-time, recursively expanding the inlined
function in itself...  Most compilers will catch this, and break off
after some heuristic limit.  

> Else I can suppose the compiler decides on its own when
> do inline and when not.

The compiler is always free to decide whether to inline functions that
are declared inline, or not.

Regs, Pierre.

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein