Thanks Ryan, Mike and James for your comments and info. Ryan I will follow up the links you posted.
In the meantime, a request for some clarification... I have read / watched clojure stuff along these lines... ie that data hiding (in an immutable data context) is bad. I thought my approach was taking this into account. Ie, I am actually using a hash-map for my fruit instance data (rather than say closures for true data hiding) and this is not hidden - it is freely accessible to users of my fruit library. Users can choose to use getter functions or use more direct map access techniques. The getter functions sort of provide self documentation about interface intent, without restricting/forcing users to be limited to this if the interface has weaknesses. I guess I was trying to "take the best from both approaches". But maybe you are telling me that even this watered-down-encapsulation is not good? Ryan you are suggesting that maybe defrecord is the way to go. I haven't read about that yet, so I will look into that. But just suppose I wanted to stick with using raw hash-maps for my data. Would you suggest that instead of my current approach, I should... - Not implement any getter function when a keyword accessor will do. Eg don't implement (defn color [fru] (:color fru)), just let library users do (:color fru) themselves. - Do still implement other getters, eg (defn red? [fru] (= :red fru)) and eg (defn packingvol [{:keys [size]}] (* size size size)). - What about "make"? Do I still implement a fruit constructor function, or do I leave it to users to use usual hash-map constructors? (And if I should not implement a fruit constructor, how do I indicate to users the shape that a fruit hash-map should take? Do I just document this in comments?) - Was I right to construct a new namespace for my fruit-related data and functions? Thanks, Mark. On Thursday, 26 June 2014 11:42:01 UTC+9:30, Ryan Schmitt wrote: > > In object-oriented programming, encapsulation is always and everywhere > regarded as a highly significant design virtue, but the Clojure people have > a bit of a different assessment, particularly when it comes to information. > In one talk, Rich Hickey pointed out that encapsulation is for hiding > implementation details, but information doesn't *have* an implementation; > there are no innards to encapsulate *unless you add them*. Stuart > Halloway gave one talk where he made a brilliant point about how > abstraction is valuable for *commands*, because then it limits what you > have to know, but it's not valuable for *queries*, because then the > abstraction (i.e. the custom accessors that "encapsulate" your data) only > limits what you can perceive. > > And of course, there's Alan Perlis's old saw that "it is better to have a > hundred functions operate on one data structure than to have ten functions > operate on ten data structures"--that is to say, by using generic data > structures (e.g. maps) to directly represent information in your domain, > you can reuse all of the generic functions that operate on those data > structures, whereas encapsulated data screws your clients because it > renders all of their generic collections libraries useless. (This is one of > the ways in which OOP has failed to deliver on its promise of pervasive > code reuse.) > > Some of Rich Hickey's talks that touch on the subject: > > http://www.infoq.com/presentations/Value-Values > http://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey > > As for your particular example, I recommend looking at defrecord, which > generates a data structure that behaves like a map (it can be perceived and > manipulated generically), as well as various constructors and readers and > so forth for that type. defrecord also lets you specify protocols for your > data type. See: > > http://clojure.org/datatypes > > Also be sure to check out Prismatic's survey of Clojure's choices for > doing "object"-like things: > > > https://github.com/Prismatic/eng-practices/blob/master/clojure/20130926-data-representation.md#data-types > > On Wednesday, June 25, 2014 6:34:50 PM UTC-7, Mark P wrote: >> >> I've only recently started real clojure development, so very much still >> learning what styles work and what don't. I have a question about naming >> attribute getters... >> >> Suppose I want to model "fruit" entities. I will use a hash-map to >> represent the data for each such entity, and will defn a "make" function to >> construct fruit instances. I will put "make" and any other fruit-related >> functions within a new namespace "myprog.fruit". >> >> Because my data representation is a map, strictly speaking I don't need >> any attribute getter functions. Because I could simply use the attribute >> keywords in the map as my getter functions, eg (:color fru). But I will >> create actual getter functions within my namespace anyway, for a few >> reasons. >> >> 1. It will signal to any users of my fruit library, which attributes >> are "official" and are expected to be used / supported, versus attributes >> which are more of an implementation detail. >> 2. Some attributes will simply be (defn color [fru] (:color fru)), >> whereas others are less direct, eg (defn red? [fru] (= :red fru)) or >> another eg (defn packingvol [{:keys [size]}] (* size size size)). >> 3. Down the track I can change my data representation, and just >> reimplement the getter functions. Users of my fruit library who have >> stuck >> to my getter functions interface will not need to change a thing. >> >> This approach seems okay to me so far, though I am open to critiques and >> alternative suggestions. But one issue has come to mind... leading to the >> question of this post... >> >> At the end of 2. above, I have defined a local let symbol "size" as part >> of the map destructuring. But it so happens I have already defined a size >> getter, namely (defn size [fru] (:size fru)). So within the definition of >> packingvol my size getter is masked by the local symbol "size". Now I'm >> not sure this masking causes much harm... I don't actually need to use the >> size getter here, and if I really needed it I could always use >> "myprog.fruit/size"... But something still makes me feel uncomfortable >> about it, maybe because this masking could end up happening a lot within my >> fruit.clj source code file. >> >> Now I could just switch to a new naming convention for my getters, ie >> "color-get", "red?-get", "size-get", "packingvol-get" etc. But I'm not >> sure I like the extra verbosity. And for users of my fruit library - who >> will be working in a different namespace - this problem mostly goes away as >> they will probably be namespace-qualifying access to my getters. >> >> Is using self-named attribute getters a good idea? >> >> Thanks, >> >> Mark. >> >> -- 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 unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.