From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Tim X Newsgroups: gmane.emacs.help Subject: Re: Always return a list Date: Fri, 26 Nov 2010 10:03:10 +1100 Organization: Unlimited download news at news.astraweb.com Message-ID: <87tyj5f1ld.fsf@puma.rapttech.com.au> References: NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Trace: dough.gmane.org 1291898059 31966 80.91.229.12 (9 Dec 2010 12:34:19 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Thu, 9 Dec 2010 12:34:19 +0000 (UTC) To: help-gnu-emacs@gnu.org Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Thu Dec 09 13:34:15 2010 Return-path: Envelope-to: geh-help-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1PQfhN-0003qL-PX for geh-help-gnu-emacs@m.gmane.org; Thu, 09 Dec 2010 13:34:14 +0100 Original-Received: from localhost ([127.0.0.1]:44013 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PQfhK-00021t-W1 for geh-help-gnu-emacs@m.gmane.org; Thu, 09 Dec 2010 07:34:11 -0500 Original-Path: usenet.stanford.edu!news.glorb.com!news2.glorb.com!news.glorb.com!news.astraweb.com!border1.newsrouter.astraweb.com!not-for-mail Original-Newsgroups: gnu.emacs.help User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.0.50 (gnu/linux) Cancel-Lock: sha1:RZTHzi6K4p9X7hVHF8LdyDkcxUo= Original-Lines: 89 Original-NNTP-Posting-Host: 1ee47da8.news.astraweb.com Original-X-Trace: DXC=lK?2SkjQXQKMnc]O[a9m]EL?0kYOcDh@JN7:H2`MmAUC]OJTWN^F8NF]G; 2>V^?kWCCAkl5c@XgkNDVh6<=G4nKN=O3[6HD@Y2O Original-Xref: usenet.stanford.edu gnu.emacs.help:182637 X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.help:77033 Archived-At: Johan Andersson writes: > Hey, > > I have a struct. To make it simple, lets assume this is the struct: >   (defstruct package name deps) > > The deps slot is for the package dependencies. Example of packages: >   (make-package :name "one" :deps "two") >   (make-package :name "two" :deps '("three" "four")) > > To make it easier to use the dependencies from the code, when I > call (package-deps package) I always want it to return a list. So: > >   (let ((one (make-package :name "one" :deps "two")) >         (two (make-package :name "two" :deps '("three" "four")))) > >     (print (package-deps one)) ;; => ("two") >     (print (package-deps two)) ;; => ("three" "four") >     ) > > I tried doing this using an advice, with no success: >   (defadvice package-deps (around package-deps-around) >     (let ((deps ad-do-it)) >       (if (listp deps) deps (list deps)))) >   (ad-activate 'package-deps) > > Can I do this in a way that doesn't require that much of a hack? > If your structure is not much more complicated that your example, I would not even bother with defstruct. The defstruct facility is not a core elisp data type, but rather a partial implementation of the CL defstruct type. This implementation is based on either a list or vector type. Unless your also using many other cl functions, you will probably get more precisely what you want by defining your own functions to create and manipulate either a list or vector representing your data and avoid the need to require the whole cl package. Writing the functions to create, set, get, test and print a simple structured list or vector like your example is quite trivial and you would have more control over things. If what you need is actaully more complex, I would suggest looking into the eieo package. There are a couple of things you could do if you want to stick with defstruct 1. Create a custom constructor for your struct that sets the deps slot to always be a list. You will need to set the default constructor to nil to stop a default from being created. Your custom constructor(s) will need to handle the cases where it is called with a deps argument that is nil, a single atomic element and a list - converting all to a list. Ensure all calls to set a slot pass it a list, i.e.   (let ((one (make-package :name :deps (list "two")))         (two (make-package :name "two" :deps (list "three" "four")))) With these two restrictions, you can make the assumption the deps slot is always a list and dispenc with the tests. 2. Just define your own print-deps funtion. Instead of     (print (package-deps one)) ;; => ("two") (print-deps one) ;; => ("two") 3. Redefine package-deps to include the test/conversion of the slot to always be a list. This approach has the advantage that querying the deps slot will provide consistent results regardless of where it is used. 4. If you feel adventurous, this could be a good macro learning exercise. Create a mydefstruct macro, which would define the base list structure, the constructor, setters, getters and tests etc. Possibly not a bad example for exploring the possibilities that macros provide. 5. Simplest of all - just ensure you always create new struct instances with a list argument for the deps slot and ensure in any setf operations, you set it to either a list or nil. The core of the problem you have is that currently, your deps slot may be a single atom or it may be a list. If you ensure it is always a list, results will be consistent. Of course, this does leave a good place for bugs to lurk as it requires the programmer to know/remember this. Tim -- tcross (at) rapttech dot com dot au