I read the rest of this thread, and thought I'd throw in my two cents.
It seems to me that you are mostly concerned with being able to
provide a stable external API to clients while allowing the internal
data structures to change.  As a library designer you need to choose
which parts of your API are going to be stable.  If you promise that
functions will accept and return maps with certain keys, then you must
keep that promise moving forward.  Let's use your example of :name.
API v1 has functions that accept/return maps of the form {:name ...}.
In API v2 you decide that it is better to actually use {:first-name
"" :last-name ""}.  If you wish to keep API v1 compatibility you need
to also provide the :name key.  So even if you wish to change internal
structures, you need to present old structures to the outside world.
At some layer you must be dealing with functions in your API, at this
level you should marshal between the old map keys & the new map keys.
For cases like this you could even merge the maps & allow both APIs at
the same time.

IMHO the situation is not very different from any other API version
problem, you just have to view the keys in a public access map as part
of your API.

Cheers,
Brad

On Apr 19, 8:00 am, Timo Mihaljov <noid....@gmail.com> wrote:
> Hi,
>
> 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.
>
> The obvious and traditional solution, at least for someone used to
> thinking in OO terms, would be to tell the clients of the library to
> treat the records as opaque handles, and only use the library's accessor
> functions to access their contents. However, I don't like this approach
> because it leads to a lot of boilerplate code that's there "just in case
> I'll need it some day". It also prevents my clients from using generic
> map manipulation functions on the records.
>
> In Python, my current go-to language, I can have my cake and eat it too
> by using class properties.
>
>      # A struct-like class whose members can be manipulated directly
>      class Person1(object):
>          name = "full name"
>
>      p1 = Person1()
>      print p1.name
>
>      # Like above, but with three members, one of which is calculated by
>      # a function when it is accessed
>      class Person2(object):
>          first_name = "first"
>          last_name = "last"
>
>          def get_name(self):
>              return self.first_name + " " + self.last_name
>          name = property(get_name)
>
>      p2 = Person2()
>      print p2.name   # The old API still works, even though the data is
>                      # stored in a different way
>
> What's the idiomatic Clojure way of dealing with this issue?
>
> --
> Timo
--~--~---------~--~----~------------~-------~--~----~
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