Another approach would be to use records and protocols:

(defprotocol HasCees
  (c [this] "Returns a 'c'"))

(defrecord Foo [a b]
  HasCees
  (c [this]
    (+ (:a this) (:b this))))

Now, to use it:

user> (def my-foo (Foo. 1 2)
#'user/my-foo
user> (c my-foo)
3

This is practically a drop-in replacement for the struct-based code
(since Clojure records behave like maps).  I think with the advent of
records, there isn't really any reason to use structs anymore.  Also,
this is arguably more fitting with the semantics you have, as the "c"
is more of a behavior than a value.

It's also common to have a factory function to create record instances
(just as Michel showed with structs), like this:

(defn make-a-foo [a b]
  (Foo. a b))

This helps to make dealing with the positional constructors of records
a bit less awkward.

Here's some links:
http://clojure.org/datatypes
http://clojure.org/protocols

Hope that helps,
Chris

On Sat, Nov 13, 2010 at 11:48 AM, Michel Alexandre Salim
<michel+...@michelsylvain.info> wrote:
> On Sat, 13 Nov 2010 06:31:03 -0800, garf wrote:
>
>> If I have a struct whose creation will require some function calls that
>> references some of its members, I am unsure how to go about it in a
>> clean way.  For example:
>> (defstruct tz :a :b :c)
>>
>> (def tz1   1  2  (+ (:a tz1) (:b tz1))
>>
> Could you give a more realistic example of how you plan to use this?
>
> If the only restriction is that you only know the values for :a and :b at
> the time you want to create the structure, then this would work:
>
> (defn create-tz [a-val b-val]
>  (struct-map tz :a a-val :b b-val :c (some-fn a-val b-val)))
>
>
>> will not work, but reflects the problem.   Ideally at the end of this I
>> could do (:c tz1) and get 3 back.  Any suggestions?   Originally I had
>> used assocs, but that runs into the immutability problem, for example
>>
>> (defstruct tz :a :b)
>> (def tz1  1 2)
>> (assoc tz1 :c  (+ (:a tz1) (:b tz1))
>>
>> does not actually update tz1
>>
> Correct. Values are immutable, and in Clojure, even collections are
> values!
>
> If you want to have a variable hold a reference to some changing values
> then what you want is to use an atom or a ref. Atom is more easy to use,
> and unless you have several mutable values that need concurrent updating,
> is sufficient, so here's an example:
>
>> (def tz1 (atom (struct-map tz :a 1 :b 2)))
> #'user/tz1
>> @tz1
> {:a 1, :b 2, :c nil}
>> (swap! tz1 #(assoc % :c (+ (:a %) (:b %))))
> {:a 1, :b 2, :c 3}
>> @tz1
> {:a 1, :b 2, :c 3}
>
> Hope that helps,
>
> --
> Michel Alexandre Salim
> Clojure contributor: http://clojure.org/contributing
> GPG key ID: 78884778
>
> µblog: http://identi.ca/hircus   | Jabber: hir...@jabber.ccc.de
>       http://twitter.com/hircus | IRC:    hir...@irc.freenode.net
>
> ()  ascii ribbon campaign - against html e-mail
> /\  www.asciiribbon.org   - against proprietary attachments
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with your 
> first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to