From: Chuck Fry
Subject: Substitute for COMPILER-LET?
Date: 
Message-ID: <6u1seh$sld$1@shell5.ba.best.com>
In an attempt to optimize some legacy code that needs a substantial
performance boost, I've run into a situation where I need to pass
information between outer and inner macro expanders.  The outer macros
define an accessing context; the inner macros use information passed by
the outer macros to allow optimization of the generated code.

I thought COMPILER-LET might do what I need in a straightforward manner.
I was dismayed to find out it isn't in ANSI CL.  Since this code must be
portable across at least two different CL implementations, I need to
find a portable solution.

The code below outlines the best idea I've had to date.  I'm not happy
with it on a couple of grounds, notably having to explicitly expand and
evaluate a macro at macro expansion time, and I'm open to suggestions.

From the user's point of view, DO-FOO performs an operation on a FOO
object.  The WITH-FOOS macro optimizes accesses to selected FOOs when
you know you'll be doing a lot with them.

From the implementor's point of view, the WITH-FOOS macro creates
temporary variables to hold the optimized FOO objects, and somehow hands
off information about these variables and objects to macros in its body,
including DO-FOO and possibly nested WITH-FOOS.  This information is
needed only at macro expansion time; ideally it would not exist at run
time, and should be hidden from the user.

The best idea I've had so far is to define a macro at top level that
expands to NIL (or perhaps other information known at compile time), and
whose definition is overridden by MACROLET within the expansion of a
WITH-FOO.

Does anyone have better ideas, or other comments about the approach
illustrated below?

 -- Chuck

(in-package :cl-user)


;;; Used internally by DO-FOOS; not advertised.
;;; This macro is overridden by a MACROLET in WITH-FOOS below.

(defmacro get-known-foos () nil)


;;; This macro:
;;;  - generates new variables for each foo in FOOS, and binds each
;;; to an optimized (pre-digested) version of its corresponding foo;
;;;  - provides information to macroexpanders within the body to allow
;;; references to the variables in FOOS to be replaced with
;;; references to the new variables containing optimized objects.

;;; FOOS is expected to be a list of variable names.

;;; This is an advertised interface.

(defmacro with-foos (foos &body body
                          &environment outer-env)
  (let* ((old-foos
          (eval (macroexpand '(get-known-foos) outer-env)))
         (known-foos
          (nconc (mapcar #'(lambda (foo) (list foo (gensym))) 
                         foos)
                 old-foos)))
    `(let ,(mapcar #'(lambda (entry)
                       (destructuring-bind (user-foo optimized-foo)
                                           entry
                         `(,optimized-foo (get-optimized-foo
,user-foo))))
                   known-foos)
       (macrolet ((get-known-foos () '',known-foos))
         ,@body))))



;;; Advertised interface for accessing foos.

(defmacro do-foo (a-foo &environment env)
  `(do-foo-1 ,a-foo ,(macroexpand '(get-known-foos) env)))


;;; Generates code for DO-FOO.  Not an advertised interface.

(defmacro do-foo-1 (a-foo known-foos)
  ;;(format t "~&KNOWN-FOOS = ~S~%" known-foos)
  (let ((alist-entry nil))
    (cond
     ((setf alist-entry (assoc a-foo (eval known-foos)))
      `(do-foo-optimized ,(second alist-entry)))
     (t
      `(do-foo-unoptimized ,a-foo)))))


;;; Optimize a foo.  Not advertised.

(defun get-optimized-foo (x)
  (string x))


;;; Call this function on optimized foos.  Not advertised.

(defun do-foo-optimized (x)
  (format t "~&The optimized foo: ~S~%" x))


;;; Call this version on unoptimized foos.  Not advertised.

(defun do-foo-unoptimized (x)
  (format t "~&The unoptimized foo: ~S~%" x))


;;; Demonstrate all of the above.

(defun foo-test ()
  (let ((a 'eh)
        (b 'be)
        (c 'ci))
    (with-foos (a)
      (with-foos (c)
        (do-foo a)                      ; s/b optimized outer
        (do-foo b)                      ; s/b unoptimized
        (do-foo c)                      ; s/b optimized inner
        ))))
-- 
	    Chuck Fry -- Jack of all trades, master of none
 ······@chucko.com (text only please)  ········@home.com (MIME enabled)
Lisp bigot, mountain biker, car nut, sometime guitarist and photographer

From: David D. Smith
Subject: Re: Substitute for COMPILER-LET?
Date: 
Message-ID: <dds-2109981323080001@x056.bit-net.com>
In article <············@shell5.ba.best.com>, ······@best.com (Chuck Fry) wrote:

> In an attempt to optimize some legacy code that needs a substantial
> performance boost, I've run into a situation where I need to pass
> information between outer and inner macro expanders.  The outer macros
> define an accessing context; the inner macros use information passed by
> the outer macros to allow optimization of the generated code.
> 
> I thought COMPILER-LET might do what I need in a straightforward manner.
> I was dismayed to find out it isn't in ANSI CL.  Since this code must be
> portable across at least two different CL implementations, I need to
> find a portable solution.

I had a similar problem in my implementation of TWIG.  I originally used
COMPILER-LET to hold information about each TWIG. and its destructred
bindings, for compilation (and subsequent  macroexpansions) of the body. 
Although MCL retained COMPILER-LET, a opted to move to a "portable"
approach.  My approach turned out not to be portable, to FrACL PC at
least.  I bound the tree info, and the synthesised labels for subnode
binding. etc. to SYMBOL macros.  They worked fine in MCL, but were
inaccesible in FrACL.

Using SYMBOL-MACROLET/MACROEXPAND turned out to be a considerably more
work than COMPILER-LET, and obscured the workings of the code.  I don't
know why COMPILER-LET was deprecated/removed.  I wound up having to
"simulate" COMPILER-LET for the FrACL version of TWIG anyway, but with
assignments SPECIAL.  The idea was the that the dross whould be absent
from the final compiler build from precompiled code.

 
> The best idea I've had so far is to define a macro at top level that
> expands to NIL (or perhaps other information known at compile time), and
> whose definition is overridden by MACROLET within the expansion of a
> WITH-FOO.

This is the basic approach I use, but I use SYMBOL-MACROLET where possible.


d
From: Kent M Pitman
Subject: Re: Substitute for COMPILER-LET?
Date: 
Message-ID: <sfwyardxd4k.fsf@world.std.com>
Btw, I pointed Chucko to the discussion of the compiler-let workaround
in x3j13 issue COMPILER-LET-CONFUSION and he said that was helpful.
Anyone with the same issue should chcek there.  I haven't looked
recently at it myself, but I remember they worked it out in fair
detail at the time.
From: Chuck Fry
Subject: Re: Substitute for COMPILER-LET?
Date: 
Message-ID: <6u75us$57a$1@shell5.ba.best.com>
In article <····················@x056.bit-net.com>,
David D. Smith <···@flavors.com> wrote:
>I had a similar problem in my implementation of TWIG.  I originally used
>COMPILER-LET to hold information about each TWIG. and its destructred
>bindings, for compilation (and subsequent  macroexpansions) of the body. 
>Although MCL retained COMPILER-LET, a opted to move to a "portable"
>approach.  My approach turned out not to be portable, to FrACL PC at
>least.  I bound the tree info, and the synthesised labels for subnode
>binding. etc. to SYMBOL macros.  They worked fine in MCL, but were
>inaccesible in FrACL.

This is interesting.  I'd heard that SYMBOL-MACROLET was broken (for
some value of "broken") in MCL.  This is the first I've heard of a
problem in Allegro CL.

Can anyone who knows the details please elaborate?

I wrote:
>> The best idea I've had so far is to define a macro at top level that
>> expands to NIL (or perhaps other information known at compile time), and
>> whose definition is overridden by MACROLET within the expansion of a
>> WITH-FOO.
>
>This is the basic approach I use, but I use SYMBOL-MACROLET where possible.

This would seem slightly cleaner for my application, if it's truly
portable.  For the record the two implementations we're using for this
project are Allegro CL 4.3 (SPARC) for development and Harlequin
LispWorks 3.x (PPC) for delivery.  I'd also appreciate it if the
solution ran on MCL, since some of our team prefers it for development,
and I use it at home.

Thanks again to Kent for privately suggesting I look at the X3J13 issue
COMPILER-LET-CONFUSION.  The description there illustrates quite nicely
how to use MACROLET or SYMBOL-MACROLET for just this sort of
application, though as David points out in a quote I omitted, the result
is not the clearest code you could want.

 -- Chuck
-- 
	    Chuck Fry -- Jack of all trades, master of none
 ······@chucko.com (text only please)  ········@home.com (MIME enabled)
Lisp bigot, mountain biker, car nut, sometime guitarist and photographer
From: Erik Naggum
Subject: Re: Substitute for COMPILER-LET?
Date: 
Message-ID: <3115444919322734@naggum.no>
* ······@best.com (Chuck Fry)
| This is interesting.  I'd heard that SYMBOL-MACROLET was broken (for some
| value of "broken") in MCL.  This is the first I've heard of a problem in
| Allegro CL.
| 
| Can anyone who knows the details please elaborate?

  "Allegro Common Lisp" was used both of the CLtL1-based Windows version
  (latest was 3.0.2) and the Real Thing under Unix (latest 4.3.1).  _lots_
  of things were seriously broken in ACL 3 for Windows that worked fine in
  ACL 4 for Unix.  thankfully, this horrible confusion is now history, and
  all platforms use the same system, now, in ACL 5.0.

#:Erik
-- 
  ATTENTION, all abducting aliens!  you DON'T need to RETURN them!
From: David D. Smith
Subject: Re: Substitute for COMPILER-LET?
Date: 
Message-ID: <dds-2309980348300001@x052.bit-net.com>
In article <············@shell5.ba.best.com>, ······@best.com (Chuck Fry) wrote:

> In article <····················@x056.bit-net.com>,
> David D. Smith <···@flavors.com> wrote:
> >I had a similar problem in my implementation of TWIG.  I originally used
> >COMPILER-LET to hold information about each TWIG. and its destructred
> >bindings, for compilation (and subsequent  macroexpansions) of the body. 
> >Although MCL retained COMPILER-LET, a opted to move to a "portable"
> >approach.  My approach turned out not to be portable, to FrACL PC at
> >least.  I bound the tree info, and the synthesised labels for subnode
> >binding. etc. to SYMBOL macros.  They worked fine in MCL, but were
> >inaccesible in FrACL.
> 
> This is interesting.  I'd heard that SYMBOL-MACROLET was broken (for
> some value of "broken") in MCL.  This is the first I've heard of a
> problem in Allegro CL.
> 
> Can anyone who knows the details please elaborate?

Dredgeing from possibly faulty memory...

The forms I generate for compilation bind environments to compile time
symbols via SYMBOL-MACROLET, and I retrieve them during macroexpansion via
MACROEXPAND.

I never had any problem with MCL.

In ACLPC 3.x this didn't work.  The binding wasn't accessible via
MACROEXPAND.  Curriously the Steele example from CLtL 2, 7.5 p156 works at
top level in ACLPC3.x, but not at the breakpoint entered during the error
I generated in the compiler.

I did not pursue the matter, just hacked around it.

From my archives:
________________________________________________________
My bug report:
________________________________________________________
To: Bug.acl
From: Duncan Smith <···@flavors.com>
Subject: SYMBOL-MACROLET Does What?
Cc: e, Yamagen.Internet
Bcc: 
X-Attachments: 

Your SYMBOL-MACROLET is not up to X3J13 March 89 <172> <173>

CLtL 2, 7.5 p156, Example

You have:

>> (symbol-macrolet ((pollyanna 'goody))
     (list pollyanna (let ((pollyanna 'two-shoes)) pollyanna)))
>>[Control-E]
(GOODY GOODY)
>>[Control-M]
((LAMBDA ()
    (DECLARE)
    (LIST #1='GOODY
       ((LAMBDA (POLLYANNA)
           (DECLARE)
           #1#)
          'TWO-SHOES))))
>>




******

P.S. This is a showstopper.
___________________________________________________________
Franz's request for more info...
___________________________________________________________
Date: Fri, 25 Apr 1997 17:35:32 -0700
From: ·······@Franz.COM (Alice Ng)
To: ···@flavors.com
Class: bh
Bh-Id: pcspr4585
Bh: append pcspr4585
Subject: Re: [pcspr4585] SYMBOL-MACROLET Does What?
Cc: ··········@Franz.COM, ·@flavors.com, ·······@yaskawa.co.jp


Duncan Smith:

   Your SYMBOL-MACROLET is not up to X3J13 March 89 <172> <173>.

On a fresh Allegro CL for Windows 3.0.2, the correct answer, which is
(goody two-shoes), is returned.  The following is a transcript of our
testing of the example taken from CLtL2, page 156:

   Welcome to Allegro CL for Windows
   Version: 3.0.2 Release: 15-Jan-97 18:56
   Copyright (C) 1992-1997, Franz Inc., Berkeley, CA, USA.
   All rights reserved.
   Loaded Franz Inc. Patches: None.

   > (symbol-macrolet ((pollyanna 'goody))
       (list pollyanna (let ((pollyanna 'two-shoes)) pollyanna)))
   (GOODY TWO-SHOES)
   > 

In order to determine what is causing the problem on your side, please
send us more information and a transcript of what you did.

                  Sincerely,
                  Alice Ng

Alice Ng       Franz Inc.
·······@franz.com    1995 University Avenue, Suite 275
phone(510) 548-3600     Berkeley, CA 94704-1072
fax  (510) 548-8253     ACL FAQs: http://www.franz.com/support/ or
                 ftp://ftp.franz.com:/pub/*faq

NB: Please cc ··········@franz.com on all mail related to this matter.
Be sure to include tracking number pcspr4585 on the subject line.
___________________________________________________________

d
From: Duane Rettig
Subject: Re: Substitute for COMPILER-LET?
Date: 
Message-ID: <4af3qzu68.fsf@beta.franz.com>
···@flavors.com (David D. Smith) writes:

> In article <············@shell5.ba.best.com>, ······@best.com (Chuck Fry) wrote:
> 
> > In article <····················@x056.bit-net.com>,
> > David D. Smith <···@flavors.com> wrote:
> > >I had a similar problem in my implementation of TWIG.
> > [ ... ]  They worked fine in MCL, but were
> > >inaccesible in FrACL.
> > 
> > This is interesting.  I'd heard that SYMBOL-MACROLET was broken (for
> > some value of "broken") in MCL.  This is the first I've heard of a
> > problem in Allegro CL.
> > 
> > Can anyone who knows the details please elaborate?

I think that the differences in experience above come from the
fact that there are (were) two different implementations of Allegro CL.
Now that ACL5 is out, in which the Windows side has been reimplemented
from the (conforming) unix implementation, I am hoping that such
confusion will eventually disappear.

> Dredgeing from possibly faulty memory...
> 
> The forms I generate for compilation bind environments to compile time
> symbols via SYMBOL-MACROLET, and I retrieve them during macroexpansion via
> MACROEXPAND.
> 
> I never had any problem with MCL.
> 
> In ACLPC 3.x this didn't work.  The binding wasn't accessible via
> MACROEXPAND.  Curriously the Steele example from CLtL 2, 7.5 p156 works at
> top level in ACLPC3.x, but not at the breakpoint entered during the error
> I generated in the compiler.

ACLPC 3.x was essentially a CLtL1-conformant lisp to which CLOS was
added.  In many ways this "enhancement" actually confused people
because it did not move all the way to CLtL2/ANSI conformance.
It is interesting to note that at the beginning of the discussion
of symbol-macrolet on p 155, it is mentioned that symbol-macrolet
was added as a piece of the CLOS system.  I had never noticed this
before; I knew that symbol-macrolet was an X3J13 addition, but
hadn't realized that it was part of CLOS.  I guess that explains
why symbol-macrolet was in ACLPC 3.x at all.

> I did not pursue the matter, just hacked around it.

-- 
Duane Rettig          Franz Inc.            http://www.franz.com/ (www)
1995 University Ave Suite 275  Berkeley, CA 94704
Phone: (510) 548-3600; FAX: (510) 548-8253   ·····@Franz.COM (internet)