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 [req resp] (send-status! resp 405)) (OPTIONS [req resp] (send-status! resp 405)) (TRACE [req resp] (send-status! resp 405))) Then modify deftype to include "defaults" in the spec* set: (deftype user-resource [user-id] base-resource (GET [req resp] (if-let [u (find-user user-id)] (send-entity! resp 200 u) (send-status! resp 404)))) -- 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