From: jurgen_defurne
Subject: Use of macro's for conditional compilation ?
Date: 
Message-ID: <1157954966.610699.13140@q16g2000cwq.googlegroups.com>
Hello,

What I wanted to know is if it is possible to do a conditional
expansion in a macro, based upon the type of the argument.

This was my code :

(defmacro a-function (arg)
 (if (struct-a-p arg)
    `(a-function-for-struct-a arg)
    `(a-function-for-struct-b arg)))

The reason for trying it this way was that I wanted to have the maximum
speed for the used functions by declaring them inline, and depending on
the structure used at that point, compile a function for struct-a or
struct-b.

When it did not work I checked the value of arg which, at that point in
the macro, said CONS.

After looking through the CLHS and reading a little bit on the
newsgroup here I understand why it does not work now.

What I really want to know, however, is it possible what I wanted to
achieve, difficult or just plain impossible ?

And I know about CLOS and generic functions, but I have tested CLOS,
and while it might certainly have applications in more complex
settings, I want to extract the last drop of performance for my
program. A test program (in SBCL) written to test the access time to a
structure or an object, showed the access time to a structure to be two
times faster than CLOS.

Regards,

Jurgen

From: Ari Johnson
Subject: Re: Use of macro's for conditional compilation ?
Date: 
Message-ID: <m2zmd6pqn0.fsf@hermes.theari.com>
"jurgen_defurne" <··············@pandora.be> writes:

> What I wanted to know is if it is possible to do a conditional
> expansion in a macro, based upon the type of the argument.
>
> This was my code :
>
> (defmacro a-function (arg)
>  (if (struct-a-p arg)
>     `(a-function-for-struct-a arg)
>     `(a-function-for-struct-b arg)))
>

Anytime you are tempted to write "defmacro a-function," you might be
thinking of compiler macros.  But Pascal's response regarding how you
can know the type of arg at compile time is also quite relevant.
From: Pascal Bourguignon
Subject: Re: Use of macro's for conditional compilation ?
Date: 
Message-ID: <87odtmvrc3.fsf@thalassa.informatimago.com>
"jurgen_defurne" <··············@pandora.be> writes:

> Hello,
>
> What I wanted to know is if it is possible to do a conditional
> expansion in a macro, based upon the type of the argument.
>
> This was my code :
>
> (defmacro a-function (arg)
>  (if (struct-a-p arg)
>     `(a-function-for-struct-a arg)
>     `(a-function-for-struct-b arg)))
>
> The reason for trying it this way was that I wanted to have the maximum
> speed for the used functions by declaring them inline, and depending on
> the structure used at that point, compile a function for struct-a or
> struct-b.
>
> When it did not work I checked the value of arg which, at that point in
> the macro, said CONS.
>
> After looking through the CLHS and reading a little bit on the
> newsgroup here I understand why it does not work now.
>
> What I really want to know, however, is it possible what I wanted to
> achieve, difficult or just plain impossible ?

It is possible, or difficult, or plain impossible, depending on what
you expect exactly.

If you give to the macro (shouldn't you call it a-macro instead of
a-function?) a structure object, then it will perfectly work:

    (defstruct struct-a a)

    (defmacro a-macro (arg)
     (if (struct-a-p arg)
        `(a-function-for-struct-a arg)
        `(a-function-for-struct-b arg)))

    (macroexpand-1 '(a-macro #S(struct-a :a 'a)))
     --> (A-FUNCTION-FOR-STRUCT-A ARG) ;
         T

But of course, if you give it an expression instead of a struct-a, it
will intead select a-function-for-struct-b:

    (macroexpand-1 '(a-macro (make-struct-a :a 'a)))
    --> (A-FUNCTION-FOR-STRUCT-B ARG) ;
        T

Now, note how in both case it pass as argument to the function the
variable named ARG.  Which variable named ARG???

Let's correct this bug:


    (defmacro a-macro (arg)
     (if (struct-a-p arg)
        `(a-function-for-struct-a ,arg)
        `(a-function-for-struct-b ,arg)))


    (macroexpand-1 '(a-macro #S(struct-a :a 'a)))
    --> (A-FUNCTION-FOR-STRUCT-A #S(STRUCT-A :A 'A)) ;
        T
    
    (macroexpand-1 '(a-macro (make-struct-a :a 'a)))
    --> (A-FUNCTION-FOR-STRUCT-B (MAKE-STRUCT-A :A 'A)) ;
        T

The question you may want to ask is, are you sure that the function
MAKE-STRUCT-A will return a STRUCT-A?  How can you know that at
macroexpansion time?


In the first case, the struct-a is created at read time by the #S
reader macro.

In the second case, the struct-as will be created (possibly, probably)
at run time, by the function make-struct-a.  At macro expansion time,
we don't know it yet.


So if you want to select one algorithm or the other depending on
run-time values, you must select it at run-time.  Indeed, for this
using a generic function with specialized methods is a good idea.

The alternative, if you as programmer have prooved that at run time
you will only get values of struct-a type, then you can write directly:

   (A-FUNCTION-FOR-STRUCT-A (MAKE-STRUCT-A :A 'A))


> And I know about CLOS and generic functions, but I have tested CLOS,
> and while it might certainly have applications in more complex
> settings, I want to extract the last drop of performance for my
> program. A test program (in SBCL) written to test the access time to a
> structure or an object, showed the access time to a structure to be two
> times faster than CLOS.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
You never feed me.
Perhaps I'll sleep on your face.
That will sure show you.
From: Wade Humeniuk
Subject: Re: Use of macro's for conditional compilation ?
Date: 
Message-ID: <suhNg.3370$bf5.787@edtnps90>
jurgen_defurne wrote:
> Hello,
> 
> What I wanted to know is if it is possible to do a conditional
> expansion in a macro, based upon the type of the argument.
> 
> This was my code :
> 
> (defmacro a-function (arg)
>  (if (struct-a-p arg)
>     `(a-function-for-struct-a arg)
>     `(a-function-for-struct-b arg)))
> 

The simplest way would be to pass the type of argument directly
to the macro.  If you as a programmer can determine that
statically then .... something like (mimicking defmethod)

(defmacro a-function ((arg type))
  (ecase type
    (a `(a-function-for-struct-a ,arg))
    (b `(a-function-for-struct-b ,arg))))

CL-USER 1 > (macroexpand '(a-function (arg a)))
(A-FUNCTION-FOR-STRUCT-A ARG)
T

CL-USER 2 >

Wade
From: Thomas F. Burdick
Subject: Re: Use of macro's for conditional compilation ?
Date: 
Message-ID: <xcvhczdoe6o.fsf@conquest.OCF.Berkeley.EDU>
"jurgen_defurne" <··············@pandora.be> writes:

> Hello,
> 
> What I wanted to know is if it is possible to do a conditional
> expansion in a macro, based upon the type of the argument.
> 
> This was my code :
> 
> (defmacro a-function (arg)
>  (if (struct-a-p arg)
>     `(a-function-for-struct-a arg)
>     `(a-function-for-struct-b arg)))
> 
> The reason for trying it this way was that I wanted to have the maximum
> speed for the used functions by declaring them inline, and depending on
> the structure used at that point, compile a function for struct-a or
> struct-b.

Then you want to do this:

  (declaim (inline a-function))
  (defun a-function (arg)
    (etypecase arg
      (a (a-function-for-struct-a arg))
      (b (a-function-for-struct-b arg))))

At the points where a-function is called, if the compiler can
determine the type of arg, it will prune away the code for the other
branch(es).  If it cannot determine the type, it will have to keep the
runtime type-check.
From: Thomas A. Russ
Subject: Re: Use of macro's for conditional compilation ?
Date: 
Message-ID: <ymivenq7013.fsf@sevak.isi.edu>
"jurgen_defurne" <··············@pandora.be> writes:

> And I know about CLOS and generic functions, but I have tested CLOS,
> and while it might certainly have applications in more complex
> settings, I want to extract the last drop of performance for my
> program. A test program (in SBCL) written to test the access time to a
> structure or an object, showed the access time to a structure to be two
> times faster than CLOS.

To add to your CLOS knowledge, there is nothing that stops you from
using generic functions that dispatch on types introduced by DEFSTRUCT.
So you can still use the generic function dispatch to decide which
function to call at run-time while enjoying the faster access times of
structs versus classes.  This lets you use Pascal's solution to the
problem of run-time dispatch.

But the next question is whether you really need the last drop of
performance for your program.  How much of the TOTAL runtime of the
program is spent performing slot accesses?  Can you reduce that by using
local variables instead?  How much of an improvement does subsituting
structs for classes make in the final runtime of the program?


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Thomas F. Burdick
Subject: Re: Use of macro's for conditional compilation ?
Date: 
Message-ID: <xcvac51odlx.fsf@conquest.OCF.Berkeley.EDU>
···@sevak.isi.edu (Thomas A. Russ) writes:

> "jurgen_defurne" <··············@pandora.be> writes:
> 
> > And I know about CLOS and generic functions, but I have tested CLOS,
> > and while it might certainly have applications in more complex
> > settings, I want to extract the last drop of performance for my
> > program. A test program (in SBCL) written to test the access time to a
> > structure or an object, showed the access time to a structure to be two
> > times faster than CLOS.
> 
> To add to your CLOS knowledge, there is nothing that stops you from
> using generic functions that dispatch on types introduced by DEFSTRUCT.
> So you can still use the generic function dispatch to decide which
> function to call at run-time while enjoying the faster access times of
> structs versus classes.  This lets you use Pascal's solution to the
> problem of run-time dispatch.
> 
> But the next question is whether you really need the last drop of
> performance for your program.  How much of the TOTAL runtime of the
> program is spent performing slot accesses?  Can you reduce that by using
> local variables instead?  How much of an improvement does subsituting
> structs for classes make in the final runtime of the program?

These are all good questions, but since the poster is using a specific
implementation (SBCL) some other questions raise themselves; are you
losing anything by using structs versus defclass?  Although the spec
doesn't have defined semantics for structure redefinition, SBCL does.
You still only get single inheritance, and no before/after/around
methods on accessors, but that may be good enough for a given module.
Are you storing the types of values in your slots which you want to
declare?  The implementation treats structure slot definitions as
assertions, and is able to use that information when doing type
inference elsewhere.  A couple of :type (unsigned-byte 7) (vector
single-float) declarations in defstructs can be really helpful when
compiling at (speed 3), while keeping your code readable overall.
This last one is the big win for structures in SBCL, IMNSHO.
From: jurgen_defurne
Subject: Re: Use of macro's for conditional compilation ?
Date: 
Message-ID: <1158305955.525650.101740@p79g2000cwp.googlegroups.com>
Thomas F. Burdick wrote:
> ···@sevak.isi.edu (Thomas A. Russ) writes:
>
> > "jurgen_defurne" <··············@pandora.be> writes:
> >
> > > And I know about CLOS and generic functions, but I have tested CLOS,
> > > and while it might certainly have applications in more complex
> > > settings, I want to extract the last drop of performance for my
> > > program. A test program (in SBCL) written to test the access time to a
> > > structure or an object, showed the access time to a structure to be two
> > > times faster than CLOS.
> >
> > To add to your CLOS knowledge, there is nothing that stops you from
> > using generic functions that dispatch on types introduced by DEFSTRUCT.
> > So you can still use the generic function dispatch to decide which
> > function to call at run-time while enjoying the faster access times of
> > structs versus classes.  This lets you use Pascal's solution to the
> > problem of run-time dispatch.
> >
> > But the next question is whether you really need the last drop of
> > performance for your program.  How much of the TOTAL runtime of the
> > program is spent performing slot accesses?  Can you reduce that by using
> > local variables instead?  How much of an improvement does subsituting
> > structs for classes make in the final runtime of the program?
>
> These are all good questions, but since the poster is using a specific
> implementation (SBCL) some other questions raise themselves; are you
> losing anything by using structs versus defclass?  Although the spec
> doesn't have defined semantics for structure redefinition, SBCL does.
> You still only get single inheritance, and no before/after/around
> methods on accessors, but that may be good enough for a given module.
> Are you storing the types of values in your slots which you want to
> declare?  The implementation treats structure slot definitions as
> assertions, and is able to use that information when doing type
> inference elsewhere.  A couple of :type (unsigned-byte 7) (vector
> single-float) declarations in defstructs can be really helpful when
> compiling at (speed 3), while keeping your code readable overall.
> This last one is the big win for structures in SBCL, IMNSHO.

By using SBCL and its type system, and after asserting that my test
programs ran correctly, I could get an ultimate speedup of 600%
compared to my initial implementation which did not have any type
declarations.

Regards,

Jurgen
From: jurgen_defurne
Subject: Re: Use of macro's for conditional compilation ?
Date: 
Message-ID: <1158306705.383650.233220@k70g2000cwa.googlegroups.com>
Thomas A. Russ wrote:
> "jurgen_defurne" <··············@pandora.be> writes:
>
> > And I know about CLOS and generic functions, but I have tested CLOS,
> > and while it might certainly have applications in more complex
> > settings, I want to extract the last drop of performance for my
> > program. A test program (in SBCL) written to test the access time to a
> > structure or an object, showed the access time to a structure to be two
> > times faster than CLOS.
>
> To add to your CLOS knowledge, there is nothing that stops you from
> using generic functions that dispatch on types introduced by DEFSTRUCT.
> So you can still use the generic function dispatch to decide which
> function to call at run-time while enjoying the faster access times of
> structs versus classes.  This lets you use Pascal's solution to the
> problem of run-time dispatch.

The problem is, when I tried defining a generic function for my
structs, the first error message I got was that the class with the name
of the struct could not be found.

>
> But the next question is whether you really need the last drop of
> performance for your program.  How much of the TOTAL runtime of the
> program is spent performing slot accesses?  Can you reduce that by using
> local variables instead?  How much of an improvement does subsituting
> structs for classes make in the final runtime of the program?
>

Its difficult to count, but there really is a whole lot of slot access.
Every struct keeps a state which is necessary to define the next state.
I am simulating digital components at the function level (register,
ALU, controller), they keep an internal state in a structure, and they
are connected with each other through other structures.

Closures are ruled out here, because they are too private, and I need
access to all internals for visualisation.

Regards,

Jurgen
From: Thomas A. Russ
Subject: Re: Use of macro's for conditional compilation ?
Date: 
Message-ID: <ymi64fp6q2l.fsf@sevak.isi.edu>
"jurgen_defurne" <··············@pandora.be> writes:

> The problem is, when I tried defining a generic function for my
> structs, the first error message I got was that the class with the name
> of the struct could not be found.

The struct definitions need to be loaded before you can define methods
on them.  I'm not that familiar with SBCL's particular requirements, but
I would expect that if you define the structs in the same file as the
methods, you should be OK when file compiling.  But it may be necessary
to do them separately.

In my version of SBCL (0.9.4) on Mac OS X, I am able to do the following
in the REPL without any problems or warnings:

(defstruct foo a b)
(defgeneric create-list (s))
(defmethod create-list ((s foo))
  (list (foo-a s) (foo-b s)))
(defvar *f1* (make-foo :a 'a :b 6))
(create-list *f1*)
   ==> (A 6)


> Thomas A. Russ wrote:
> > But the next question is whether you really need the last drop of
> > performance for your program.  How much of the TOTAL runtime of the
> > program is spent performing slot accesses?  Can you reduce that by using
> > local variables instead?  How much of an improvement does subsituting
> > structs for classes make in the final runtime of the program?
> >
> 
> Its difficult to count, but there really is a whole lot of slot access.
> Every struct keeps a state which is necessary to define the next state.
> I am simulating digital components at the function level (register,
> ALU, controller), they keep an internal state in a structure, and they
> are connected with each other through other structures.

OK.  This sounds like a good application for structs.

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Ken Tilton
Subject: Re: Use of macro's for conditional compilation ?
Date: 
Message-ID: <tzCOg.2$B25.0@newsfe12.lga>
jurgen_defurne wrote:
> Thomas A. Russ wrote:
> 
>>"jurgen_defurne" <··············@pandora.be> writes:
>>
>>
>>>And I know about CLOS and generic functions, but I have tested CLOS,
>>>and while it might certainly have applications in more complex
>>>settings, I want to extract the last drop of performance for my
>>>program. A test program (in SBCL) written to test the access time to a
>>>structure or an object, showed the access time to a structure to be two
>>>times faster than CLOS.
>>
>>To add to your CLOS knowledge, there is nothing that stops you from
>>using generic functions that dispatch on types introduced by DEFSTRUCT.
>>So you can still use the generic function dispatch to decide which
>>function to call at run-time while enjoying the faster access times of
>>structs versus classes.  This lets you use Pascal's solution to the
>>problem of run-time dispatch.
> 
> 
> The problem is, when I tried defining a generic function for my
> structs, the first error message I got was that the class with the name
> of the struct could not be found.

I think you meant generic method. Either put the method definition after 
the struct definition (same requirement for CLOS classes by the way) or 
correct the typo in the struct name. :)

ken

-- 
Cells: http://common-lisp.net/project/cells/

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon