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