|
|||
|
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 |
|
|
||||
|
||||
|
|
|
|||
|
"jurgen_defurne" <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. |
|
|||
|
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 |
|
|||
|
"jurgen_defurne" <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. |
|
|||
|
"jurgen_defurne" <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 |
|
|||
|
tar@sevak.isi.edu (Thomas A. Russ) writes:
> "jurgen_defurne" <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. |
|
|||
|
Thomas F. Burdick wrote:
> tar@sevak.isi.edu (Thomas A. Russ) writes: > > > "jurgen_defurne" <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 |
|
|||
|
Thomas A. Russ wrote: > "jurgen_defurne" <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 |
|
|||
|
"jurgen_defurne" <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 |
|
|||
|
jurgen_defurne wrote: > Thomas A. Russ wrote: > >>"jurgen_defurne" <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 |
|
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Re: Reset compiled macros | toby dunn | Newsgroup comp.soft-sys.sas | 0 | 02-06-2006 01:38 PM |
| Re: Why not use macros ? | Ben Powell | Newsgroup comp.soft-sys.sas | 0 | 01-19-2006 07:40 AM |
| Re: Why not use macros ? | Pudding Man | Newsgroup comp.soft-sys.sas | 0 | 01-17-2006 08:24 PM |
| Re: Why not use macros ? | David L Cassell | Newsgroup comp.soft-sys.sas | 0 | 01-13-2006 01:26 AM |
| Re: The advantage and disadvanatge of using SAS Macros | Jim Simmons | Newsgroup comp.soft-sys.sas | 1 | 04-16-2005 03:33 PM |