Re: Datatypes and Protocols update

2010-05-24 Thread Pedro Teixeira


On May 22, 9:51 pm, Pedro Teixeira pedr...@gmail.com wrote:
 On Apr 27, 9:45 am, Rich Hickey richhic...@gmail.com wrote:





  On Apr 27, 2010, at 3:20 AM, Mark Engelberg wrote:

   Watching Stuart's tutorial, it looks like the automaticfactory
   functions for deftypes have gone away (I'm still working with Clojure
   1.1, so haven't had a chance to try the latest changes for myself).
   I'm going to miss that feature, especially fordefrecord, which is now
   the common case construct.

   I understand that you can always do Foo. to construct a Foo record,
   but these constructors don't act as full-fledged functions, right?

   Honestly, for me the main issue is just that subjectively, it is less
   satisfying to create a Clojure data structure and end up with
   something that you construct with Java interop syntax.  I'd like
   Clojure data structures to look and feel Clojurish not Javaish
   (yes, I know that Clojure is built with interop in mind, so
   technically, anything Javaish is also Clojurish, but I still feel a
   difference).

  I agree. I asked for suggestions for thefactoryfn in #clojure, but  
  got some pushback against introducing things in the namespace. I'm  
  still open to suggestions, here are the issues:

  The generated type name is now imported, so at the very least the  
  factoryfn can't have the same name as the class. Alternatives are  
  create-Foo etc.

  Some have asked for parameterized factories:

  (record Foo ...) or (record ::Foo ...)

  These cannot be made as fast as direct factories. Also, they may be  
  used for key/value initialization:

  (record ::Foo :field1 v1 :field2 v2 ...)

  As soon as people want bodies for the factories, in order to do  
  argument transformation/validation/defaulting, a generatedfactoryis  
  in the way.

  We left it at: If you really want afactoryyou can always write one,  
  let's see if people do.

 Thought a dynamic factory is usefull. Here it goes my first macro, so
 please let me know if I'm silly here.

 (defmacro record
   Dynamic factory for defrecords.
   ([name] `(record ~name {}) )
   ([name vals-map]
      (let [num-fields
            (alength (.getParameterTypes (first (.getDeclaredConstructors
 (class name)
            args (repeat num-fields nil)]
        `(merge (new ~name ~...@args) ~vals-map

 Usage:
 (defrecord Bar [x y])
 (record Bar)



That previous attempt was not good. For any one interested, the
following macro might do the job:

(defmacro record
  Dynamic factory for defrecords.
  ([name] `(record ~name {}) )
  ([name vals-map]
 `(let [con# (first (.getDeclaredConstructors ~name))
num# (alength (.getParameterTypes con#))]
(merge (.newInstance con# (make-array Object num#)) ~vals-map


So we can maintain a dynamic relation with defrecord:
(defrecord Bar [x y])
(record Bar)
(record Bar {:x 1))

cheers,
Pedro

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


Re: Datatypes and Protocols update

2010-05-23 Thread Pedro Teixeira

On Apr 27, 9:45 am, Rich Hickey richhic...@gmail.com wrote:
 On Apr 27, 2010, at 3:20 AM, Mark Engelberg wrote:





  Watching Stuart's tutorial, it looks like the automaticfactory
  functions for deftypes have gone away (I'm still working with Clojure
  1.1, so haven't had a chance to try the latest changes for myself).
  I'm going to miss that feature, especially fordefrecord, which is now
  the common case construct.

  I understand that you can always do Foo. to construct a Foo record,
  but these constructors don't act as full-fledged functions, right?

  Honestly, for me the main issue is just that subjectively, it is less
  satisfying to create a Clojure data structure and end up with
  something that you construct with Java interop syntax.  I'd like
  Clojure data structures to look and feel Clojurish not Javaish
  (yes, I know that Clojure is built with interop in mind, so
  technically, anything Javaish is also Clojurish, but I still feel a
  difference).

 I agree. I asked for suggestions for thefactoryfn in #clojure, but  
 got some pushback against introducing things in the namespace. I'm  
 still open to suggestions, here are the issues:

 The generated type name is now imported, so at the very least the  factoryfn 
 can't have the same name as the class. Alternatives are  
 create-Foo etc.

 Some have asked for parameterized factories:

 (record Foo ...) or (record ::Foo ...)

 These cannot be made as fast as direct factories. Also, they may be  
 used for key/value initialization:

 (record ::Foo :field1 v1 :field2 v2 ...)

 As soon as people want bodies for the factories, in order to do  
 argument transformation/validation/defaulting, a generatedfactoryis  
 in the way.

 We left it at: If you really want afactoryyou can always write one,  
 let's see if people do.



Thought a dynamic factory is usefull. Here it goes my first macro, so
please let me know if I'm silly here.

(defmacro record
  Dynamic factory for defrecords.
  ([name] `(record ~name {}) )
  ([name vals-map]
 (let [num-fields
   (alength (.getParameterTypes (first (.getDeclaredConstructors
(class name)
   args (repeat num-fields nil)]
   `(merge (new ~name ~...@args) ~vals-map


Usage:
(defrecord Bar [x y])
(record Bar)


cheers,
Pedro

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


Re: Datatypes and Protocols update

2010-04-27 Thread Mark Engelberg
Watching Stuart's tutorial, it looks like the automatic factory
functions for deftypes have gone away (I'm still working with Clojure
1.1, so haven't had a chance to try the latest changes for myself).
I'm going to miss that feature, especially for defrecord, which is now
the common case construct.

I understand that you can always do Foo. to construct a Foo record,
but these constructors don't act as full-fledged functions, right?

Honestly, for me the main issue is just that subjectively, it is less
satisfying to create a Clojure data structure and end up with
something that you construct with Java interop syntax.  I'd like
Clojure data structures to look and feel Clojurish not Javaish
(yes, I know that Clojure is built with interop in mind, so
technically, anything Javaish is also Clojurish, but I still feel a
difference).

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


Re: Datatypes and Protocols update

2010-04-27 Thread Konrad Hinsen

On 27 Apr 2010, at 09:20, Mark Engelberg wrote:


I understand that you can always do Foo. to construct a Foo record,
but these constructors don't act as full-fledged functions, right?


No. They are not first-class objects (in fact, not objects at all in  
the JVM sense), so you can't pass them around.



Honestly, for me the main issue is just that subjectively, it is less
satisfying to create a Clojure data structure and end up with
something that you construct with Java interop syntax.  I'd like
Clojure data structures to look and feel Clojurish not Javaish


That was my initial reaction as well. However, I just write my own  
factory functions now, and this gives me the opportunity to add  
argument validation in any way I like.


BTW, another change is that the defined type is a Java class, whereas  
before it was a var pointing to the factory function. Not being a var  
means that the type doesn't really reside in the namespace. In  
particular, a :use of the namespace doesn't get you the type, you have  
to :import it.


Taken together, these changes make deftype and defrecord low-level  
features for defining data types that are best exposed to the outside  
world via a functional API. Your clients don't need to know that  
there's a Java type with a constructor hidden somewhere.


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


Re: Datatypes and Protocols update

2010-04-27 Thread Rich Hickey


On Apr 27, 2010, at 3:20 AM, Mark Engelberg wrote:


Watching Stuart's tutorial, it looks like the automatic factory
functions for deftypes have gone away (I'm still working with Clojure
1.1, so haven't had a chance to try the latest changes for myself).
I'm going to miss that feature, especially for defrecord, which is now
the common case construct.

I understand that you can always do Foo. to construct a Foo record,
but these constructors don't act as full-fledged functions, right?

Honestly, for me the main issue is just that subjectively, it is less
satisfying to create a Clojure data structure and end up with
something that you construct with Java interop syntax.  I'd like
Clojure data structures to look and feel Clojurish not Javaish
(yes, I know that Clojure is built with interop in mind, so
technically, anything Javaish is also Clojurish, but I still feel a
difference).




I agree. I asked for suggestions for the factory fn in #clojure, but  
got some pushback against introducing things in the namespace. I'm  
still open to suggestions, here are the issues:


The generated type name is now imported, so at the very least the  
factory fn can't have the same name as the class. Alternatives are  
create-Foo etc.


Some have asked for parameterized factories:

(record Foo ...) or (record ::Foo ...)

These cannot be made as fast as direct factories. Also, they may be  
used for key/value initialization:


(record ::Foo :field1 v1 :field2 v2 ...)

As soon as people want bodies for the factories, in order to do  
argument transformation/validation/defaulting, a generated factory is  
in the way.


We left it at: If you really want a factory you can always write one,  
let's see if people do.


Rich

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


Re: Datatypes and Protocols update

2010-04-27 Thread Konrad Hinsen
On 27.04.2010, at 14:45, Rich Hickey wrote:

 I agree. I asked for suggestions for the factory fn in #clojure, but got some 
 pushback against introducing things in the namespace. I'm still open to 
 suggestions, here are the issues:
 
 The generated type name is now imported, so at the very least the factory fn 
 can't have the same name as the class. Alternatives are create-Foo etc.

How about providing the name of a factory function via an option, with no 
factory as the default? Something like

(defrecord Foo
  [bar baz]
  :factory create-Foo)

This would avoid the creation of vars that are not explicitly named in the 
code, and thus bad surprises.

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


Re: Datatypes and Protocols update

2010-04-26 Thread Rich Hickey


On Apr 23, 2010, at 11:48 PM, Mark Engelberg wrote:


A few meandering observations:

I like the latest change to include a this argument.  It makes the
number of arguments line up which is a good thing.

I like the idea of defrecord for the common case, rather than having
to request default implementations of various interfaces within
deftype.  Still, I think the splitting of deftype and defrecord has
merely delayed, not eliminated, the need to eventually find a
convenient, general scheme for layering in default implementations of
interfaces.  I look forward to seeing how this evolves.

I like Rich's description of Clojure's datatypes/protocols as
opinionated, and mostly agree with his manifesto.  The one opinion I
have the most difficulty with is:
It has always been an unfortunate characteristic of using classes for
application domain information that it resulted in information being
hidden behind class-specific micro-languages, e.g. even the seemingly
harmless employee.getName() is a custom interface to data. Putting
information in such classes is a problem, much like having every book
being written in a different language would be a problem. You can no
longer take a generic approach to information processing. This results
in an explosion of needless specificity, and a dearth of reuse.

OO programmers write employee.getName() methods to preserve the option
of doing something more sophisticated later, which isn't readily
possible once all your clients start using employee.name everywhere.
So if you really want to create a generic approach to information
processing, it seems like the best approach is to address the
underlying reason that these custom interfaces are needed.

For this reason, I've always found appealing languages which let you
optionally write getter/setter methods that hook into the standard
field access syntax.  This lets you start out with your fields public,
and let your clients use the standard field access interface.
Later, if you realize you need to do something special, you can easily
add a custom getter without breaking your clients.

As far as I know, Clojure doesn't currently make any attempt to
address this problem of allowing a standard way to access public data
from an object, while preserving the option of doing something more
sophisticated later.  So a programmer is still forced to choose
between the convenience of keyword lookup of data, versus a protocol
filled with get-name functions to preserve future flexibility.

Ideally, I'd like to see a way to allow me to write a program using
(:name employee), and later, if I need to, customize the employee
datatype so that (:name employee) actually dispatches to some other
function.  Ditto with (assoc employee :name Mark) (for example, to
validate the data in some way?).

If I'm off-base, and these issues are easy to currently workaround in
Clojure, I'd love to hear more about how others are handling this in
their own programs.





You can use functions if you don't like unencapsulated data.

Weren't you also advocating for serialization? Such things become much  
simpler when one knows they are dealing with just data, and not the  
results of some (possibly irreversible) function, of some other  
possibly uninitialized dependents etc.


You need a level that is the data (even under some 'property' system).  
The keyword-accessible, constructor-mapped fields are that layer. You  
can always build functions on top of that.


Calculated getters/setters are one of those rich sources of incidental  
complexity, with little real-world benefit IMO.


That said, defrecord is simply implemented in terms of deftype. People  
can easily prototype alternatives for consideration.


Rich

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

Re: Datatypes and Protocols update

2010-04-26 Thread Rich Hickey


On Apr 24, 2010, at 1:11 PM, Richard Newman wrote:


Neither of those attributes reveal information about the
implementation of the objects in question. They both reveal
information about the state that some client could find useful. They
are both values that, if not directly available from the object  
should

be calculated by the object, as calculating the value requires
knowledge about the implementation.


This approach still isn't 'good' OO -- it might not leak  
implementation details, but it supports asking, not telling.


http://pragprog.com/articles/tell-dont-ask

That is, you should endeavor to tell objects what you want them to  
do; do not ask them questions about their state, make a decision,  
and then tell them what to do.





To the extent OO tries to make information into objects, it isn't  
'good', IMO. That article is a good example of how goofy things get  
when you try to turn information into objects. Information is data.  
Records are for information.


Why ever would I want to try to 'tell' a piece of information anything?

The datatype and protocol system is there to support the polymorphic  
manipulation of data by functions, not for recreating OO rabbit holes.


Rich

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


Re: Datatypes and Protocols update

2010-04-26 Thread Konrad Hinsen
On 24.04.2010, at 05:48, Mark Engelberg wrote:

 As far as I know, Clojure doesn't currently make any attempt to
 address this problem of allowing a standard way to access public data
 from an object, while preserving the option of doing something more
 sophisticated later.  So a programmer is still forced to choose
 between the convenience of keyword lookup of data, versus a protocol
 filled with get-name functions to preserve future flexibility.

This is basically a question of how you choose your abstractions (the 
documented interfaces) and your implementations (the data structures), and in 
particular on where you draw the boundaries. That is a design issue, so I don't 
expect any language feature to remove the necessity to think about this 
carefully.

 For this reason, I've always found appealing languages which let you
 optionally write getter/setter methods that hook into the standard
 field access syntax.

That's little more than syntactic sugar, considering that field access is 
equivalent to calling a method with no arguments.

The closest equivalent in Clojure would be to define a functional accessor API 
for all access to your data. A first implementation would simply set the 
accessor to be a field-name keyword:

(defrecord foo [bar baz])
(def get-bar :bar)
(def get-baz :baz)

If necessary you can then replace the accessor functions by something more 
complicated, or turn them into prototype functions to allow multiple 
implementations. Client code won't see the difference.

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


Re: Datatypes and Protocols update

2010-04-24 Thread MarkSwanson
 You can no
 longer take a generic approach to information processing. This results
 in an explosion of needless specificity, and a dearth of reuse.

 For this reason, I've always found appealing languages which let you
 optionally write getter/setter methods that hook into the standard
 field access syntax.  This lets you start out with your fields public,
 and let your clients use the standard field access interface.
 Later, if you realize you need to do something special, you can easily
 add a custom getter without breaking your clients.

I'd argue that leaky abstractions like getter/setter methods are evil,
and a good article (from a Java/imperative perspective) describing why
can be found here:
http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html?page=1

I think that the quote above from Rich is another good description of
why getter/setter methods are bad from a functional perspective.

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


Re: Datatypes and Protocols update

2010-04-24 Thread Mike Meyer
On Sat, 24 Apr 2010 06:51:18 -0700 (PDT)
MarkSwanson mark.swanson...@gmail.com wrote:

  You can no
  longer take a generic approach to information processing. This results
  in an explosion of needless specificity, and a dearth of reuse.
 
  For this reason, I've always found appealing languages which let you
  optionally write getter/setter methods that hook into the standard
  field access syntax.  This lets you start out with your fields public,
  and let your clients use the standard field access interface.
  Later, if you realize you need to do something special, you can easily
  add a custom getter without breaking your clients.
 
 I'd argue that leaky abstractions like getter/setter methods are evil,
 and a good article (from a Java/imperative perspective) describing why
 can be found here:
 http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html?page=1

I think his fundamental assumption - that getter/setters reveal
details of the implementation - is wrong. They *can* do that, and
possibly in the Java world they normally do do that. But properly
used, attributes reveal information about the *state* of the object,
not about the implementation. Classic examples would be a queue object
with a length attribute, or a financial account object with a
balance attribute.

Neither of those attributes reveal information about the
implementation of the objects in question. They both reveal
information about the state that some client could find useful. They
are both values that, if not directly available from the object should
be calculated by the object, as calculating the value requires
knowledge about the implementation.

 I think that the quote above from Rich is another good description of
 why getter/setter methods are bad from a functional perspective.

Given that your attributes that aren't just random variables from the
implementation, but are reasonable things for a client to want to
know, then the unattributed inner quote nailed it: languages that
don't distinguish between reading the value of an attribute and
invoking a zero-argument method - or at least allow you to make the
latter look like the former - hide that specificity and encourage
reuse.

mike
-- 
Mike Meyer m...@mired.org http://www.mired.org/consulting.html
Independent Network/Unix/Perforce consultant, email for more information.

O ascii ribbon campaign - stop html mail - www.asciiribbon.org

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


Re: Datatypes and Protocols update

2010-04-24 Thread Per Vognsen
A lot of these arguments go away with functional programming. With a
functional queue, you might as well store the length as a value
attribute because it won't ever change. In some cases I can see the
argument for on-demand computation of fields with referentially
transparent caching. That's where the delay form comes in. If you're
using the delay form to hide a very expensive computation, it's
probably good to express that in the interface by requiring explicit
forcing, rather than having an innocent-looking map lookup take
arbitrary time to execute because it forces the evaluation of a
delayed expression.

-Per

On Sat, Apr 24, 2010 at 9:39 PM, Mike Meyer
mwm-keyword-googlegroups.620...@mired.org wrote:
 On Sat, 24 Apr 2010 06:51:18 -0700 (PDT)
 MarkSwanson mark.swanson...@gmail.com wrote:

  You can no
  longer take a generic approach to information processing. This results
  in an explosion of needless specificity, and a dearth of reuse.

  For this reason, I've always found appealing languages which let you
  optionally write getter/setter methods that hook into the standard
  field access syntax.  This lets you start out with your fields public,
  and let your clients use the standard field access interface.
  Later, if you realize you need to do something special, you can easily
  add a custom getter without breaking your clients.

 I'd argue that leaky abstractions like getter/setter methods are evil,
 and a good article (from a Java/imperative perspective) describing why
 can be found here:
 http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html?page=1

 I think his fundamental assumption - that getter/setters reveal
 details of the implementation - is wrong. They *can* do that, and
 possibly in the Java world they normally do do that. But properly
 used, attributes reveal information about the *state* of the object,
 not about the implementation. Classic examples would be a queue object
 with a length attribute, or a financial account object with a
 balance attribute.

 Neither of those attributes reveal information about the
 implementation of the objects in question. They both reveal
 information about the state that some client could find useful. They
 are both values that, if not directly available from the object should
 be calculated by the object, as calculating the value requires
 knowledge about the implementation.

 I think that the quote above from Rich is another good description of
 why getter/setter methods are bad from a functional perspective.

 Given that your attributes that aren't just random variables from the
 implementation, but are reasonable things for a client to want to
 know, then the unattributed inner quote nailed it: languages that
 don't distinguish between reading the value of an attribute and
 invoking a zero-argument method - or at least allow you to make the
 latter look like the former - hide that specificity and encourage
 reuse.

        mike
 --
 Mike Meyer m...@mired.org              http://www.mired.org/consulting.html
 Independent Network/Unix/Perforce consultant, email for more information.

 O ascii ribbon campaign - stop html mail - www.asciiribbon.org

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


Re: Datatypes and Protocols update

2010-04-24 Thread Richard Newman

Neither of those attributes reveal information about the
implementation of the objects in question. They both reveal
information about the state that some client could find useful. They
are both values that, if not directly available from the object should
be calculated by the object, as calculating the value requires
knowledge about the implementation.


This approach still isn't 'good' OO -- it might not leak  
implementation details, but it supports asking, not telling.


http://pragprog.com/articles/tell-dont-ask

That is, you should endeavor to tell objects what you want them to  
do; do not ask them questions about their state, make a decision, and  
then tell them what to do.


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


Re: Datatypes and Protocols update

2010-04-23 Thread Konrad Hinsen

On 22 Apr 2010, at 21:15, Konrad Hinsen wrote:

I have several former deftypes that are a perfect fit for the new  
defrecord, except that they need a specific comparison function.  
This is usually for excluding some fields from equality testing, or  
for requiring identity rather than equality for some fields.


What I'd actually like to have for defrecord is an equality protocol  
that I can implement myself or use a default implementation. That  
protocol would have a function equals guaranteed to be called only  
if the object compared to is of the same type. Object.equals would  
take care of type testing and then call the protocol function. That  
would remove the check-type-before-comparing-fields overhead that  
every equals implementation for deftype and defrecord currently  
requires.


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


Re: Datatypes and Protocols update

2010-04-23 Thread ataggart
One problem with requiring the other object to be of the same type
is that it would break the current model, e.g.:

user= (= '(1 2 3) [1 2 3])
true

I'm left to wonder if it the more correct implementation of the
desired behavior is not to override the equals, but rather to
implement Comparable.


On Apr 23, 12:12 am, Konrad Hinsen konrad.hin...@fastmail.net wrote:
 On 22 Apr 2010, at 21:15, Konrad Hinsen wrote:

  I have several former deftypes that are a perfect fit for the new  
  defrecord, except that they need a specific comparison function.  
  This is usually for excluding some fields from equality testing, or  
  for requiring identity rather than equality for some fields.

 What I'd actually like to have for defrecord is an equality protocol  
 that I can implement myself or use a default implementation. That  
 protocol would have a function equals guaranteed to be called only  
 if the object compared to is of the same type. Object.equals would  
 take care of type testing and then call the protocol function. That  
 would remove the check-type-before-comparing-fields overhead that  
 every equals implementation for deftype and defrecord currently  
 requires.

 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
 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 
 athttp://groups.google.com/group/clojure?hl=en

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


Re: Datatypes and Protocols update

2010-04-23 Thread Rich Hickey


On Apr 22, 2010, at 3:15 PM, Konrad Hinsen wrote:


On 22.04.2010, at 18:53, Rich Hickey wrote:


Feedback and errata welcome as always,


One feature in the deftype/defrecord split that I regret is that  
defrecord no longer allows the redefinition of equals and hashCode.  
Any attempt to override those results in an error message about  
duplicate method definitions.


I have several former deftypes that are a perfect fit for the new  
defrecord, except that they need a specific comparison function.  
This is usually for excluding some fields from equality testing, or  
for requiring identity rather than equality for some fields.


It is a design goal of defrecord that the types it creates have  
uniform semantics. As soon as you have user-defined equality you can  
get broken semantics.




As it is, I must convert all these to the new deftype, losing the  
convient field access through keywords.




You can get that back easily by implementing ILookup/IKeywordLookup,  
as does defrecord. I still have ideas about macro-like mixins for use  
in deftype, but I concluded the mandatory use of such mixins to create  
record-like things was too much user effort, and we need more  
experience with code reuse in deftype to determine need.


Rich



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


Re: Datatypes and Protocols update

2010-04-23 Thread Rich Hickey


On Apr 23, 2010, at 3:12 AM, Konrad Hinsen wrote:


On 22 Apr 2010, at 21:15, Konrad Hinsen wrote:

I have several former deftypes that are a perfect fit for the new  
defrecord, except that they need a specific comparison function.  
This is usually for excluding some fields from equality testing, or  
for requiring identity rather than equality for some fields.


What I'd actually like to have for defrecord is an equality  
protocol that I can implement myself or use a default  
implementation. That protocol would have a function equals  
guaranteed to be called only if the object compared to is of the  
same type. Object.equals would take care of type testing and then  
call the protocol function. That would remove the check-type-before- 
comparing-fields overhead that every equals implementation for  
deftype and defrecord currently requires.




There's not much 'overhead' to that check.

Rich


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


Re: Datatypes and Protocols update

2010-04-23 Thread Rich Hickey


On Apr 22, 2010, at 1:30 PM, Mark Engelberg wrote:


I tried using deftype relatively recently, but realized it wouldn't
work for my needs because serialization via *print-dup* wasn't yet
implemented.  I'd recommend including this with the 1.2 release (or is
there a new recommended way to serialize Clojure data?)


print-dup is likely for defrecord, but not deftype (roll your own  
there).


Rich


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


Re: Datatypes and Protocols update

2010-04-23 Thread Krukow
On Apr 22, 6:53 pm, Rich Hickey richhic...@gmail.com wrote:
[snip..]
 Feedback and errata welcome as always,


1) Typo on http://clojure.org/protocols:

Section Basics
defprotocol will automatically generate a corresponding interface,
with the same name as the protocol, i.e. given a protocol my.ns/
Protocol, an interface my.ns.MyProtocol.

my.ns.MyProtocol = my.ns.Protocol


2) Question. Could someone elaborate on the bullet

You can implement a protocol on an interface

Spefically the relation to multiple inheritance

3) When is 1.2 expected (roughly)?

Thanks,
/Karl

[snip..]

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


Re: Datatypes and Protocols update

2010-04-23 Thread Konrad Hinsen
On 23.04.2010, at 17:49, ataggart wrote:

 One problem with requiring the other object to be of the same type
 is that it would break the current model, e.g.:
 
 user= (= '(1 2 3) [1 2 3])
 true

I'd want this only for defrecord, which is a more limited (but also more 
convenient) way to define types. For the more basic and general deftype, 
everything should be possible.

However, a perhaps better way to arrive at the same goal is to provide a macro 
that takes care of the type comparison.

 I'm left to wonder if it the more correct implementation of the
 desired behavior is not to override the equals, but rather to
 implement Comparable.

Comparable requires a fully defined order relation, if I remember correctly. 
And it's not used by the standard Clojure comparison operators.

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


Re: Datatypes and Protocols update

2010-04-23 Thread Konrad Hinsen
On 23.04.2010, at 19:20, Rich Hickey wrote:

 You can get that back easily by implementing ILookup/IKeywordLookup, as does 
 defrecord. I still have ideas about macro-like mixins for use in deftype, but 
 I concluded the mandatory use of such mixins to create record-like things was 
 too much user effort, and we need more experience with code reuse in deftype 
 to determine need.

That sounds very interesting. I have been playing with various ideas for 
reusing method code in several defttypes, but I am not really happy with any of 
them. Macros are difficult to use because nothing at the toplevel of a deftype 
form is macro-expanded. Syntax-quote is messy because it requires so many 
symbols to be prefixed with ~'. I ended up writing my own little templating 
system but its use is getting messier all the time as well.

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


Re: Datatypes and Protocols update

2010-04-23 Thread Mark Engelberg
A few meandering observations:

I like the latest change to include a this argument.  It makes the
number of arguments line up which is a good thing.

I like the idea of defrecord for the common case, rather than having
to request default implementations of various interfaces within
deftype.  Still, I think the splitting of deftype and defrecord has
merely delayed, not eliminated, the need to eventually find a
convenient, general scheme for layering in default implementations of
interfaces.  I look forward to seeing how this evolves.

I like Rich's description of Clojure's datatypes/protocols as
opinionated, and mostly agree with his manifesto.  The one opinion I
have the most difficulty with is:
It has always been an unfortunate characteristic of using classes for
application domain information that it resulted in information being
hidden behind class-specific micro-languages, e.g. even the seemingly
harmless employee.getName() is a custom interface to data. Putting
information in such classes is a problem, much like having every book
being written in a different language would be a problem. You can no
longer take a generic approach to information processing. This results
in an explosion of needless specificity, and a dearth of reuse.

OO programmers write employee.getName() methods to preserve the option
of doing something more sophisticated later, which isn't readily
possible once all your clients start using employee.name everywhere.
So if you really want to create a generic approach to information
processing, it seems like the best approach is to address the
underlying reason that these custom interfaces are needed.

For this reason, I've always found appealing languages which let you
optionally write getter/setter methods that hook into the standard
field access syntax.  This lets you start out with your fields public,
and let your clients use the standard field access interface.
Later, if you realize you need to do something special, you can easily
add a custom getter without breaking your clients.

As far as I know, Clojure doesn't currently make any attempt to
address this problem of allowing a standard way to access public data
from an object, while preserving the option of doing something more
sophisticated later.  So a programmer is still forced to choose
between the convenience of keyword lookup of data, versus a protocol
filled with get-name functions to preserve future flexibility.

Ideally, I'd like to see a way to allow me to write a program using
(:name employee), and later, if I need to, customize the employee
datatype so that (:name employee) actually dispatches to some other
function.  Ditto with (assoc employee :name Mark) (for example, to
validate the data in some way?).

If I'm off-base, and these issues are easy to currently workaround in
Clojure, I'd love to hear more about how others are handling this in
their own programs.

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


Re: Datatypes and Protocols update

2010-04-23 Thread Michał Marczyk
On 24 April 2010 05:48, Mark Engelberg mark.engelb...@gmail.com wrote:
 Ideally, I'd like to see a way to allow me to write a program using
 (:name employee), and later, if I need to, customize the employee
 datatype so that (:name employee) actually dispatches to some other
 function.  Ditto with (assoc employee :name Mark) (for example, to
 validate the data in some way?).

You can do that with deftype by implementing the appropriate
interfaces, like Rich mentioned in response to Konrad above. I've been
playing around with this actually:

http://gist.github.com/377480

Note that (:x (Foo. 1 2 3) nil) returns 1, while ((Foo. 1 2 3) :x)
returns 2. (It could be the other way around or whatever, anything
seems possible.)

Also note that for some reason (:x (Foo. 1 2 3) nil) works fine, while
(:x (Foo. 1 2 3)) throws an exception; not sure if I've run into a bug
here or simply done something silly (I'd expect the latter though).

Sincerely,
Michał

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


Re: Datatypes and Protocols update

2010-04-22 Thread Mark Engelberg
I tried using deftype relatively recently, but realized it wouldn't
work for my needs because serialization via *print-dup* wasn't yet
implemented.  I'd recommend including this with the 1.2 release (or is
there a new recommended way to serialize Clojure data?)

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


Re: Datatypes and Protocols update

2010-04-22 Thread Konrad Hinsen
On 22.04.2010, at 18:53, Rich Hickey wrote:

 Feedback and errata welcome as always,

One feature in the deftype/defrecord split that I regret is that defrecord no 
longer allows the redefinition of equals and hashCode. Any attempt to override 
those results in an error message about duplicate method definitions.

I have several former deftypes that are a perfect fit for the new defrecord, 
except that they need a specific comparison function. This is usually for 
excluding some fields from equality testing, or for requiring identity rather 
than equality for some fields.

As it is, I must convert all these to the new deftype, losing the convient 
field access through keywords.

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


Re: Datatypes and Protocols update

2010-04-22 Thread ataggart
On protocols:
- doc string coming after the arg vecs seems odd. I'm used to putting
them after the name of whatever I'm working on.

On protocols doc:
- You can implement a protocol on nil ... Object: could you
elaborate on how these work and/or provide examples? I think this will
solve the one problem I was running into earlier.
- given a protocol my.ns/Protocol, an interface my.ns.MyProtocol:
the final segments don't match.




On Apr 22, 9:53 am, Rich Hickey richhic...@gmail.com wrote:
 I have been doing some work cleaning up the design and implementation
 of datatypes and protocols in preparation for the 1.2 release. Some
 notable changes for those who have been working with the earlier
 versions:

 deftype/reify now take an explicit 'this' argument in method sigs.
 The :as option is gone.

 There is a new datatype construct, defrecord. defrecord includes the
 implementation of persistent map, and the IPersistentMap magic of
 deftype is gone.

 deftype and defrecord create named classes, even in non-AOT use. There
 is no factory fn created, instead you can just call the constructor.

 The types for defrecord, deftype and definterface are automatically
 imported into the defining namespace.

 Substantial performance improvements to extend, and to higher-order
 use of protocol fns.

 In addition, I have started documenting these on the clojure.org site,
 and you should use this documentation instead of the wiki design docs,
 which will not be maintained.

 http://clojure.org/protocolshttp://clojure.org/datatypes

 Please note that these are just higher-level descriptions, and contain
 links to the detailed function docs, which are a must-read prior to
 use.

 Feedback and errata welcome as always,

 Rich

 --
 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 
 athttp://groups.google.com/group/clojure?hl=en

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


Re: Datatypes and Protocols update

2010-04-22 Thread Stuart Halloway
A good place to look for examples is protocols.clj and gvec.clj in  
clojure itself. protocols.clj includes an example of implementing a  
protocol on nil.


Stu


On protocols:
- doc string coming after the arg vecs seems odd. I'm used to putting
them after the name of whatever I'm working on.

On protocols doc:
- You can implement a protocol on nil ... Object: could you
elaborate on how these work and/or provide examples? I think this will
solve the one problem I was running into earlier.
- given a protocol my.ns/Protocol, an interface my.ns.MyProtocol:
the final segments don't match.




On Apr 22, 9:53 am, Rich Hickey richhic...@gmail.com wrote:

I have been doing some work cleaning up the design and implementation
of datatypes and protocols in preparation for the 1.2 release. Some
notable changes for those who have been working with the earlier
versions:

deftype/reify now take an explicit 'this' argument in method sigs.
The :as option is gone.

There is a new datatype construct, defrecord. defrecord includes the
implementation of persistent map, and the IPersistentMap magic of
deftype is gone.

deftype and defrecord create named classes, even in non-AOT use.  
There

is no factory fn created, instead you can just call the constructor.

The types for defrecord, deftype and definterface are automatically
imported into the defining namespace.

Substantial performance improvements to extend, and to higher-order
use of protocol fns.

In addition, I have started documenting these on the clojure.org  
site,
and you should use this documentation instead of the wiki design  
docs,

which will not be maintained.

http://clojure.org/protocolshttp://clojure.org/datatypes

Please note that these are just higher-level descriptions, and  
contain

links to the detailed function docs, which are a must-read prior to
use.

Feedback and errata welcome as always,

Rich

--
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 
athttp://groups.google.com/group/clojure?hl=en


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


Re: Datatypes and Protocols update

2010-04-22 Thread Jason Wolfe
+1, I am also using this feature of the old deftype.

On Apr 22, 12:15 pm, Konrad Hinsen konrad.hin...@fastmail.net wrote:
 On 22.04.2010, at 18:53, Rich Hickey wrote:

  Feedback and errata welcome as always,

 One feature in the deftype/defrecord split that I regret is that defrecord no 
 longer allows the redefinition of equals and hashCode. Any attempt to 
 override those results in an error message about duplicate method definitions.

 I have several former deftypes that are a perfect fit for the new defrecord, 
 except that they need a specific comparison function. This is usually for 
 excluding some fields from equality testing, or for requiring identity rather 
 than equality for some fields.

 As it is, I must convert all these to the new deftype, losing the convient 
 field access through keywords.

 Konrad.

 --
 You received this message because you are subscribed to the Google
 Groups Clojure group.To post to this group, send email 
 tocloj...@googlegroups.com
 Note that posts from new members are moderated - please be patient with your 
 first post.
 To unsubscribe from this group, send email 
 toclojure+unsubscr...@googlegroups.com
 For more options, visit this group 
 athttp://groups.google.com/group/clojure?hl=en

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


Re: Datatypes and Protocols update

2010-04-22 Thread ataggart
Ah, great!  And of course the piece I as missing is that nil and
Object get supported via extend.  Makes sense now given that that was
the section of the doc, but it didn't click the first time through.

On Apr 22, 2:54 pm, Stuart Halloway stuart.hallo...@gmail.com wrote:
 A good place to look for examples is protocols.clj and gvec.clj in  
 clojure itself. protocols.clj includes an example of implementing a  
 protocol on nil.

 Stu





  On protocols:
  - doc string coming after the arg vecs seems odd. I'm used to putting
  them after the name of whatever I'm working on.

  On protocols doc:
  - You can implement a protocol on nil ... Object: could you
  elaborate on how these work and/or provide examples? I think this will
  solve the one problem I was running into earlier.
  - given a protocol my.ns/Protocol, an interface my.ns.MyProtocol:
  the final segments don't match.

  On Apr 22, 9:53 am, Rich Hickey richhic...@gmail.com wrote:
  I have been doing some work cleaning up the design and implementation
  of datatypes and protocols in preparation for the 1.2 release. Some
  notable changes for those who have been working with the earlier
  versions:

  deftype/reify now take an explicit 'this' argument in method sigs.
  The :as option is gone.

  There is a new datatype construct, defrecord. defrecord includes the
  implementation of persistent map, and the IPersistentMap magic of
  deftype is gone.

  deftype and defrecord create named classes, even in non-AOT use.  
  There
  is no factory fn created, instead you can just call the constructor.

  The types for defrecord, deftype and definterface are automatically
  imported into the defining namespace.

  Substantial performance improvements to extend, and to higher-order
  use of protocol fns.

  In addition, I have started documenting these on the clojure.org  
  site,
  and you should use this documentation instead of the wiki design  
  docs,
  which will not be maintained.

 http://clojure.org/protocolshttp://clojure.org/datatypes

  Please note that these are just higher-level descriptions, and  
  contain
  links to the detailed function docs, which are a must-read prior to
  use.

  Feedback and errata welcome as always,

  Rich

  --
  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 
  athttp://groups.google.com/group/clojure?hl=en

  --
  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 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 
 athttp://groups.google.com/group/clojure?hl=en

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


Re: Datatypes and Protocols update

2010-04-22 Thread MarkSwanson
Minor errata barely worth mentioning:on the page: http://clojure.org/datatypes

employeee.getName()

employeee needs just 2 'e' characters.

Cheers.

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


Re: Datatypes and protocols - update

2009-12-12 Thread ataggart


On Dec 11, 11:56 pm, ataggart alex.tagg...@gmail.com wrote:
 On Dec 11, 11:44 pm, ataggart alex.tagg...@gmail.com wrote:





  On Dec 11, 4:14 pm, Jason Wolfe jawo...@berkeley.edu wrote:

   I've been trying out the new branch, and on the whole I like it a lot.
    I know it'll take some time to learn how do things properly the new
   way, and I've figured out how to do most of the things I want to do
   thus far.  Thanks, Rich!

   One thing I haven't figured out how to do cleanly without inheritance
   is to specify properties of objects in a hierarchical domain in a
   clean, efficient way.  I'm sure I haven't fully wrapped my head around
   the new abstractions, so I'd love to hear about a clean way to solve
   this problem.

   A very simple example is: I have a protocol A, and sub-protocols
   A1 and A2.  Every A is either an A1 or A2, but not both (and this
   split is closed, as far as I'm concerned).  Sometimes I want to deal
   with instances of A1 and A2 together, and so I put the methods shared
   between all As in protocol A.  But, at some point I need to
   separate out the A1s from the A2s.  To do this, it seems like I
   have at least three options:

   1.  Add an is-A1 method to Protocol A.  The problem with this option
   is that every type that derives from A1 needs to manually write out
   this method returning true, and vice-versa for implementers of A2.
   Users could eliminate this by extending their types with a mixin map
   to A, rather than implementing it directly in the deftype.  But, this
   sacrifices readability (IMO) as well as efficiency.

   2.  use (satisfies? A1 x) to determine if x satisfies A1.  The main
   problem with this, at least currently, is that satisfies? seems to be
   really slow in the negative case.  I profiled my (non-trivial) program
   and half the runtime was going to reflection in satisfies?  Moreover,
   this solution is not as general.

   3.  Use a multimethod.  This would work generally and be reasonably
   efficient, but I feel like I'd be cluttering up my interface by mixing
   up protocols and multimethods.  On the other hand, I guess
   multimethods are the main (only?) hierarchical construct built into
   Clojure, so maybe this is what's intended.

   So, which do people feel is preferred?  Or have I missed a better
   option?

   Thanks!
   Jason

  If I understand Rich's reasoning, what you want runs antithetical to
  the protocols design, namely it being explicitly non-hierarchical.

  As such, you'd instead have 3 composable protocols, A, B, and C (where
  B and C would correspond to the functions of A1 and A2, respectively):

  (defprotocol A (a [x]))
  (defprotocol B (b [x]))
  (defprotocol C (c [x]))

  And then the type would reify the appropriate protocols:

  (deftype A1 [] A B
    (a [] (println in A1.a))
    (b [] (println in A1.b)))

  (deftype A2 [] A C
    (a [] (println in A2.a))
    (c [] (println in A2.c)))

 I should also note that isa? can be used for differentiation:

 user= (def my-a (A1))
 #'user/my-a
 user= (isa? (type my-a) ::A1)
 true
 user= (isa? (type my-a) ::A2)
 false

Oh, and it occurs to me that you could create an after-the-fact
hierarchical relationship:

user= (derive ::A1 ::A)
nil
user= (derive ::A2 ::A)
nil
user= (isa? (type my-a) ::A)
true

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


Re: Datatypes and protocols - update

2009-12-12 Thread Konrad Hinsen
On 12 Dec 2009, at 01:14, Jason Wolfe wrote:

 A very simple example is: I have a protocol A, and sub-protocols
 A1 and A2.  Every A is either an A1 or A2, but not both (and this
 split is closed, as far as I'm concerned).  Sometimes I want to deal
 with instances of A1 and A2 together, and so I put the methods shared
 between all As in protocol A.  But, at some point I need to
 separate out the A1s from the A2s.  To do this, it seems like I
 have at least three options:

Those are the options you have in the world of protocols, types/ 
classes, and hierarchies. But there are many more options for  
classifying objects. For example, you could have a set A1 to which you  
add all the types in your A1 category. Or you could call functions  
specific to A1 or A2 through a lookup table implemented as a map. I  
can't judge if any of these would work fine for you, of course.

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


Re: Datatypes and protocols - update

2009-12-12 Thread Rich Hickey


On Dec 11, 8:48 am, Chris Kent cjk...@gmail.com wrote:
 Rich Hickey richhickey at gmail.com writes:



  An updated version of the code for datatypes[1] and protocols[2] is
  now available in the 'new' branch[3].

 I've converted some code that used gen-class to use deftype and defprotocol 
 and
 the results are great so far.  The code is shorter, easier to write and the
 intent is much clearer.  I'm a big fan.

 I've come across one problem though.  I've created a type with deftype that
 calls a function in one of its methods:

 (ns ns1.deftypetest)

 (defn bar [] bar)
 (defprotocol P (foo [p]))
 (deftype T [] P (foo [] (bar)))

 When I compile the namespace, create an instance of the type from Java and
 invoke the foo method I get:

 java.lang.IllegalStateException: Var ns1.deftypetest/bar is unbound.

 I guess the namespace isn't getting loaded.  Should this work?  I've created a
 class in the same namespace using gen-class and that has no problem invoking 
 the
 function when it's instantiated from Java.


Currently deftype classes do no automatic namespace loading, unlike
gen-class classes. The difference is gen-class classes are AOT-only,
whereas deftype classes can be defined dynamically, where reloading
namespaces would not be desired. I'm still thinking about how best to
support Java consumption of deftype classes. For now, you will need
some init glue code to load any support namespaces.

Rich

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


Re: Datatypes and protocols - update

2009-12-11 Thread Chris Kent
Rich Hickey richhickey at gmail.com writes:

 
 An updated version of the code for datatypes[1] and protocols[2] is
 now available in the 'new' branch[3].

I've converted some code that used gen-class to use deftype and defprotocol and
the results are great so far.  The code is shorter, easier to write and the
intent is much clearer.  I'm a big fan.

I've come across one problem though.  I've created a type with deftype that
calls a function in one of its methods:

(ns ns1.deftypetest)

(defn bar [] bar)
(defprotocol P (foo [p]))
(deftype T [] P (foo [] (bar)))

When I compile the namespace, create an instance of the type from Java and
invoke the foo method I get:

java.lang.IllegalStateException: Var ns1.deftypetest/bar is unbound.

I guess the namespace isn't getting loaded.  Should this work?  I've created a
class in the same namespace using gen-class and that has no problem invoking the
function when it's instantiated from Java.

Thanks
Chris


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


Re: Datatypes and protocols - update

2009-12-11 Thread Jason Wolfe
I've been trying out the new branch, and on the whole I like it a lot.
 I know it'll take some time to learn how do things properly the new
way, and I've figured out how to do most of the things I want to do
thus far.  Thanks, Rich!

One thing I haven't figured out how to do cleanly without inheritance
is to specify properties of objects in a hierarchical domain in a
clean, efficient way.  I'm sure I haven't fully wrapped my head around
the new abstractions, so I'd love to hear about a clean way to solve
this problem.

A very simple example is: I have a protocol A, and sub-protocols
A1 and A2.  Every A is either an A1 or A2, but not both (and this
split is closed, as far as I'm concerned).  Sometimes I want to deal
with instances of A1 and A2 together, and so I put the methods shared
between all As in protocol A.  But, at some point I need to
separate out the A1s from the A2s.  To do this, it seems like I
have at least three options:

1.  Add an is-A1 method to Protocol A.  The problem with this option
is that every type that derives from A1 needs to manually write out
this method returning true, and vice-versa for implementers of A2.
Users could eliminate this by extending their types with a mixin map
to A, rather than implementing it directly in the deftype.  But, this
sacrifices readability (IMO) as well as efficiency.

2.  use (satisfies? A1 x) to determine if x satisfies A1.  The main
problem with this, at least currently, is that satisfies? seems to be
really slow in the negative case.  I profiled my (non-trivial) program
and half the runtime was going to reflection in satisfies?  Moreover,
this solution is not as general.

3.  Use a multimethod.  This would work generally and be reasonably
efficient, but I feel like I'd be cluttering up my interface by mixing
up protocols and multimethods.  On the other hand, I guess
multimethods are the main (only?) hierarchical construct built into
Clojure, so maybe this is what's intended.

So, which do people feel is preferred?  Or have I missed a better
option?

Thanks!
Jason

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


Re: Datatypes and protocols - update

2009-12-11 Thread ataggart


On Dec 11, 4:14 pm, Jason Wolfe jawo...@berkeley.edu wrote:
 I've been trying out the new branch, and on the whole I like it a lot.
  I know it'll take some time to learn how do things properly the new
 way, and I've figured out how to do most of the things I want to do
 thus far.  Thanks, Rich!

 One thing I haven't figured out how to do cleanly without inheritance
 is to specify properties of objects in a hierarchical domain in a
 clean, efficient way.  I'm sure I haven't fully wrapped my head around
 the new abstractions, so I'd love to hear about a clean way to solve
 this problem.

 A very simple example is: I have a protocol A, and sub-protocols
 A1 and A2.  Every A is either an A1 or A2, but not both (and this
 split is closed, as far as I'm concerned).  Sometimes I want to deal
 with instances of A1 and A2 together, and so I put the methods shared
 between all As in protocol A.  But, at some point I need to
 separate out the A1s from the A2s.  To do this, it seems like I
 have at least three options:

 1.  Add an is-A1 method to Protocol A.  The problem with this option
 is that every type that derives from A1 needs to manually write out
 this method returning true, and vice-versa for implementers of A2.
 Users could eliminate this by extending their types with a mixin map
 to A, rather than implementing it directly in the deftype.  But, this
 sacrifices readability (IMO) as well as efficiency.

 2.  use (satisfies? A1 x) to determine if x satisfies A1.  The main
 problem with this, at least currently, is that satisfies? seems to be
 really slow in the negative case.  I profiled my (non-trivial) program
 and half the runtime was going to reflection in satisfies?  Moreover,
 this solution is not as general.

 3.  Use a multimethod.  This would work generally and be reasonably
 efficient, but I feel like I'd be cluttering up my interface by mixing
 up protocols and multimethods.  On the other hand, I guess
 multimethods are the main (only?) hierarchical construct built into
 Clojure, so maybe this is what's intended.

 So, which do people feel is preferred?  Or have I missed a better
 option?

 Thanks!
 Jason

If I understand Rich's reasoning, what you want runs antithetical to
the protocols design, namely it being explicitly non-hierarchical.

As such, you'd instead have 3 composable protocols, A, B, and C (where
B and C would correspond to the functions of A1 and A2, respectively):

(defprotocol A (a [x]))
(defprotocol B (b [x]))
(defprotocol C (c [x]))

And then the type would reify the appropriate protocols:

(deftype A1 [] A B
  (a [] (println in A1.a))
  (b [] (println in A1.b)))

(deftype A2 [] A C
  (a [] (println in A2.a))
  (c [] (println in A2.c)))


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


Re: Datatypes and protocols - update

2009-12-11 Thread ataggart


On Dec 11, 11:44 pm, ataggart alex.tagg...@gmail.com wrote:
 On Dec 11, 4:14 pm, Jason Wolfe jawo...@berkeley.edu wrote:





  I've been trying out the new branch, and on the whole I like it a lot.
   I know it'll take some time to learn how do things properly the new
  way, and I've figured out how to do most of the things I want to do
  thus far.  Thanks, Rich!

  One thing I haven't figured out how to do cleanly without inheritance
  is to specify properties of objects in a hierarchical domain in a
  clean, efficient way.  I'm sure I haven't fully wrapped my head around
  the new abstractions, so I'd love to hear about a clean way to solve
  this problem.

  A very simple example is: I have a protocol A, and sub-protocols
  A1 and A2.  Every A is either an A1 or A2, but not both (and this
  split is closed, as far as I'm concerned).  Sometimes I want to deal
  with instances of A1 and A2 together, and so I put the methods shared
  between all As in protocol A.  But, at some point I need to
  separate out the A1s from the A2s.  To do this, it seems like I
  have at least three options:

  1.  Add an is-A1 method to Protocol A.  The problem with this option
  is that every type that derives from A1 needs to manually write out
  this method returning true, and vice-versa for implementers of A2.
  Users could eliminate this by extending their types with a mixin map
  to A, rather than implementing it directly in the deftype.  But, this
  sacrifices readability (IMO) as well as efficiency.

  2.  use (satisfies? A1 x) to determine if x satisfies A1.  The main
  problem with this, at least currently, is that satisfies? seems to be
  really slow in the negative case.  I profiled my (non-trivial) program
  and half the runtime was going to reflection in satisfies?  Moreover,
  this solution is not as general.

  3.  Use a multimethod.  This would work generally and be reasonably
  efficient, but I feel like I'd be cluttering up my interface by mixing
  up protocols and multimethods.  On the other hand, I guess
  multimethods are the main (only?) hierarchical construct built into
  Clojure, so maybe this is what's intended.

  So, which do people feel is preferred?  Or have I missed a better
  option?

  Thanks!
  Jason

 If I understand Rich's reasoning, what you want runs antithetical to
 the protocols design, namely it being explicitly non-hierarchical.

 As such, you'd instead have 3 composable protocols, A, B, and C (where
 B and C would correspond to the functions of A1 and A2, respectively):

 (defprotocol A (a [x]))
 (defprotocol B (b [x]))
 (defprotocol C (c [x]))

 And then the type would reify the appropriate protocols:

 (deftype A1 [] A B
   (a [] (println in A1.a))
   (b [] (println in A1.b)))

 (deftype A2 [] A C
   (a [] (println in A2.a))
   (c [] (println in A2.c)))


I should also note that isa? can be used for differentiation:

user= (def my-a (A1))
#'user/my-a
user= (isa? (type my-a) ::A1)
true
user= (isa? (type my-a) ::A2)
false

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


Re: Datatypes and protocols - update

2009-12-09 Thread Hugo Duncan
On Mon, 07 Dec 2009 12:07:12 -0500, Laurent PETIT  
laurent.pe...@gmail.com wrote:

 2009/12/7 Hugo Duncan hugodun...@users.sourceforge.net

 On Mon, 07 Dec 2009 06:53:38 -0500, Rich Hickey richhic...@gmail.com
 wrote:

  Yes, methods are not really functions. Thinking about them as closures
  over the object is a good way to go - you can see that analogy in play
  when you consider recur, which works with these methods, but could not
  rebind 'this'. The recur case sealed the deal in the decision not to
  include 'this' in the argument lists.

 I had a quick play with protocols, and the biggest problem I had getting
 started was realising that the signature of a method definition in
 defprotocol was different to the signature required to implement the  
 same
 method in deftype.  FWIW, I found it very non-intuitive.

 And now that you've got it, do you still feel this  non-intuitive.
 Because I had the same feeling first: I thought I would never rembember  
 how things work and why put 'this-like args there, and not there ...
 But now that everything clicked in place, I feel the last status of  
 what Rich achieved to do the most natural and intuitive.


I'll no doubt get used to it :-)  A couple of things that would have  
helped me get it:

 From the deftype doc:

  Thus methods for protocols will take one fewer arguments than do the  
protocol functions.

would (at least for me) be clearer as:

  Thus methods for protocols are implemented with one fewer argument than  
in the protocol function definitions.


The example of a deftype protocol implementation that is in the  
defprotocol doc string could be repeated in the deftype doc string.


 Basically, what helped me was along the lines of what Konrad said :
  * defprotocol and extend are purely functional : so you have to  
 specify
 every argument, including the object the functions acts upon.
  * deftype with embedded protocol definition for the type, or reify, in  
 the
 contrary, do not define pure functions. They define methods. You cannot  
 get
 them as values and pass them around like higher-order functions, for
 example. And you must know this fact, it cannot be an implementation  
 detail.
 So, since you know this fact, you remember that you're in a method
 definition (in the general sense of object oriented languages : method  
 of a
 class) and, as you do with e.g. java, C#, ... , when definining methods,  
 you
 do not add the target of the method as an implicit argument.

 The big advantage I see to this is that once you get it, you don't have
 anymore to remember where 'this is explicit and where it's implicit: it's
 intuitive.
 The other big advantage is that the use of recur inside these
 functions/methods bodies continue to match exactly the signature of the
 function/method (otherwise you would have had to remember that, e.g. in
 methods defined via deftype, you must place an explicit this argument  
 in
 the method arg list, but not place it in the recur calls ... :-( )

That explanation certainly helps describe and clarify the reasons for the  
difference. I still find it counter-intuitive that the definition follows  
the syntax of the functional world, and the implementation that of an  
object orientated world.  However, I can't think of any suggestion to  
resolve this, and as you say it does reflect the reality of the situation,  
so I'll get used to it :-)

--
Hugo Duncan

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


Re: Datatypes and protocols - update

2009-12-07 Thread Konrad Hinsen
On 01.12.2009, at 02:42, Rich Hickey wrote:

 An updated version of the code for datatypes[1] and protocols[2] is
 now available in the 'new' branch[3].

This weekend I finally got around to converting all my deftype-and- 
defprotocol-using code to the current Clojure new branch. It is now  
more compact and more readable, and the few parts where performance  
matters are faster. A big step forward!

 Small changes include:

 - No more use of . in reify/deftype method names
 - No more implicit this in reify/deftype

That's the only feature that I regret a bit. It looks weird in a  
functional language to have functions (or something that is very  
similar) that have an implicit argument named outside its definition  
(in the :as option). Of course, one can think of it as similar to a  
closure over the object, but it still looks a bit weird to me.

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


Re: Datatypes and protocols - update

2009-12-07 Thread Rich Hickey
On Mon, Dec 7, 2009 at 3:11 AM, Konrad Hinsen
konrad.hin...@fastmail.net wrote:
 On 01.12.2009, at 02:42, Rich Hickey wrote:

 An updated version of the code for datatypes[1] and protocols[2] is
 now available in the 'new' branch[3].

 This weekend I finally got around to converting all my deftype-and-
 defprotocol-using code to the current Clojure new branch. It is now
 more compact and more readable, and the few parts where performance
 matters are faster. A big step forward!

 Small changes include:

 - No more use of . in reify/deftype method names
 - No more implicit this in reify/deftype

 That's the only feature that I regret a bit. It looks weird in a
 functional language to have functions (or something that is very
 similar) that have an implicit argument named outside its definition
 (in the :as option). Of course, one can think of it as similar to a
 closure over the object, but it still looks a bit weird to me.


Yes, methods are not really functions. Thinking about them as closures
over the object is a good way to go - you can see that analogy in play
when you consider recur, which works with these methods, but could not
rebind 'this'. The recur case sealed the deal in the decision not to
include 'this' in the argument lists.

Rich

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


Re: Datatypes and protocols - update

2009-12-07 Thread Hugo Duncan
On Mon, 07 Dec 2009 06:53:38 -0500, Rich Hickey richhic...@gmail.com  
wrote:

 Yes, methods are not really functions. Thinking about them as closures
 over the object is a good way to go - you can see that analogy in play
 when you consider recur, which works with these methods, but could not
 rebind 'this'. The recur case sealed the deal in the decision not to
 include 'this' in the argument lists.

I had a quick play with protocols, and the biggest problem I had getting  
started was realising that the signature of a method definition in  
defprotocol was different to the signature required to implement the same  
method in deftype.  FWIW, I found it very non-intuitive.

--
Hugo Duncan

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


Re: Datatypes and protocols - update

2009-12-07 Thread Laurent PETIT
2009/12/7 Hugo Duncan hugodun...@users.sourceforge.net

 On Mon, 07 Dec 2009 06:53:38 -0500, Rich Hickey richhic...@gmail.com
 wrote:

  Yes, methods are not really functions. Thinking about them as closures
  over the object is a good way to go - you can see that analogy in play
  when you consider recur, which works with these methods, but could not
  rebind 'this'. The recur case sealed the deal in the decision not to
  include 'this' in the argument lists.

 I had a quick play with protocols, and the biggest problem I had getting
 started was realising that the signature of a method definition in
 defprotocol was different to the signature required to implement the same
 method in deftype.  FWIW, I found it very non-intuitive.


Hello,

And now that you've got it, do you still feel this  non-intuitive.
Because I had the same feeling first: I thought I would never rembember how
things work and why put 'this-like args there, and not there ...
But now that everything clicked in place, I feel the last status of what
Rich achieved to do the most natural and intuitive.

Basically, what helped me was along the lines of what Konrad said :
 * defprotocol and extend are purely functional : so you have to specify
every argument, including the object the functions acts upon.
 * deftype with embedded protocol definition for the type, or reify, in the
contrary, do not define pure functions. They define methods. You cannot get
them as values and pass them around like higher-order functions, for
example. And you must know this fact, it cannot be an implementation detail.
So, since you know this fact, you remember that you're in a method
definition (in the general sense of object oriented languages : method of a
class) and, as you do with e.g. java, C#, ... , when definining methods, you
do not add the target of the method as an implicit argument.

The big advantage I see to this is that once you get it, you don't have
anymore to remember where 'this is explicit and where it's implicit: it's
intuitive.
The other big advantage is that the use of recur inside these
functions/methods bodies continue to match exactly the signature of the
function/method (otherwise you would have had to remember that, e.g. in
methods defined via deftype, you must place an explicit this argument in
the method arg list, but not place it in the recur calls ... :-( )

HTH,

-- 
laurent

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

Re: Datatypes and protocols - update

2009-12-07 Thread ataggart


On Dec 7, 9:07 am, Laurent PETIT laurent.pe...@gmail.com wrote:
 2009/12/7 Hugo Duncan hugodun...@users.sourceforge.net

  On Mon, 07 Dec 2009 06:53:38 -0500, Rich Hickey richhic...@gmail.com
  wrote:

   Yes, methods are not really functions. Thinking about them as closures
   over the object is a good way to go - you can see that analogy in play
   when you consider recur, which works with these methods, but could not
   rebind 'this'. The recur case sealed the deal in the decision not to
   include 'this' in the argument lists.

  I had a quick play with protocols, and the biggest problem I had getting
  started was realising that the signature of a method definition in
  defprotocol was different to the signature required to implement the same
  method in deftype.  FWIW, I found it very non-intuitive.

 Hello,

 And now that you've got it, do you still feel this  non-intuitive.
 Because I had the same feeling first: I thought I would never rembember how
 things work and why put 'this-like args there, and not there ...
 But now that everything clicked in place, I feel the last status of what
 Rich achieved to do the most natural and intuitive.

 Basically, what helped me was along the lines of what Konrad said :
  * defprotocol and extend are purely functional : so you have to specify
 every argument, including the object the functions acts upon.
  * deftype with embedded protocol definition for the type, or reify, in the
 contrary, do not define pure functions. They define methods. You cannot get
 them as values and pass them around like higher-order functions, for
 example. And you must know this fact, it cannot be an implementation detail.
 So, since you know this fact, you remember that you're in a method
 definition (in the general sense of object oriented languages : method of a
 class) and, as you do with e.g. java, C#, ... , when definining methods, you
 do not add the target of the method as an implicit argument.

 The big advantage I see to this is that once you get it, you don't have
 anymore to remember where 'this is explicit and where it's implicit: it's
 intuitive.
 The other big advantage is that the use of recur inside these
 functions/methods bodies continue to match exactly the signature of the
 function/method (otherwise you would have had to remember that, e.g. in
 methods defined via deftype, you must place an explicit this argument in
 the method arg list, but not place it in the recur calls ... :-( )

 HTH,

 --
 laurent

That was my experience as well.  It started off as a gotcha (since I
was copy/pasting the protocol definitions over to the deftype), but
then after playing for a bit it wasn't a big deal.  In all my usages
so far I haven't needed to reference 'this'.

The one area I am running into issues is with being able to provide a
default implementation, or extending types such that I can override a
method.

For example, I have:

(defprotocol http-resource
  (GET [res req resp])
  (POST[res req resp])
  (PUT [res req resp])
  (DELETE  [res req resp])
  (HEAD[res req resp])
  (OPTIONS [res req resp])
  (TRACE   [res req resp]))

But I considering the usage, most of those need not be implemented per-
type, and could all be defaulted to something like:

(deftype resource [] http-resource
  (GET [req resp] (send-status! resp 405))
  (POST [req resp] (send-status! resp 405))
  (PUT [req resp] (send-status! resp 405))
  (DELETE [req resp] (send-status! resp 405))
  (HEAD [req resp] (send-status! resp 405))
  (OPTIONS [req resp] (send-status! resp 405))
  (TRACE [req resp] (send-status! resp 405)))

Alas I can't simply extend-type since that modifies the type, instead
of creating a new, modified type.  And even then, methods in the
extension map don't get called if the method exists directly on the
type, i.e., no overriding.

I'm sure my problem is simply vestigial OO thinking, but I'm not sure
how to achieve the simplicity I want.  The one route I tried that sort-
of works is making a macro to create the types, rather than extending
some extant implementation.  The downside is I have to see which
methods I'm being given and only provide defaults for the method
names/arities that aren't.

It might be sufficient if there was some facility for cloning another
type and overriding certain methods, though I can foresee problems
dealing with managing the field definitions between the original and
the altered clone.

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


Re: Datatypes and protocols - update

2009-12-07 Thread ataggart


On Dec 7, 11:23 am, ataggart alex.tagg...@gmail.com wrote:
 On Dec 7, 9:07 am, Laurent PETIT laurent.pe...@gmail.com wrote:





  2009/12/7 Hugo Duncan hugodun...@users.sourceforge.net

   On Mon, 07 Dec 2009 06:53:38 -0500, Rich Hickey richhic...@gmail.com
   wrote:

Yes, methods are not really functions. Thinking about them as closures
over the object is a good way to go - you can see that analogy in play
when you consider recur, which works with these methods, but could not
rebind 'this'. The recur case sealed the deal in the decision not to
include 'this' in the argument lists.

   I had a quick play with protocols, and the biggest problem I had getting
   started was realising that the signature of a method definition in
   defprotocol was different to the signature required to implement the same
   method in deftype.  FWIW, I found it very non-intuitive.

  Hello,

  And now that you've got it, do you still feel this  non-intuitive.
  Because I had the same feeling first: I thought I would never rembember how
  things work and why put 'this-like args there, and not there ...
  But now that everything clicked in place, I feel the last status of what
  Rich achieved to do the most natural and intuitive.

  Basically, what helped me was along the lines of what Konrad said :
   * defprotocol and extend are purely functional : so you have to specify
  every argument, including the object the functions acts upon.
   * deftype with embedded protocol definition for the type, or reify, in the
  contrary, do not define pure functions. They define methods. You cannot get
  them as values and pass them around like higher-order functions, for
  example. And you must know this fact, it cannot be an implementation detail.
  So, since you know this fact, you remember that you're in a method
  definition (in the general sense of object oriented languages : method of a
  class) and, as you do with e.g. java, C#, ... , when definining methods, you
  do not add the target of the method as an implicit argument.

  The big advantage I see to this is that once you get it, you don't have
  anymore to remember where 'this is explicit and where it's implicit: it's
  intuitive.
  The other big advantage is that the use of recur inside these
  functions/methods bodies continue to match exactly the signature of the
  function/method (otherwise you would have had to remember that, e.g. in
  methods defined via deftype, you must place an explicit this argument in
  the method arg list, but not place it in the recur calls ... :-( )

  HTH,

  --
  laurent

 That was my experience as well.  It started off as a gotcha (since I
 was copy/pasting the protocol definitions over to the deftype), but
 then after playing for a bit it wasn't a big deal.  In all my usages
 so far I haven't needed to reference 'this'.

 The one area I am running into issues is with being able to provide a
 default implementation, or extending types such that I can override a
 method.

 For example, I have:

 (defprotocol http-resource
   (GET     [res req resp])
   (POST    [res req resp])
   (PUT     [res req resp])
   (DELETE  [res req resp])
   (HEAD    [res req resp])
   (OPTIONS [res req resp])
   (TRACE   [res req resp]))

 But I considering the usage, most of those need not be implemented per-
 type, and could all be defaulted to something like:

 (deftype resource [] http-resource
   (GET [req resp] (send-status! resp 405))
   (POST [req resp] (send-status! resp 405))
   (PUT [req resp] (send-status! resp 405))
   (DELETE [req resp] (send-status! resp 405))
   (HEAD [req resp] (send-status! resp 405))
   (OPTIONS [req resp] (send-status! resp 405))
   (TRACE [req resp] (send-status! resp 405)))

 Alas I can't simply extend-type since that modifies the type, instead
 of creating a new, modified type.  And even then, methods in the
 extension map don't get called if the method exists directly on the
 type, i.e., no overriding.

 I'm sure my problem is simply vestigial OO thinking, but I'm not sure
 how to achieve the simplicity I want.  The one route I tried that sort-
 of works is making a macro to create the types, rather than extending
 some extant implementation.  The downside is I have to see which
 methods I'm being given and only provide defaults for the method
 names/arities that aren't.

 It might be sufficient if there was some facility for cloning another
 type and overriding certain methods, though I can foresee problems
 dealing with managing the field definitions between the original and
 the altered clone.

One idea:  (defdefault name options* specs*)

Similar to deftype except without any field definitions (a simplifying
restriction), thus can only operate on their args. With that I could
do:

(defdefault base-resource http-resource
  (GET [req resp] (send-status! resp 405))
  (POST [req resp] (send-status! resp 405))
  (PUT [req resp] (send-status! resp 405))
  (DELETE [req resp] (send-status! resp 405))
  (HEAD 

Re: Datatypes and protocols - update

2009-12-07 Thread DTH
On Dec 1, 9:56 pm, Rich Hickey richhic...@gmail.com wrote:

 There are 2 ways to make a deftype reach a protocol. First, you can
 implement the protocol directly in the deftype/reify, supplying the
 protocol where you do interfaces, and the methods of the protocol as
 methods of the type. The type will be made to implement the protocol's
 interface. The second way, for types you don't control, is to use
 extend-type/class/protocol, which will create method maps and register
 them with the protocol.


For the record; this means that you cannot implement two protocols
directly in deftype or reify if those protocols have fns with the same
names and signatures.  You can, however, implement one protocol
directly, and then extend it to the other, as with the following,
rather silly, example:

user (ns foo)
nil
foo (defprotocol Foo (write [this]))
Foo
foo (ns bar)
nil
bar (defprotocol Bar (write [this badger]))
Bar
bar (ns me)
nil
me (defprotocol Me (write [this] [this badger]))
Me
me (ns user)
nil
user (deftype FooMe [a b c d] foo/Foo (write [] a) bar/Bar (write
[badger] b))
#'user/FooMe
user (def fm (FooMe :foo :bar :me1 :me2))
#'user/fm
user (foo/write fm)
:foo
user (bar/write fm 1)
:bar
user (extend-type ::FooMe me/Me (write ([this] (:c this)) ([this
badger] (:d this
nil
user (me/write fm)
:me1
user (me/write fm 1)
:me2
user (foo/write fm)
:foo
user (bar/write fm 1)
:bar
user

which was unexpectedly sweet, yet totally consistent with your
explanation of how it works.  Rich, you _are_ the Badgers Nadgers.

-Dave

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


Re: Datatypes and protocols - update

2009-12-02 Thread Rich Hickey


On Dec 2, 12:29 am, Krukow karl.kru...@gmail.com wrote:
 On Dec 1, 10:56 pm, Rich Hickey richhic...@gmail.com wrote:
 [snip]

  There are 2 ways to make a deftype reach a protocol. First, you can
  implement the protocol directly in the deftype/reify, supplying the
  protocol where you do interfaces, and the methods of the protocol as
  methods of the type. The type will be made to implement the protocol's
  interface.

 OK. With extend you can use maps and merge to share implementations.
 Does directly implementing the protocol in deftype allow also for
 abstract super-classes, i.e., sharing protocol-function
 implementations across types?


Right now you would just call an implementation helper inside your
method. I'm still considering if more support is needed, and what form
it might take.

  Different methods of implementing the protocol have different
  performance. Implementing directly in deftype or reify is as fast as a
  direct interface call. Using extend-* is not quite as fast, but still
  fast. Both methods have direct support in callsites, so a call to a
  protocol fn has support both for using the interface and caching
  lookup results.

 Great. So the preferred way for data-types in my program is to
 implement the protocol directly, whereas for other types I can still
 use my protocol with extend.

 Just to confirm my understanding: Is it correct to say, for example,
 that clojure.lang.Seqable will be a protocol implemented directly in
 the Clojure data types, whereas it would reach the Java lang types
 using extend?


Yes. extend is the key to removing the current (closed) multiway
conditionals in, e.g., RT.seq/seqFrom, and is much faster as well.

 In Clojure-in-Java interfaces like IPersistentCollection extend
 Seqable:  would these be unrelated type-wise as protocols?


Yes. One of the reasons we use interface inheritance in a language
like Java is that, short of generifying everything, we have no way to
say:

foo(Counted+Sorted+Seqable+Collection coll){...}

We only get to specify one type, and any other interfaces it doesn't
imply require casts. So we use hierarchy to reduce the required
casting, but it has a cost in flexibility - i.e. you can't make a non-
Seqable collection, if that made sense.

In a dynamic language with protocols there is no reason to do it this
way. You don't need to have a single type imply multiple types via
hierarchy, and you don't need to declare anything. So each protocol is
a la carte, and a piece of code that requires the collection support
Counted, Sorted, Seqable and Collection protocols will simply use
those protocols, and work with anything that supports them. A type can
support any and just the protocols that make sense for it, without
bringing in others as a side effect of hierarchy.

Protocols are very much about polymorphism without hierarchy.

Rich

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


Re: Datatypes and protocols - update

2009-12-02 Thread Krukow
Thanks for sharing the insights.

/Karl

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


Re: Datatypes and protocols - update

2009-12-01 Thread Krukow


On Dec 1, 2:42 am, Rich Hickey richhic...@gmail.com wrote:
 I have done a lot of work on performance, and refined the design. The
 big news is that you can now directly implement a protocol inside a
 deftype, and you can also reify protocols. This cements protocols as
 the superior way to model the things for which they are suitable,
 since they can match the performance of interfaces without their
 limitations.

First of all, I think this is a wonderful addition to the language.
I've tried what is in the new branch on a small but real example,
and I am quite happy with it: So thanks!

Could you go into more detail about how protocols and datatypes are
actually implemented, and the performance improvements you've recently
made? (probably I'm not the only one interested :-)

What is generated when I define a protocol, datatype and extend the
type to the protocol?

As I understand the performance of calling a protocol function matches
the performance of calling an interface method in Java. How is it
possible to achieve this in combination with the dynamic extensibility
of extend?

/Karl

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


Re: Datatypes and protocols - update

2009-12-01 Thread Krukow


On Dec 1, 10:56 pm, Rich Hickey richhic...@gmail.com wrote:
[snip]
 There are 2 ways to make a deftype reach a protocol. First, you can
 implement the protocol directly in the deftype/reify, supplying the
 protocol where you do interfaces, and the methods of the protocol as
 methods of the type. The type will be made to implement the protocol's
 interface.

OK. With extend you can use maps and merge to share implementations.
Does directly implementing the protocol in deftype allow also for
abstract super-classes, i.e., sharing protocol-function
implementations across types?

[snip]

 Different methods of implementing the protocol have different
 performance. Implementing directly in deftype or reify is as fast as a
 direct interface call. Using extend-* is not quite as fast, but still
 fast. Both methods have direct support in callsites, so a call to a
 protocol fn has support both for using the interface and caching
 lookup results.

Great. So the preferred way for data-types in my program is to
implement the protocol directly, whereas for other types I can still
use my protocol with extend.

Just to confirm my understanding: Is it correct to say, for example,
that clojure.lang.Seqable will be a protocol implemented directly in
the Clojure data types, whereas it would reach the Java lang types
using extend?

In Clojure-in-Java interfaces like IPersistentCollection extend
Seqable:  would these be unrelated type-wise as protocols?

 The most important thing is, writing to protocols gives you a dynamic,
 open, extensible system not tied to derivation, and is fast, so a
 great way to architect the polymorphic part of your designs (when
 single-dispatch is appropriate).

 Rich

I think these constructs will have great impact on how we will
structure our Clojure programs.

/Karl

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