Discussion:
Defstruct with array
(too old to reply)
r***@gmail.com
2020-02-07 18:35:28 UTC
Permalink
Is there a concise way to make a struct with an array of structs?

I have found the following works although it is very verbose.

(defstruct lottery-ticket
(purchased ‘T)
(number ‘16384))

(defstruct tickets-array
(number-of-tickets 1000000)
(tickets))

(setf my-tickets (make-tickets-array))

(setf (tickets-array-tickets my-tickets) (make-array ‘10 :initial-element (make-lottery-ticket)))

Now I can confirm tickets-array-tickets is an array

(arrayp (tickets-array-tickets my-tickets))
T

I would have preferred to set up the array inside of the defstruct for tickets-array. Is that possible?

Thank you.
Raymond Wiker
2020-02-07 19:19:20 UTC
Permalink
Post by r***@gmail.com
Is there a concise way to make a struct with an array of structs?
I have found the following works although it is very verbose.
(defstruct lottery-ticket
(purchased ‘T)
(number ‘16384))
(defstruct tickets-array
(number-of-tickets 1000000)
(tickets))
(setf my-tickets (make-tickets-array))
(setf (tickets-array-tickets my-tickets) (make-array ‘10
:initial-element (make-lottery-ticket)))
Now I can confirm tickets-array-tickets is an array
(arrayp (tickets-array-tickets my-tickets))
T
I would have preferred to set up the array inside of the defstruct for
tickets-array. Is that possible?
Thank you.
Have you tried the obvious?

(defstruct tickets-array
(number-of-tickets 1000000)
(tickets (make-array (list 10) :initial-element (make-lottery-ticket))))

Note: the array should probably be adjustable, and have a fill
pointer. It's also a good idea to use defclass instead of defstruct -
chiefly because you are not allowed to redefine structs.
t***@google.com
2020-02-07 19:27:50 UTC
Permalink
Post by Raymond Wiker
Post by r***@gmail.com
Is there a concise way to make a struct with an array of structs?
I have found the following works although it is very verbose.
(defstruct lottery-ticket
(purchased ‘T)
(number ‘16384))
(defstruct tickets-array
(number-of-tickets 1000000)
(tickets))
(setf my-tickets (make-tickets-array))
(setf (tickets-array-tickets my-tickets) (make-array ‘10
:initial-element (make-lottery-ticket)))
Now I can confirm tickets-array-tickets is an array
(arrayp (tickets-array-tickets my-tickets))
T
I would have preferred to set up the array inside of the defstruct for
tickets-array. Is that possible?
Thank you.
Have you tried the obvious?
(defstruct tickets-array
(number-of-tickets 1000000)
(tickets (make-array (list 10) :initial-element (make-lottery-ticket))))
Note: the array should probably be adjustable, and have a fill
pointer. It's also a good idea to use defclass instead of defstruct -
chiefly because you are not allowed to redefine structs.
This will work to create a default array.

But if you want to make the initialization more complicated, such as by having
the size of the tickets array be determined by the number-of-tickets slot, then
you would need to use DEFCLASS instead of DEFSTRUCT.

DEFCLASS will let you write your own initialization function that can do
whatever computations you wish while it is building an instance.
Stefan Monnier
2020-02-11 16:39:18 UTC
Permalink
Post by t***@google.com
But if you want to make the initialization more complicated, such as
by having the size of the tickets array be determined by the
number-of-tickets slot, then you would need to use DEFCLASS instead
of DEFSTRUCT.
I don't see why:

(defstruct (tickets-array
(:constructor nil)
(:constructor make-tickets-array
(number-of-tickets
&aux
(tickets (make-array number-of-tickets
:initial-element
(make-lottery-ticket))))))
(number-of-tickets 1000000)
(tickets))
Post by t***@google.com
DEFCLASS will let you write your own initialization function that can do
whatever computations you wish while it is building an instance.
`defstruct` also lets you do whatever computation you wish in the constructor.
Post by t***@google.com
The obvious doesn't do what the OP probably wants.
You get an array of references to the same ticket.
The OP's code suffers from the same issue. Fixing it is "orthogonal"
to the question of how to make this computation be part of
the constructor.


Stefan
t***@google.com
2020-02-11 19:48:11 UTC
Permalink
Post by t***@google.com
But if you want to make the initialization more complicated, such as
by having the size of the tickets array be determined by the
number-of-tickets slot, then you would need to use DEFCLASS instead
of DEFSTRUCT.
I don't see why:

    (defstruct (tickets-array
                (:constructor nil)
                (:constructor make-tickets-array
                  (number-of-tickets
                   &aux
                   (tickets (make-array number-of-tickets
                                        :initial-element
                                        (make-lottery-ticket))))))
      (number-of-tickets 1000000)
      (tickets))

Unfortunately, you can't combine (:constructor nil) with any other constructor forms.CCL and SBCL both complain about this.
The Hyperspec (http://www.lispworks.com/documentation/HyperSpec/Body/m_defstr.htm) is a bit ambiguous about this case, saying"(:constructor nil) is meaningful only when there are no other :constructor   options specified. It prevents defstruct from generating any constructors at all."
Post by t***@google.com
The obvious doesn't do what the OP probably wants.
You get an array of references to the same ticket.
The OP's code suffers from the same issue.  Fixing it is "orthogonal"
to the question of how to make this computation be part of
the constructor.

Yes. It needs :initial-contents instead of :initial-elementFor example :initial-contents (loop repeat 1000 collect (make-lottery-ticket))
Stefan Monnier
2020-02-12 20:56:43 UTC
Permalink
Post by t***@google.com
    (defstruct (tickets-array
                (:constructor nil)
                (:constructor make-tickets-array
                  (number-of-tickets
                   &aux
                   (tickets (make-array number-of-tickets
                                        :initial-element
                                        (make-lottery-ticket))))))
      (number-of-tickets 1000000)
      (tickets))
Unfortunately, you can't combine (:constructor nil) with any other
constructor forms.CCL and SBCL both complain about this.
Then just skip the (:constructor nil), i.e. keep the default constructor
in addition to the one that I define explicitly.


Stefan

Lieven Marchand
2020-02-07 20:48:24 UTC
Permalink
Post by Raymond Wiker
Have you tried the obvious?
(defstruct tickets-array
(number-of-tickets 1000000)
(tickets (make-array (list 10) :initial-element (make-lottery-ticket))))
The obvious doesn't do what the OP probably wants. You get an array of
references to the same ticket.

[3]> (setf *foo* (make-tickets-array))
#S(TICKETS-ARRAY :NUMBER-OF-TICKETS 1000000
:TICKETS
#(#S(LOTTERY-TICKET :PURCHASED T :NUMBER 16384) #S(LOTTERY-TICKET :PURCHASED T :NUMBER 16384)
#S(LOTTERY-TICKET :PURCHASED T :NUMBER 16384) #S(LOTTERY-TICKET :PURCHASED T :NUMBER 16384)
#S(LOTTERY-TICKET :PURCHASED T :NUMBER 16384) #S(LOTTERY-TICKET :PURCHASED T :NUMBER 16384)
#S(LOTTERY-TICKET :PURCHASED T :NUMBER 16384) #S(LOTTERY-TICKET :PURCHASED T :NUMBER 16384)
#S(LOTTERY-TICKET :PURCHASED T :NUMBER 16384) #S(LOTTERY-TICKET :PURCHASED T :NUMBER 16384)))
[4]> (setf (lottery-ticket-purchased (aref (tickets-array-tickets *foo*) 0)) nil)
NIL
[5]> *foo*
#S(TICKETS-ARRAY :NUMBER-OF-TICKETS 1000000
:TICKETS
#(#S(LOTTERY-TICKET :PURCHASED NIL :NUMBER 16384) #S(LOTTERY-TICKET :PURCHASED NIL :NUMBER 16384)
#S(LOTTERY-TICKET :PURCHASED NIL :NUMBER 16384) #S(LOTTERY-TICKET :PURCHASED NIL :NUMBER 16384)
#S(LOTTERY-TICKET :PURCHASED NIL :NUMBER 16384) #S(LOTTERY-TICKET :PURCHASED NIL :NUMBER 16384)
#S(LOTTERY-TICKET :PURCHASED NIL :NUMBER 16384) #S(LOTTERY-TICKET :PURCHASED NIL :NUMBER 16384)
#S(LOTTERY-TICKET :PURCHASED NIL :NUMBER 16384) #S(LOTTERY-TICKET :PURCHASED NIL :NUMBER 16384)))
--
Laat hulle almal sterf. Ek is tevrede om die wêreld te sien brand en die vallende
konings te spot. Ek en my aasdier sal loop op die as van die verwoeste aarde.
Barry Margolin
2020-02-10 08:13:19 UTC
Permalink
Post by r***@gmail.com
Is there a concise way to make a struct with an array of structs?
I have found the following works although it is very verbose.
(defstruct lottery-ticket
(purchased ‘T)
(number ‘16384))
(defstruct tickets-array
(number-of-tickets 1000000)
(tickets))
Why do you need to wrap the array in a structure in the first place?
This isn't C, where you need to store the array length separately from
the array.
--
Barry Margolin, ***@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
Loading...