Hi,

2009/4/20 Timo Mihaljov <noid....@gmail.com>

>
> Timo Mihaljov wrote:
> > I'm wondering about how to change a data structure without breaking the
> > API used to access it. For example, let's assume that I have a library
> > for dealing with records of people and I'm storing them in structs.
> >
> >     (defstruct person :name)
> >
> > The users of my library access the data stored in the records like any
> > other map.
> >
> >     (:name some-person)
> >
> > When the library's been in use for a while, I realize that I need to
> > make a change to the data structure.
> >
> >     (defstruct :first-name :last-name)
> >
> > The problem is that making this change would break all the clients using
> > the library.
>
> After a bit of googling I found what seems to be the perfect solution:
> http://kotka.de/projects/clojure/lazy-map.html
>
> (defn new-person [first-name last-name]
>   (lazy-struct-map person
>                    :first-name first-name :last-name last-name
>                    :name (str first-name " " last-name)))
>

While interesting, this approach seems to me limited to simple cases :
 * limited in possibilities: you are not able to directly use values of
other fields. So in more complex cases, you won't be able to combine
calculated values without code repetition or prepraration via lets ..
 * limited in extensibility: in a live system, you won't be able to change
the function that displays a name because it's "hard-coded" once and for all
at the same time the data is entered in the system. Depending on your use
cases, it may or may not be a problem, though.
 * limited for persistence: when you want to persist a lazy-struct-map, the
computed value is fixed and stored, where it should not be used I think.
 * limited for equality tests (in relation with "limited in extensibility"):
you will not be able to succesfully compare for equality 2 persons with the
exact same essential data, if the way to represent names has been even
slightly enhanced, since the :name value will always be used for the
comparison as well. So it's not just a problem for performance (very minor
in that case, though it may not be that minor in other cases), but also a
problem of correctness, in the long run (for systems you want to keep
"live", and without having to do weird things when you have to marshall /
unmarshall your data).


I would like to offer another possibility. Not ideal, maybe, but that may
answer your needs.
Basically, the idea is that with a language like clojure that has higher
order functions and macros, writing "boiler plate" code should be a code
smell. The good news being that in Java, this "boiler plate" code smell has
no solution in some cases (think about design patterns), while with a lisp,
you can do something for that.

By using a macro, you could generate "boiler plate" getters for your
structure. And just "override" with new definitions those getter/setters
that need computations.

Of course, this does not solve the problem of evaluating a derived value
only once, but it does not appear to me that it was the original question of
your post :-)

--~--~---------~--~----~------------~-------~--~----~
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
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