From: ·········@olive-it.ch
Subject: dynamic slots with macro
Date: 
Message-ID: <1176937827.582800.152060@n59g2000hsh.googlegroups.com>
I would like to create a clos object at run-time when knowing all the
slots (usefull wiht html-use-input or when analyzing a database)
.
the function (parse-wars-to-def-view-class wars) will produce the list
with the slot descriptions:
(parse-wars-to-def-view-class
  (list
    (CREATE-WAR :TYPE :LINE :NAME 'EMAIL :LABEL "plüöease enter your
email")
    (CREATE-WAR :TYPE :PASSWD :NAME 'HASHED-PASSWD :LABEL
             "plüöease enter your passwd")
    (CREATE-WAR :TYPE :PASSWD :NAME 'HASHED-PASSWD2 :LABEL
             "plüöease enter your passwd to verify")
    (CREATE-WAR :TYPE :LINE :NAME 'LOGNAME :LABEL "plüöease enter your
username")))
==>
((EMAIL :TYPE (STRING 250))
 (HASHED-PASSWD :TYPE (STRING 250))
 (HASHED-PASSWD2 :TYPE (STRING 250))
 (LOGNAME :TYPE (STRING 250)))
wars is a list of war (stands for web-variable)
I use this for my web-framework (thanks edi weitz for his tbnl and yes
i know tbnl is obsolete and will never be named later) i started
developing

Now here's the macro i got stuck:
(defmacro create-instance-with (wars)
  (let ((w (parse-wars-to-def-view-class wars)))
    `(clsql:def-view-class atest ()
      ((id :type integer
	:initarg :id
	:db-constraints
	(:auto-increment :key)))
      ,@w)))

When testing with
(create-instance-with (list (CREATE-WAR :TYPE :LINE :NAME
'EMAIL :LABEL "plüöease enter your email")
 (CREATE-WAR :TYPE :PASSWD :NAME 'HASHED-PASSWD :LABEL
             "plüöease enter your passwd")
 (CREATE-WAR :TYPE :PASSWD :NAME 'HASHED-PASSWD2 :LABEL
             "plüöease enter your passwd to verify")
 (CREATE-WAR :TYPE :LINE :NAME 'LOGNAME :LABEL "plüöease enter your
username")))

macroexpansion tells me that "list" is not a war (web-variable).
Well i got the message, but i don't know how to evaluate wars to the
effective list.  The macro is
most likely called with a variable like
(create-instance-with w) where w is a list of war -- and I got the
corresponding error message (in macroexpansion): The value w is not a
list.
Should I use (symbol-value wars) (I thought this is for special value)
or must i use the oh-so-big eval function/macro?

From: Pascal Costanza
Subject: Re: dynamic slots with macro
Date: 
Message-ID: <58olskF2hsgk8U1@mid.individual.net>
·········@olive-it.ch wrote:
> Now here's the macro i got stuck:
> (defmacro create-instance-with (wars)
>   (let ((w (parse-wars-to-def-view-class wars)))
>     `(clsql:def-view-class atest ()
>       ((id :type integer
> 	:initarg :id
> 	:db-constraints
> 	(:auto-increment :key)))
>       ,@w)))
> 
> When testing with
> (create-instance-with (list (CREATE-WAR :TYPE :LINE :NAME
> 'EMAIL :LABEL "pl��ease enter your email")
>  (CREATE-WAR :TYPE :PASSWD :NAME 'HASHED-PASSWD :LABEL
>              "pl��ease enter your passwd")
>  (CREATE-WAR :TYPE :PASSWD :NAME 'HASHED-PASSWD2 :LABEL
>              "pl��ease enter your passwd to verify")
>  (CREATE-WAR :TYPE :LINE :NAME 'LOGNAME :LABEL "pl��ease enter your
> username")))
> 
> macroexpansion tells me that "list" is not a war (web-variable).
> Well i got the message, but i don't know how to evaluate wars to the
> effective list.

Macros take parameters as is. If you want to evaluate them, you have to 
arrange your code such that this happens at runtime. So the first step 
is this:

(defmacro create-instance-with (wars)
   (let ((w (gensym)))
     `(let ((,w (parse-wars-to-def-view-class ,wars)))
        ...)))

Now the expression you pass to that macro will be correctly evaluated at 
runtime.

Now the problem is that you cannot pass the result through to the 
def-view-class macro because it expects declarative specifications of 
slots that are _not_ evaluated. There are two ways out: Either clsql 
provides a functional version of def-view-class. I don't know whether 
that's the case, you have to look this up in the clsql documentation. 
Maybe there is a way to say something like (make-instance 
'clsql:view-class ...) or (ensure-class 'atest :metaclass 
'clsql:view-class ...), or some such, but that's just speculation.

Or else, you have to use eval here. This is one of the rare exceptions 
where it's ok to use eval: when there is a macro that doesn't have a 
functional counterpart, but you want to use it with arguments evaluated 
at runtime. The code should roughly look like this:

(defmacro create-instance-with (wars)
   (let ((w (gensym)))
     `(let ((,w (...)))
        (eval `(clsql:def-view-class ... ,@,w)))))


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: ·········@olive-it.ch
Subject: Re: dynamic slots with macro
Date: 
Message-ID: <1176984057.157225.82930@q75g2000hsh.googlegroups.com>
On Apr 19, 10:00 am, Pascal Costanza <····@p-cos.net> wrote:

>
> Macros take parameters as is. If you want to evaluate them, you have to
> arrange your code such that this happens at runtime. So the first step
> is this:
>
> (defmacro create-instance-with (wars)
>    (let ((w (gensym)))
>      `(let ((,w (parse-wars-to-def-view-class ,wars)))
>         ...)))
>
Thanks, that's what i was looking for.
> Now the expression you pass to that macro will be correctly evaluated at
> runtime.
>
> Now the problem is that you cannot pass the result through to the
> def-view-class macro because it expects declarative specifications of
> slots that are _not_ evaluated. There are two ways out: Either clsql
> provides a functional version of def-view-class. I don't know whether
> that's the case, you have to look this up in the clsql documentation.
> Maybe there is a way to say something like (make-instance
> 'clsql:view-class ...) or (ensure-class 'atest :metaclass
> 'clsql:view-class ...), or some such, but that's just speculation.
>
Nop, didn't find anything similar
> Or else, you have to use eval here. This is one of the rare exceptions
> where it's ok to use eval: when there is a macro that doesn't have a
> functional counterpart, but you want to use it with arguments evaluated
> at runtime. The code should roughly look like this:
>
> (defmacro create-instance-with (wars)
>    (let ((w (gensym)))
>      `(let ((,w (...)))
>         (eval `(clsql:def-view-class ... ,@,w)))))
>
> Pascal
So basically my guts where right when they didn't find a solution
without eval.
However, I'm intrigued by the fact that you can't create a list whose
car is  clsql:def-view-class and whose cdr is any other list created
at run-time in the expansion-time of the macrocall and have it
evaluated.

macroexpansion ==>
(defclass anyname ()
  ((EMAIL :TYPE (STRING 250))
   (HASHED-PASSWD :TYPE (STRING 250))
   (HASHED-PASSWD2 :TYPE (STRING 250))
   (LOGNAME :TYPE (STRING 250))))
Then eval when the macro is called.
This is not possible without eval? I can't believe it. Is it
macroexpansion time?
>
> --
> 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: Pascal Costanza
Subject: Re: dynamic slots with macro
Date: 
Message-ID: <58p5clF2hg80hU1@mid.individual.net>
·········@olive-it.ch wrote:

>> Or else, you have to use eval here. This is one of the rare exceptions
>> where it's ok to use eval: when there is a macro that doesn't have a
>> functional counterpart, but you want to use it with arguments evaluated
>> at runtime. The code should roughly look like this:
>>
>> (defmacro create-instance-with (wars)
>>    (let ((w (gensym)))
>>      `(let ((,w (...)))
>>         (eval `(clsql:def-view-class ... ,@,w)))))
>>
>> Pascal
> So basically my guts where right when they didn't find a solution
> without eval.
> However, I'm intrigued by the fact that you can't create a list whose
> car is  clsql:def-view-class and whose cdr is any other list created
> at run-time in the expansion-time of the macrocall and have it
> evaluated.
> 
> macroexpansion ==>
> (defclass anyname ()
>   ((EMAIL :TYPE (STRING 250))
>    (HASHED-PASSWD :TYPE (STRING 250))
>    (HASHED-PASSWD2 :TYPE (STRING 250))
>    (LOGNAME :TYPE (STRING 250))))
> Then eval when the macro is called.
> This is not possible without eval? I can't believe it. Is it
> macroexpansion time?

Typically, it is the case that macros should be defined in terms of a 
functional API. It's best to have macros as syntactic sugar only and to 
ensure that you can do everything in terms of the underlying functional API.

However, in the case of CLOS, the functional API is not completely 
available, so there are certain things that you can do only with the 
various def-mumble macros. Libraries that provide functionality on top 
of CLOS do the same (probably more often than not because they simply 
expand into invocations of the CLOS def-mumble macros).

In fact, you can take a look at the expansion of, say, a defclass form, 
and you will actually notice that it expands into an invocation of some 
functions that perform the job of defining the class, etc. However, this 
underlying functional API is not standardized (and there is only a 
semi-specification - the CLOS MOP - that isn't part of ANSI Common Lisp, 
so it isn't guaranteed to be supported everywhere).

So that's the reason why using eval here is an acceptable exception to 
the general rule to avoid whenever possible: Since you only have the 
macros, but not the underlying functions available, there is no other 
way to get at what you want to do here. (However, see Rainer's posting 
for some other suggestions for possible workarounds.)


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: Rainer Joswig
Subject: Re: dynamic slots with macro
Date: 
Message-ID: <joswig-022964.10203319042007@news-europe.giganews.com>
In article <························@n59g2000hsh.googlegroups.com>,
 ·········@olive-it.ch wrote:

> I would like to create a clos object at run-time when knowing all the
> slots (usefull wiht html-use-input or when analyzing a database)
> .
> the function (parse-wars-to-def-view-class wars) will produce the list
> with the slot descriptions:
> (parse-wars-to-def-view-class
>   (list
>     (CREATE-WAR :TYPE :LINE :NAME 'EMAIL :LABEL "pl��ease enter your
> email")
>     (CREATE-WAR :TYPE :PASSWD :NAME 'HASHED-PASSWD :LABEL
>              "pl��ease enter your passwd")
>     (CREATE-WAR :TYPE :PASSWD :NAME 'HASHED-PASSWD2 :LABEL
>              "pl��ease enter your passwd to verify")
>     (CREATE-WAR :TYPE :LINE :NAME 'LOGNAME :LABEL "pl��ease enter your
> username")))
> ==>
> ((EMAIL :TYPE (STRING 250))
>  (HASHED-PASSWD :TYPE (STRING 250))
>  (HASHED-PASSWD2 :TYPE (STRING 250))
>  (LOGNAME :TYPE (STRING 250)))
> wars is a list of war (stands for web-variable)
> I use this for my web-framework (thanks edi weitz for his tbnl and yes
> i know tbnl is obsolete and will never be named later) i started
> developing
> 
> Now here's the macro i got stuck:
> (defmacro create-instance-with (wars)
>   (let ((w (parse-wars-to-def-view-class wars)))
>     `(clsql:def-view-class atest ()
>       ((id :type integer
> 	:initarg :id
> 	:db-constraints
> 	(:auto-increment :key)))
>       ,@w)))
> 
> When testing with
> (create-instance-with (list (CREATE-WAR :TYPE :LINE :NAME
> 'EMAIL :LABEL "pl��ease enter your email")
>  (CREATE-WAR :TYPE :PASSWD :NAME 'HASHED-PASSWD :LABEL
>              "pl��ease enter your passwd")
>  (CREATE-WAR :TYPE :PASSWD :NAME 'HASHED-PASSWD2 :LABEL
>              "pl��ease enter your passwd to verify")
>  (CREATE-WAR :TYPE :LINE :NAME 'LOGNAME :LABEL "pl��ease enter your
> username")))
> 
> macroexpansion tells me that "list" is not a war (web-variable).
> Well i got the message, but i don't know how to evaluate wars to the
> effective list.  The macro is
> most likely called with a variable like
> (create-instance-with w) where w is a list of war -- and I got the
> corresponding error message (in macroexpansion): The value w is not a
> list.
> Should I use (symbol-value wars) (I thought this is for special value)
> or must i use the oh-so-big eval function/macro?


1)

You can construct the list of WARs at read-time with #..

CL-USER> (read-from-string "#.(list 1 2 3)")
(1 2 3)

You have to make sure that at read time the necessary
information is available.

2)

You could create the right form as a list and then call EVAL.


3)

You could create the right form as a list, dump the
list to a file, compile and load that file.


4)

You could find out if there is a functional protocol
underneath DEF-VIEW-CLASS and use that if available.


---

Small naming convention I'd use:

CREATE-SOMETHING  would be a function.

DEF-SOMETHING  would be a macro.

-- 
http://lispm.dyndns.org
From: ·········@olive-it.ch
Subject: Re: dynamic slots with macro
Date: 
Message-ID: <1176984268.171507.50660@b58g2000hsg.googlegroups.com>
On Apr 19, 10:20 am, Rainer Joswig <······@lisp.de> wrote:
> In article <························@n59g2000hsh.googlegroups.com>,
>
>
>
>  ·········@olive-it.ch wrote:
> > I would like to create a clos object at run-time when knowing all the
> > slots (usefull wiht html-use-input or when analyzing a database)
> > .
> > the function (parse-wars-to-def-view-class wars) will produce the list
> > with the slot descriptions:
> > (parse-wars-to-def-view-class
> >   (list
> >     (CREATE-WAR :TYPE :LINE :NAME 'EMAIL :LABEL "plüöease enter your
> > email")
> >     (CREATE-WAR :TYPE :PASSWD :NAME 'HASHED-PASSWD :LABEL
> >              "plüöease enter your passwd")
> >     (CREATE-WAR :TYPE :PASSWD :NAME 'HASHED-PASSWD2 :LABEL
> >              "plüöease enter your passwd to verify")
> >     (CREATE-WAR :TYPE :LINE :NAME 'LOGNAME :LABEL "plüöease enter your
> > username")))
> > ==>
> > ((EMAIL :TYPE (STRING 250))
> >  (HASHED-PASSWD :TYPE (STRING 250))
> >  (HASHED-PASSWD2 :TYPE (STRING 250))
> >  (LOGNAME :TYPE (STRING 250)))
> > wars is a list of war (stands for web-variable)
> > I use this for my web-framework (thanks edi weitz for his tbnl and yes
> > i know tbnl is obsolete and will never be named later) i started
> > developing
>
> > Now here's the macro i got stuck:
> > (defmacro create-instance-with (wars)
> >   (let ((w (parse-wars-to-def-view-class wars)))
> >     `(clsql:def-view-class atest ()
> >       ((id :type integer
> >    :initarg :id
> >    :db-constraints
> >    (:auto-increment :key)))
> >       ,@w)))
>
> > When testing with
> > (create-instance-with (list (CREATE-WAR :TYPE :LINE :NAME
> > 'EMAIL :LABEL "plüöease enter your email")
> >  (CREATE-WAR :TYPE :PASSWD :NAME 'HASHED-PASSWD :LABEL
> >              "plüöease enter your passwd")
> >  (CREATE-WAR :TYPE :PASSWD :NAME 'HASHED-PASSWD2 :LABEL
> >              "plüöease enter your passwd to verify")
> >  (CREATE-WAR :TYPE :LINE :NAME 'LOGNAME :LABEL "plüöease enter your
> > username")))
>
> > macroexpansion tells me that "list" is not a war (web-variable).
> > Well i got the message, but i don't know how to evaluate wars to the
> > effective list.  The macro is
> > most likely called with a variable like
> > (create-instance-with w) where w is a list of war -- and I got the
> > corresponding error message (in macroexpansion): The value w is not a
> > list.
> > Should I use (symbol-value wars) (I thought this is for special value)
> > or must i use the oh-so-big eval function/macro?
>
> 1)
>
> You can construct the list of WARs at read-time with #..
>
> CL-USER> (read-from-string "#.(list 1 2 3)")
> (1 2 3)
>
> You have to make sure that at read time the necessary
> information is available.
>
When is read-time? I suppose it happens at compile-time, not at
running time?
> 2)
>
> You could create the right form as a list and then call EVAL.
>
There is no way without eval?
> 3)
>
> You could create the right form as a list, dump the
> list to a file, compile and load that file.
>
load ::= read from file + eval
> 4)
>
> You could find out if there is a functional protocol
> underneath DEF-VIEW-CLASS and use that if available.
>
see parent
> ---
>
> Small naming convention I'd use:
>
> CREATE-SOMETHING  would be a function.
>
> DEF-SOMETHING  would be a macro.
Ah, yes this is something I should keep in mind, thanx.
>
> --http://lispm.dyndns.org
From: Rainer Joswig
Subject: Re: dynamic slots with macro
Date: 
Message-ID: <joswig-F628E6.11081220042007@news-europe.giganews.com>
In article <·······················@b58g2000hsg.googlegroups.com>,
 ·········@olive-it.ch wrote:

> > You can construct the list of WARs at read-time with #..
> >
> > CL-USER> (read-from-string "#.(list 1 2 3)")
> > (1 2 3)
> >
> > You have to make sure that at read time the necessary
> > information is available.
> >
> When is read-time? I suppose it happens at compile-time, not at
> running time?

READ-TIME is whenever you read something.

When you compile a file (COMPILE-FILE), the
compiler needs to READ the forms and it compiles them.

When you LOAD a source file, the loader reads the forms
and executes each read form.

At the READ-EVAL-PRINT-LOOP, forms will be READ, then
evaluated, the result will be printed next.

You can invoke the reader in your program by calling
READ or READ-FROM-STRING.


This READer has a few things you can use to modify its
behavior.

1) readtable
2) a few variables
3) using #. to execute code

> > 2)
> >
> > You could create the right form as a list and then call EVAL.
> >
> There is no way without eval?


If you want a macro invocation on changing data which
is computed at runtime, then you need to create
that source form and compile/execute or evaluate it.

It is the nature of a Macro that it operates
on read source code and creates new source code.
The result of the macro expansion is code
that needs to be compiled and then executed
or needs to be interpreted.

EVAL is doing it in a way that is implementation dependent.
Some implementations don't have an interpreter or
don't invoke it by default. For them EVAL will
take source forms and run the usual macroexpand, compile
and execute sequence.

> > 3)
> >
> > You could create the right form as a list, dump the
> > list to a file, compile and load that file.
> >
> load ::= read from file + eval
> > 4)
> >
> > You could find out if there is a functional protocol
> > underneath DEF-VIEW-CLASS and use that if available.
> >
> see parent
> > ---
> >
> > Small naming convention I'd use:
> >
> > CREATE-SOMETHING  would be a function.
> >
> > DEF-SOMETHING  would be a macro.
> Ah, yes this is something I should keep in mind, thanx.
> >
> > --http://lispm.dyndns.org

-- 
http://lispm.dyndns.org