From: dpapathanasiou
Subject: Dynamic access to struct slots?
Date: 
Message-ID: <1178801529.534278.169180@u30g2000hsc.googlegroups.com>
I've defined three structs, using the :named key, which have a slot in
common called "tags".

I'd like to write a single function/macro which can use the (type-of)
result to get to the slot's data, but I'm not sure how (or if) it can
be done.

In my first attempt, I used a simple (cond), like this:

(defun get-struct-tags (obj)
  (cond ((a-p obj) (a-tags obj))
           ((b-p  obj) (b-tags  obj))
           ((c-p  obj) (c-tags  obj))))

It works, but puts me on the slippery slope of spaghetti code.

Then I tried closures, like this:

(defun get-struct-tags (obj)
  (funcall (get (type-of obj) 'struct-tags) obj))

(setf (get 'a 'struct-tags) #'(lambda (obj) (a-tags obj))) ; repeated
for b and c structs

Which was somewhat better, but what I'd really be able to do is write
something like this:

(defmacro get-struct-tags (obj)
  `((type-of ,obj)-tags ,obj))

Except, of course, (type-of ,obj)-tags doesn't expand the way I need
it to, for this idea to work.

Is there a way to do it like that?

From: ···············@yahoo.com
Subject: Re: Dynamic access to struct slots?
Date: 
Message-ID: <1178806988.092588.250850@o5g2000hsb.googlegroups.com>
Structs can inherit from other structs using the :include option.
Maybe you could define a common struct abc with the tags slot, and
arrange for a, b, and c to include abc.  You would access the tags
with abc-tags.
From: dpapathanasiou
Subject: Re: Dynamic access to struct slots?
Date: 
Message-ID: <1178810066.371807.207360@h2g2000hsg.googlegroups.com>
Pascal & Mark:

Good points about using inheritance to solve this problem, either
with :include, :method, or CLOS (if I were to abandon the structs for
this problem).

But I'm more interested about the possibility of getting a macro like
the one I described, to work:

(defmacro get-struct-tags (obj)
  `((type-of ,obj)-tags ,obj))

In other words, is there anyway to get a macro to expand "(type-
of ,obj)-tags" into "a-tags" (assuming the value of ,obj was an a
struct), which would then be invoked properly inside of "`(a-
tags ,obj)" ?

I can think of other places, besides struct access, where this would
be useful.
From: Pascal Bourguignon
Subject: Re: Dynamic access to struct slots?
Date: 
Message-ID: <87k5vglk0b.fsf@thalassa.lan.informatimago.com>
dpapathanasiou <···················@gmail.com> writes:
> But I'm more interested about the possibility of getting a macro like
> the one I described, to work:
>
> (defmacro get-struct-tags (obj)
>   `((type-of ,obj)-tags ,obj))
>
> In other words, is there anyway to get a macro to expand "(type-
> of ,obj)-tags" into "a-tags" (assuming the value of ,obj was an a
> struct), which would then be invoked properly inside of "`(a-
> tags ,obj)" ?

Have a look at INTERN

(defmacro get-struct-tags (obj)
  `(,(intern (format nil "~A-TAGS" (type-of obj))) ,obj))

Be prepared to have names like |(INTEGER 0 100)-TAGS|...
(read again CLHS TYPE-OF).

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"A TRUE Klingon warrior does not comment his code!"
From: Alex Mizrahi
Subject: Re: Dynamic access to struct slots?
Date: 
Message-ID: <46434a86$0$90276$14726298@news.sunsite.dk>
(message (Hello 'dpapathanasiou)
(you :wrote  :on '(10 May 2007 08:14:26 -0700))
(

  d> (defmacro get-struct-tags (obj)
 d>   `((type-of ,obj)-tags ,obj))

 d> In other words, is there anyway to get a macro to expand "(type-
 d> of ,obj)-tags" into "a-tags" (assuming the value of ,obj was an a
 d> struct), which would then be invoked properly inside of "`(a-
 d> tags ,obj)" ?

note that type of obj is typically known only at runtime. if it's variable, 
it will be seen as SYMBOL to macro.
you can do dispatch at runtime, but you don't need a macro for this

(defun get-struct-tags (obj)
    (apply (intern (format nil "~A-TAGS" (type-of obj))) obj))

but it's really ugly, it's much better to use dispatch in other way.

)
(With-best-regards '(Alex Mizrahi) :aka 'killer_storm)
"I am everything you want and I am everything you need") 
From: Pascal Costanza
Subject: Re: Dynamic access to struct slots?
Date: 
Message-ID: <5agjirF2p4g6jU1@mid.individual.net>
dpapathanasiou wrote:
> I've defined three structs, using the :named key, which have a slot in
> common called "tags".
> 
> I'd like to write a single function/macro which can use the (type-of)
> result to get to the slot's data, but I'm not sure how (or if) it can
> be done.
> 
> In my first attempt, I used a simple (cond), like this:
> 
> (defun get-struct-tags (obj)
>   (cond ((a-p obj) (a-tags obj))
>            ((b-p  obj) (b-tags  obj))
>            ((c-p  obj) (c-tags  obj))))
> 
> It works, but puts me on the slippery slope of spaghetti code.

The easiest path is to switch to CLOS classes.

If you want to stick with structs, why not translate the above code to a 
generic function?

(defgeneric get-struct-tags (obj)
   (:method ((obj a)) (a-tags obj))
   (:method ((obj b)) (b-tags obj))
   (:method ((obj c)) (c-tags obj)))

This generic function is now extensible (and contrary to popular belief 
in some circles not inefficient at all ;).

Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Wade Humeniuk
Subject: Re: Dynamic access to struct slots?
Date: 
Message-ID: <m2k5vgte96.fsf@telus.net.no.spam>
dpapathanasiou <···················@gmail.com> writes:

> I've defined three structs, using the :named key, which have a slot in
> common called "tags".
>
> I'd like to write a single function/macro which can use the (type-of)
> result to get to the slot's data, but I'm not sure how (or if) it can
> be done.
>
> In my first attempt, I used a simple (cond), like this:
>
> (defun get-struct-tags (obj)
>   (cond ((a-p obj) (a-tags obj))
>            ((b-p  obj) (b-tags  obj))
>            ((c-p  obj) (c-tags  obj))))
>
> It works, but puts me on the slippery slope of spaghetti code.
>

Think outside the "box".

Just give up trying to do it in standard CL. Most of the CLs have
structs integrated into CLOS so slot-value works on them.

LispWorks ---

CL-USER 1 > (defstruct test tags other)
TEST

CL-USER 2 > (defvar *test* (make-test :tags '(10 :a "hello") :other 'other))
*TEST*

CL-USER 3 > (slot-value *test* 'tags)
(10 :A "hello")

CL-USER 4 > (type-of *test*)
TEST

CL-USER 5 > (class-of *test*)
#<STRUCTURE-CLASS TEST 2161EEDF>

CL-USER 6 > 

OpenMCL ----

CL-USER> (defstruct test tags other)
TEST
CL-USER> (defvar *test* (make-test :tags '(10 :a "hello") :other 'other))
*TEST*
CL-USER> (slot-value *test* 'tags)
(10 :A "hello")
CL-USER> 

SBCL ----

* (defstruct test tags other)
TEST
* (defvar *test* (make-test :tags '(10 :a "hello") :other 'other))
*TEST*
* (slot-value *test* 'tags)
(10 :A "hello")
* 
Wade