On Mar 23, 2009, at 18:20, Mark Engelberg wrote:

> standard maps.  I guess, loosely speaking, I was envisioning a model
> in which seq on a hash map would only traverse the "public keys", so
> that library functions will work on your objects, without exposing
> innards.  But perhaps there is no consistent, sane way to do this,
> since it's hard to predict what things might actually need that
> private information (like equality, for example).

One way to do this is to implement some well-defined public interface  
for your type. Your implementation of the interface would then ensure  
that only selected fields of your data structure are exposed in this  
way.

Take a look at these interfaces, for example:

        http://code.google.com/p/clojure-contrib/source/browse/trunk/src/ 
clojure/contrib/generic/collection.clj

They are "high-level" versions of some common Clojure functions for  
manipulating collections. By "high-level" I mean that they are  
implemented as multimethods for which you can provide specific  
implementations based on a type tag in metadata. This makes them more  
versatile, but also slower, so I don't expect something like this to  
replace the basic Clojure functions.

If you want to expose a map-like interface to your data structures in  
which only certain keys are exposed, you could implement the  
interfaces assoc, dissoc, and get from  
clojure.contrib.generic.collection and make them part of the public  
API of your objects. That still won't stop mischievous or buggy  
client code from using Clojure's built-in low-level versions of these  
operations and destroy the integrity of your data, of course.

I have been using these interfaces in my code for a while now and  
overall I like that approach. The biggest problem is that these high- 
level interface functions have the same names as the corresponding  
Clojure functions, which can lead to confusion. On the other hand,  
there are so many of these functions that choosing different names  
would be a pain as well. For the moment, I have adopted the  
convention of accessing the high-level versions through a namespace  
alias, e.g.

        (ns ... (:require [clojure.contrib.generic.collection :as gc]))

        (gc/seq my-data)

I find this clear enough when reading the code, but it does happen  
that I forgot to type the gc/ when writing. I am open for better  
ideas for handling this!

Konrad.


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