Prev: mod_lisp, apache
Next: Principal Component Analysis
From: Tamas K Papp on 21 May 2010 05:34 Hi, I am considering migrating part of some code from classes to structures. I am doing this because I read that structures can lead to gains in speed in some cases. The code is mature now, and I expect few changes. I am not using the MOP or anything fancy, so I guess structs should work fine. I have a general and a specific question: 1. I would be interested in hearing about projects where a similar change was undertaken, and whether it lead to significant speed improvements (I am using SBCL, but the project will be portable, all stories are welcome). 2. A specific question: I am wondering how to do consistency checks on certain objects. Eg if I want to ensure that two slots are always equal, for classes I would just have an INITIALIZE-INSTANCE :AFTER method to check that. I came up with the following for structs: (defstruct (foo (:constructor make-foo% (a b))) ;; make-foo% not exported (a 0 :type fixnum :read-only t) (b 0 :type fixnum :read-only t)) (defun make-foo (a b) (assert (= a b)) (make-foo% a b)) Is there a simpler way? Thanks, Tamas
From: Stelian Ionescu on 21 May 2010 07:01 On Fri, 21 May 2010 09:34:32 +0000, Tamas K Papp wrote: > 2. A specific question: I am wondering how to do consistency checks on > certain objects. Eg if I want to ensure that two slots are always > equal, for classes I would just have an INITIALIZE-INSTANCE :AFTER > method to check that. I came up with the following for structs: > > (defstruct (foo (:constructor make-foo% (a b))) > ;; make-foo% not exported > (a 0 :type fixnum :read-only t) > (b 0 :type fixnum :read-only t)) > > (defun make-foo (a b) > (assert (= a b)) > (make-foo% a b)) > > Is there a simpler way? (defstruct (foo (:constructor %make-foo (a b))) ;; make-foo% not exported (a 0 :type fixnum :read-only t) (b 0 :type fixnum :read-only t)) (defun make-foo (a) (make-foo% a a)) -- Stelian Ionescu a.k.a. fe[nl]ix Quidquid latine dictum sit, altum videtur. http://common-lisp.net/project/iolib
From: Thomas A. Russ on 21 May 2010 13:10 Tamas K Papp <tkpapp(a)gmail.com> writes: > Hi, > > I am considering migrating part of some code from classes to > structures. I am doing this because I read that structures can lead > to gains in speed in some cases. The code is mature now, and I expect > few changes. I am not using the MOP or anything fancy, so I guess > structs should work fine. I have a general and a specific question: Of course, question one is whether your current code is fast enough? If it is, then there might not be much in the way of gains to be worth making the effort to switch. > 1. I would be interested in hearing about projects where a similar > change was undertaken, and whether it lead to significant speed > improvements (I am using SBCL, but the project will be portable, all > stories are welcome). Our Stella system (and by extension PowerLoom) has the option of producing either CLOS-based or STRUCT-based objects. We have found that we can get a speed-up using the struct-based code that is between 1.5x and 2x that of the CLOS-based code. This does cause some re-working of, in particular, the accesors, since they are no longer generic functions but normal functions (well they compile down to array accesses). That gives us a lot of the speed-up, but it also means that one often has to know a bit more about exactly what items one is accessing. We do still use generic functions and methods to do operations other than slot access on the class or struct instances, so our speedup really comes from a combination of a (slightly) smaller memory footprint and the use of more efficient accessors to get slot values. > 2. A specific question: I am wondering how to do consistency checks on > certain objects. Eg if I want to ensure that two slots are always > equal, for classes I would just have an INITIALIZE-INSTANCE :AFTER > method to check that. I came up with the following for structs: Well, it seems like you really like some of the features that you can get from CLOS, so unless you think the speedup is worth it, you may be happier just staying with CLOS. > > (defstruct (foo (:constructor make-foo% (a b))) > ;; make-foo% not exported > (a 0 :type fixnum :read-only t) > (b 0 :type fixnum :read-only t)) > > (defun make-foo (a b) > (assert (= a b)) > (make-foo% a b)) > > Is there a simpler way? Not really. Since you don't have the more sophisticated initialization protocol of CLOS, you have to put all of that checking into your struct constructor. You will still not have anything that maintains the constraint about A and B remaining the same if one of them changes. You can do that with SETF methods on the classes but you can't do that for structs. -- Thomas A. Russ, USC/Information Sciences Institute
From: Pascal J. Bourguignon on 23 May 2010 08:41 Tamas K Papp <tkpapp(a)gmail.com> writes: > Hi, > > I am considering migrating part of some code from classes to > structures. I am doing this because I read that structures can lead > to gains in speed in some cases. The code is mature now, and I expect > few changes. I am not using the MOP or anything fancy, so I guess > structs should work fine. I have a general and a specific question: > > 1. I would be interested in hearing about projects where a similar > change was undertaken, and whether it lead to significant speed > improvements (I am using SBCL, but the project will be portable, all > stories are welcome). > > 2. A specific question: I am wondering how to do consistency checks on > certain objects. Eg if I want to ensure that two slots are always > equal, for classes I would just have an INITIALIZE-INSTANCE :AFTER > method to check that. I came up with the following for structs: > > (defstruct (foo (:constructor make-foo% (a b))) > ;; make-foo% not exported > (a 0 :type fixnum :read-only t) > (b 0 :type fixnum :read-only t)) > > (defun make-foo (a b) > (assert (= a b)) > (make-foo% a b)) > > Is there a simpler way? I recently wrote this macro: (defmacro define-destructuring-structure (name &rest arguments) (let ((docstring (when (and (rest arguments) (stringp (first arguments))) (pop arguments))) (documented-lambda-list (pop arguments)) (checks arguments)) (flet ((documentation-map (documented-lambda-list) ;; FIXME: use source-form to parse the macro-lambda-list and retrieve the parameter names. (mapcar (lambda (x) (list (first x) (second x))) (remove '&key documented-lambda-list))) (lambda-list (documented-lambda-list) ;; FIXME: use source-form to parse the macro-lambda-list and retrieve the parameter names. (mapcar (lambda (x) (if (atom x) x (first x))) documented-lambda-list)) (parameter-names (lambda-list) ;; FIXME: use source-form to parse the macro-lambda-list and retrieve the parameter names. (remove '&key lambda-list))) (let* ((docstring-map (documentation-map documented-lambda-list)) (lambda-list (lambda-list documented-lambda-list)) (parameter-names (parameter-names lambda-list))) `(progn (defstruct ,name ,(format nil "~%A ~S structure contains the following fields:~:{~% ~30D ~A~}~%~@[~A~%~]" name docstring-map docstring) ,@parameter-names) (defun ,(conc-name 'parse name) (arguments) ,(format nil "Parse a ~S structure." name) (destructuring-bind ,lambda-list arguments (progn ,@check) (,(conc-name 'make name) ,@(mapcan (lambda (pn) (list (keywordize pn) pn)) parameter-names)))) ',name))))) so that I can write things like: (define-destructuring-structure point "A little destructuring structure for an example." ((x "the X coordinate") (y "the Y coordinate") &key (color "the color of the point") (charm "the charm of the point")) ;; here come code inserted in the constructor. (assert (imply (< x y) (redp color))) (assert (imply (> x y) charm))) (list (parse-point 0 0 :color 'blue) (parse-point 42 24 :charm t :color 'blue)) Playing with defstruct conc-name option could also be done. But the point is that there is always a simplier way to write things, as long as you are able to write the macro and functions needed to implement this more concise language. Also, I would advise to define your entities with your own set of macros instead of defclass or defstruct, so that you can switch from one to the other easily. I could easily change the defstruct in my define-destructuring-macro into a defclass... -- __Pascal Bourguignon__ http://www.informatimago.com/
|
Pages: 1 Prev: mod_lisp, apache Next: Principal Component Analysis |