unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* Always return a list
@ 2010-11-25 10:05 Johan Andersson
  0 siblings, 0 replies; 2+ messages in thread
From: Johan Andersson @ 2010-11-25 10:05 UTC (permalink / raw)
  To: help-gnu-emacs

[-- Attachment #1: Type: text/plain, Size: 911 bytes --]

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?

Thanks!

[-- Attachment #2: Type: text/html, Size: 1453 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Always return a list
       [not found] <mailman.0.1290679543.16375.help-gnu-emacs@gnu.org>
@ 2010-11-25 23:03 ` Tim X
  0 siblings, 0 replies; 2+ messages in thread
From: Tim X @ 2010-11-25 23:03 UTC (permalink / raw)
  To: help-gnu-emacs

Johan Andersson <johan.rejeep@gmail.com> 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


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2010-11-25 23:03 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-11-25 10:05 Always return a list Johan Andersson
     [not found] <mailman.0.1290679543.16375.help-gnu-emacs@gnu.org>
2010-11-25 23:03 ` Tim X

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).