Hey Luc,

That's a cool casting strategy to cleanly build a standard way to get at 
the person piece of any type of applicable record.  In the pure composition 
case, it's actually a nice solution to build functions know how to unpack 
the Person aspect of a subtype.

However, I think which strategy is best depends very much on whether you 
plan to extensively change the protocol implementation between the the 
different  related types.  In the case where Employee simply carries extra 
information with regard to a person, I agree that it is nice simply to 
define a mechanism to extract the base type and just act on it directly.  
However if you wish to do something more complicated or override default 
behavior extensively, I think the encapsulated "newtyped" way is more 
convenient.

For example, how about we build a little DSL to represent different types 
of Excel cells.  In Excel, everything is represented as a float, so we have 
to keep track of the type separately.  I think using a record type is a 
fairly natural way to encode this extra data on type of Cell, where I might 
have reached for inheritance in traditional OOP.

(defprotocol Convertable
  (convert-cell [this]))

(defrecord Cell [row col float-value])

(defrecord MoneyCell [cell])

(defrecord DateCell [cell])

(defrecord NumberCell [cell])

(extend-protocol Convertable
    NumberCell
    (convert-cell [this] (float (-> this :cell :float-value))
    DateCell
    (convert-cell [this] (excel-date (-> this :cell :float-value)) ;; 
Translate an Excel datestamp to java.util.Date
    MoneyCell
    (convert-cell [this] (bigdec (convert-cell (Number (:cell this))))) 
;;BigDecimals are for exact money handling.

Blindly unpacking the Cell type (via a Cellable convention like in the 
Person example) would lose information we need to accurately describe the 
conversion process and call the best function.  This strategy also 
leverages ones of the best aspects of protocols: how extensible they are to 
new types of data.  If I ever decide to support a StringCell type or a 
BooleanCell, I would just be one extend-protocol away rather than having to 
rewrite some gnarly embedded cond to work with my new type of cell.  Of 
course for operations that don't care about their type, creating a protocol 
to extract the cell and working directly with its attributes (such as 
manipulating row and position directly), makes a great deal of sense.

Best,
Mark

On Monday, May 21, 2012 10:09:02 PM UTC-7, Luc wrote:
>
> Interesting demonstration, except for one thing, defining getters is a 
> waste of 
> time :) 
>
> When you need to define accessors, you start to run into inefficient use 
> of 
> your time. It still a bearable workload in Java because of all this heavy 
> tooling that allows 
> to select for which fields accessors will be generated. 
> Without getters, you would also expose mutable stuff to the universe. 
>
> However in Clojure the values are not mutable... Why bother defining 
> an accessor to a read-only value ? 
>
> A better way would be something like: 
>
> (defprotocol Personable 
>     (person [this]) 
>      (age [this] ) 
>
> (defprotocol CensusOperators 
>     (age [this])) 
>
> (extend-protocol Personable 
>     Person 
>     (person [this] this) 
>     Employee 
>     (person [this] (:person this))) 
>
> (extend-protocol CensusOperators 
>      Person 
>      (age [this] (date-dif (java.util.Date.) (:birthday this))))) 
>
> Much more convenient to me. I can take anything and make it a person. 
> Even from a Clojure map just by extending it and returning a Person 
> instance. 
> You expose the Person abstraction when available instead of hiding it. 
>
> Computed values like the age ? This is something that could be computed 
> for other entities like an animal. 
>
> So you can write (age (person xxxx)) or (age (animal xxxx)). 
>
> This is why I tell people to get out of their usual thinking process. Get 
> lazy, 
> playing hide and seek was fun at pre-school age but in your code and data 
> structures ? 
>
> Luc P. 
>
>
> > I think it's misleading to use inheritance to reduce code duplication.   
> > Inheritance is about indicating function typing and creating typed 
> > contracts, both of which are fairly un-idiomatic in Clojure. 
> > 
> > However, there is another way to prevent code duplication: use 
> composition 
> > instead.  Instead of having the Employee class mirror the attributes of 
> the 
> > Person (which if you really wanted, you could easily do via a 
> "defperson" 
> > like macro that would slug on extra fields), why not have an Employee 
> carry 
> > a Person as one of its attributes?  This approach is more similar to the 
> > Haskell/functional way of working with record types (I think Haskell's 
> > newtype operator works similarly under the covers).  There is also an 
> > analogue to the decorator pattern in Java. 
> > 
> > In this case, you would specify a Personable protocol, which both Person 
> > and Employee implement; for all the basic operations, Employee would 
> just 
> > defer to its internal person.  Example: 
> > 
> > (defrecord Person [name birthday]) 
> > 
> > (defrecord Employee [title person]) 
> > 
> > (defprotocol Personable 
> >   (name [this]) 
> >   (age [this)) 
> > 
> > (extend-protocol Personable 
> >   Person 
> >   (name [this] (:name this)) 
> >   (age [this] (date-dif (java.util.Date.) (:birthday this)) ;;date diff 
> > defined elsewhere 
> >   Employee 
> >   (name [this] (name (:person this)) 
> >   (age [this] (age (:person this))) 
> > 
> > Arguably, if we were deferring to the current Java best practices and 
> > encapsulation, one should be creating interfaces of getters and setters 
> > rather than directly accessing instance variables anyway, making the 
> extra 
> > protocol definition no more work than doing it correctly in modern Java. 
> > 
> > Best, 
> > Mark 
> > 
> > On Sunday, May 20, 2012 10:22:55 AM UTC-7, Warren Lynn wrote: 
> > > 
> > > So from what I read  the philosophy of Clojure discourages inheritance 
> > > on concrete data types. However, maybe I am too entrenched in my OO 
> > > thinking, how do I define a new record type that includes all the data 
> > > members of another record type? I am thinking about the classic 
> > > Employee/Person example. 
> > > 
> > > If I can define a record of Employee with Person's data members 
> > > included, even that is not true inheritance (as no protocols of 
> > > "Person" will be automatically extended to "Employee"), I need that 
> > > for function re-use (so a function working on Person will 
> > > automatically work on Employee because Employee is guaranteed to have 
> > > all the data members in Person). 
> > > 
> > > Also, again, maybe I am too OO minded, is there a way inherit another 
> > > record type's protocol implementation? That seems to give the best 
> > > combination of both worlds (OO and functional), so you can either have 
> > > you own very customized combination of data type/protocols, or use the 
> > > very common OO pattern. Just like we have both the single-typed 
> > > dispatching (which is more OO like and covers a large portion of use 
> > > cases), and more advanced multimethods. 
> > > 
> > > Thanks. 
> > 
> > -- 
> > 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 
> -- 
> Softaddicts<lprefonta...@softaddicts.ca> sent by ibisMail from my ipad! 
>

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

Reply via email to