From: Ron Garret
Subject: Is there a way to do this without using EVAL?
Date: 
Message-ID: <rNOSPAMon-CE5295.14463315022007@news.gha.chartermi.net>
I want to write a macro that wraps defclass which evaluates (and 
type-checks) initforms at macroexpand time.  I can do this as follows:

(defmacro my-defclass (...)
  `(let ((initvals (list ,@(extract-iniforms ...))))
     (type-check initvals)
     (eval `(defclass ... ,@(stick-initvals-in-specs ... initvals)))))

But of course this triggers the general rule that if you're using eval 
you're almost certainly doing something wrong.  I think eval is actually 
necessary here because you need to produce a macroexpanded form to 
evaluate the initforms in the proper lexical environment, and then you 
have to use those values to produce *another* form which is the final 
macroexpansion, and this two-phase process requires you to explicitly 
eval either the initforms or the final expression (with lexical scoping 
requirements indicating the latter).  But I thought I'd check with the 
experts before I totally threw in the towel.

Thanks,
rg

From: Espen Vestre
Subject: Re: Is there a way to do this without using EVAL?
Date: 
Message-ID: <m1y7mzyqr6.fsf@gazonk.vestre.net>
Ron Garret <·········@flownet.com> writes:

> I want to write a macro that wraps defclass which evaluates (and 
> type-checks) initforms at macroexpand time.  

I'm too tired right now, so I don't quite get why you want to do this,
but couldn't you just use (assuming you accept a litte AMOP)
ensure-class?
-- 
  (espen)
From: Pascal Bourguignon
Subject: Re: Is there a way to do this without using EVAL?
Date: 
Message-ID: <87d54bf2le.fsf@thalassa.informatimago.com>
Ron Garret <·········@flownet.com> writes:

> I want to write a macro that wraps defclass which evaluates (and 
> type-checks) initforms at macroexpand time.  I can do this as follows:
>
> (defmacro my-defclass (...)
>   `(let ((initvals (list ,@(extract-iniforms ...))))
>      (type-check initvals)
>      (eval `(defclass ... ,@(stick-initvals-in-specs ... initvals)))))

If you want to typecheck at macroexpansion time, don't do it at run time!

(defmacro my-defclass (...)
  (let ((initvals (extract-iniforms ...)))                      ; MEX time
     (type-check initvals)                                      ; MEX time
     `(defclass ... ,@(stick-initvals-in-specs ... initvals)))) ; RUN time

should do.


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

WARNING: This product warps space and time in its vicinity.
From: Kaz Kylheku
Subject: Re: Is there a way to do this without using EVAL?
Date: 
Message-ID: <1171584517.589773.10320@v33g2000cwv.googlegroups.com>
On Feb 15, 3:00 pm, Pascal Bourguignon <····@informatimago.com> wrote:
> Ron Garret <·········@flownet.com> writes:
> > I want to write a macro that wraps defclass which evaluates (and
> > type-checks) initforms at macroexpand time.  I can do this as follows:
>
> > (defmacro my-defclass (...)
> >   `(let ((initvals (list ,@(extract-iniforms ...))))
> >      (type-check initvals)
> >      (eval `(defclass ... ,@(stick-initvals-in-specs ... initvals)))))
>
> If you want to typecheck at macroexpansion time, don't do it at run time!
>
> (defmacro my-defclass (...)
>   (let ((initvals (extract-iniforms ...)))                      ; MEX time
>      (type-check initvals)                                      ; MEX time
>      `(defclass ... ,@(stick-initvals-in-specs ... initvals)))) ; RUN time
>
> should do.

ROFL.

It's times like these that one regrets having been sucked in by
flamebait like ``Lisp-2 is a hacky but workable solution to the
problem of unintended name capture in macros.''
From: Pascal Costanza
Subject: Re: Is there a way to do this without using EVAL?
Date: 
Message-ID: <53k72uF1t3rvqU1@mid.individual.net>
Ron Garret wrote:
> I want to write a macro that wraps defclass which evaluates (and 
> type-checks) initforms at macroexpand time.  I can do this as follows:
> 
> (defmacro my-defclass (...)
>   `(let ((initvals (list ,@(extract-iniforms ...))))
>      (type-check initvals)
>      (eval `(defclass ... ,@(stick-initvals-in-specs ... initvals)))))
> 
> But of course this triggers the general rule that if you're using eval 
> you're almost certainly doing something wrong.  I think eval is actually 
> necessary here because you need to produce a macroexpanded form to 
> evaluate the initforms in the proper lexical environment, and then you 
> have to use those values to produce *another* form which is the final 
> macroexpansion, and this two-phase process requires you to explicitly 
> eval either the initforms or the final expression (with lexical scoping 
> requirements indicating the latter).  But I thought I'd check with the 
> experts before I totally threw in the towel.

No, an eval should not be necessary here because the initforms in a 
defclass are evaluated, and they are even evaluated in the current 
lexical environment.


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/
From: Ron Garret
Subject: Re: Is there a way to do this without using EVAL?
Date: 
Message-ID: <rNOSPAMon-86BE57.15325315022007@news.gha.chartermi.net>
In article <···············@mid.individual.net>,
 Pascal Costanza <··@p-cos.net> wrote:

> Ron Garret wrote:
> > I want to write a macro that wraps defclass which evaluates (and 
> > type-checks) initforms at macroexpand time.  I can do this as follows:
> > 
> > (defmacro my-defclass (...)
> >   `(let ((initvals (list ,@(extract-iniforms ...))))
> >      (type-check initvals)
> >      (eval `(defclass ... ,@(stick-initvals-in-specs ... initvals)))))
> > 
> > But of course this triggers the general rule that if you're using eval 
> > you're almost certainly doing something wrong.  I think eval is actually 
> > necessary here because you need to produce a macroexpanded form to 
> > evaluate the initforms in the proper lexical environment, and then you 
> > have to use those values to produce *another* form which is the final 
> > macroexpansion, and this two-phase process requires you to explicitly 
> > eval either the initforms or the final expression (with lexical scoping 
> > requirements indicating the latter).  But I thought I'd check with the 
> > experts before I totally threw in the towel.
> 
> No, an eval should not be necessary here because the initforms in a 
> defclass are evaluated, and they are even evaluated in the current 
> lexical environment.

I was unclear about one of my design goals.  I want the initforms to be 
evaluated only once, preferably at macroexpand time.  I also want them 
to be properly lexically scoped.  So for example:

(let ((x 1)) (defclass foo () ((x :initform (print (incf x))))))

This would print a different number every time an instance of FOO is 
created.


If you replaced defclass with my-defclass it should print one number (2) 
when the my-defclass form is evaluated, not print anything when 
instances of FOO are created, and all instances of FOO should have the X 
slot initialized to 2.  (And if the initform evaluated to something of 
the wrong type that error should be signaled at macroexpand time.)

And yes, I know that my code doesn't do all that.  But it comes closer 
than anything else I've been able to manage.

rg
From: Barry Margolin
Subject: Re: Is there a way to do this without using EVAL?
Date: 
Message-ID: <barmar-EA5F84.21101015022007@comcast.dca.giganews.com>
In article <·······························@news.gha.chartermi.net>,
 Ron Garret <·········@flownet.com> wrote:

> I was unclear about one of my design goals.  I want the initforms to be 
> evaluated only once, preferably at macroexpand time.  I also want them 
> to be properly lexically scoped.  So for example:
> 
> (let ((x 1)) (defclass foo () ((x :initform (print (incf x))))))
> 
> This would print a different number every time an instance of FOO is 
> created.
> 
> 
> If you replaced defclass with my-defclass it should print one number (2) 
> when the my-defclass form is evaluated, not print anything when 
> instances of FOO are created, and all instances of FOO should have the X 
> slot initialized to 2.  (And if the initform evaluated to something of 
> the wrong type that error should be signaled at macroexpand time.)

What you want to do is expand MY-DEFCLASS into DEFCLASS, where all the 
initforms are replaced with something like

(let ((val <initform>))
  (check-type val <type>)
  val)

E.g. the above form (using MY-DEFCLASS in place of DEFCLASS) would 
expand into:

(let ((x 1))
  (defclass foo () 
    ((x :initform (let ((val (print (incf x))))
                    (check-type val 'number)
                    val)))))

-- 
Barry Margolin, ······@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 ***
From: Pascal Costanza
Subject: Re: Is there a way to do this without using EVAL?
Date: 
Message-ID: <53kafqF1t0mh6U1@mid.individual.net>
Ron Garret wrote:

> I was unclear about one of my design goals.  I want the initforms to be 
> evaluated only once, preferably at macroexpand time.  I also want them 
> to be properly lexically scoped.  So for example:
> 
> (let ((x 1)) (defclass foo () ((x :initform (print (incf x))))))
> 
> This would print a different number every time an instance of FOO is 
> created.
> 
> 
> If you replaced defclass with my-defclass it should print one number (2) 
> when the my-defclass form is evaluated, not print anything when 
> instances of FOO are created, and all instances of FOO should have the X 
> slot initialized to 2.  (And if the initform evaluated to something of 
> the wrong type that error should be signaled at macroexpand time.)
> 
> And yes, I know that my code doesn't do all that.  But it comes closer 
> than anything else I've been able to manage.

In other words, you want this?

(let ((x 1))
   (let ((g123 (print (incf x))))
     (defclass foo () ((x :initform g123)))))


Then that's what your macro should expand into... ;)


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/
From: Ron Garret
Subject: Re: Is there a way to do this without using EVAL?
Date: 
Message-ID: <rNOSPAMon-1C2CD0.16171415022007@news.gha.chartermi.net>
In article <···············@mid.individual.net>,
 Pascal Costanza <··@p-cos.net> wrote:

> Ron Garret wrote:
> 
> > I was unclear about one of my design goals.  I want the initforms to be 
> > evaluated only once, preferably at macroexpand time.  I also want them 
> > to be properly lexically scoped.  So for example:
> > 
> > (let ((x 1)) (defclass foo () ((x :initform (print (incf x))))))
> > 
> > This would print a different number every time an instance of FOO is 
> > created.
> > 
> > 
> > If you replaced defclass with my-defclass it should print one number (2) 
> > when the my-defclass form is evaluated, not print anything when 
> > instances of FOO are created, and all instances of FOO should have the X 
> > slot initialized to 2.  (And if the initform evaluated to something of 
> > the wrong type that error should be signaled at macroexpand time.)
> > 
> > And yes, I know that my code doesn't do all that.  But it comes closer 
> > than anything else I've been able to manage.
> 
> In other words, you want this?
> 
> (let ((x 1))
>    (let ((g123 (print (incf x))))
>      (defclass foo () ((x :initform g123)))))
> 
> 
> Then that's what your macro should expand into... ;)

Duh.  I was trying to capture the values and stick those into the 
defclass form, but of course lexical variables capturing those values 
work just as well.  (I guess I forgot that the iniforms are properly 
lexically scoped.)

Now, where's my dunce cap?

Thanks.

rg
From: Pascal Bourguignon
Subject: Re: Is there a way to do this without using EVAL?
Date: 
Message-ID: <878xezf26d.fsf@thalassa.informatimago.com>
Pascal Costanza <··@p-cos.net> writes:
> Ron Garret wrote:
>> I want to write a macro that wraps defclass which evaluates (and
>> type-checks) initforms at macroexpand time.  I can do this as
>> follows:
>>
>> (defmacro my-defclass (...)
>>   `(let ((initvals (list ,@(extract-iniforms ...))))
>>      (type-check initvals)
>>      (eval `(defclass ... ,@(stick-initvals-in-specs ... initvals)))))
>>
>> But of course this triggers the general rule that if you're using
>> eval you're almost certainly doing something wrong.  I think eval is
>> actually necessary here because you need to produce a macroexpanded
>> form to evaluate the initforms in the proper lexical environment,
>> and then you have to use those values to produce *another* form
>> which is the final macroexpansion, and this two-phase process
>> requires you to explicitly eval either the initforms or the final
>> expression (with lexical scoping requirements indicating the
>> latter).  But I thought I'd check with the experts before I totally
>> threw in the towel.
>
> No, an eval should not be necessary here because the initforms in a
> defclass are evaluated, and they are even evaluated in the current
> lexical environment.

Well, this is another problem: can you do the type check at macro
expansion time at all if you don't have access to the lexical
environment where defclass runs?

(labels ((proper-list-p (x) ...))
   (my-defclass c ()
     ((a :type '(satisfies proper-list-p) :initform '()))))

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

"This machine is a piece of GAGH!  I need dual Opteron 850
processors if I am to do battle with this code!"
From: Ron Garret
Subject: Re: Is there a way to do this without using EVAL?
Date: 
Message-ID: <rNOSPAMon-3B3BD4.16022615022007@news.gha.chartermi.net>
In article <··············@thalassa.informatimago.com>,
 Pascal Bourguignon <···@informatimago.com> wrote:

> Pascal Costanza <··@p-cos.net> writes:
> > Ron Garret wrote:
> >> I want to write a macro that wraps defclass which evaluates (and
> >> type-checks) initforms at macroexpand time.  I can do this as
> >> follows:
> >>
> >> (defmacro my-defclass (...)
> >>   `(let ((initvals (list ,@(extract-iniforms ...))))
> >>      (type-check initvals)
> >>      (eval `(defclass ... ,@(stick-initvals-in-specs ... initvals)))))
> >>
> >> But of course this triggers the general rule that if you're using
> >> eval you're almost certainly doing something wrong.  I think eval is
> >> actually necessary here because you need to produce a macroexpanded
> >> form to evaluate the initforms in the proper lexical environment,
> >> and then you have to use those values to produce *another* form
> >> which is the final macroexpansion, and this two-phase process
> >> requires you to explicitly eval either the initforms or the final
> >> expression (with lexical scoping requirements indicating the
> >> latter).  But I thought I'd check with the experts before I totally
> >> threw in the towel.
> >
> > No, an eval should not be necessary here because the initforms in a
> > defclass are evaluated, and they are even evaluated in the current
> > lexical environment.
> 
> Well, this is another problem: can you do the type check at macro
> expansion time at all if you don't have access to the lexical
> environment where defclass runs?
> 
> (labels ((proper-list-p (x) ...))
>    (my-defclass c ()
>      ((a :type '(satisfies proper-list-p) :initform '()))))

I think I've realized one source of confusion: there are two different 
macroexpansion times and three different run times involved here:

1.  Macroexpansion of my-defclass
2.  Running my-defclass
3.  Macroexpansion of the defclass that my-defclass expands into
4.  Running that defclass and
5.  Creating instances of the resulting class

What I really want is for the initform evaluation and type checking to 
happen sometime before step 5.  Exactly where doesn't really matter that 
much to me (so it probably makes the most sense to do it in step 2).

rg