Re: Possible Solution for Left-Right Precedence and More when using Multimethods? (was re: oo)

2009-04-01 Thread Konrad Hinsen

On 31.03.2009, at 21:48, Konrad Hinsen wrote:

 On 31.03.2009, at 18:50, Mark Engelberg wrote:

 On Tue, Mar 31, 2009 at 9:45 AM, Konrad Hinsen
 konrad.hin...@laposte.net wrote:
 I think this should be sufficient to cover all cases you mentioned,
 but of course it needs to be tried in practice.

 I think your idea of specifying a sequence of items to try in the
 dispatching function, at the point of definition for the multimethod,
 violates the principle of allowing library consumers to easily extend
 this on their own without having to contact the library designer.

 Maybe I wasn't clear about one point: the return sequence is not the
 sequence of concrete implementations to try (the dispatch function
 wouldn't even necessarily know them), but a sequence of starting
 points in the hierarchy from which the standard lookup would start.

One night's sleep later, I see that this is not sufficient. The  
dispatch function is defined before the multimethod, and thus  
potentially inside some library, which cannot know all the needs of  
its potential clients. So yes, there has to be a way to specify  
preferences later on.

One possibility would be to make the dispatch function itself a  
multimethod, or have it call one, but I am not sure that's a good  
solution.

Konrad.


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Possible Solution for Left-Right Precedence and More when using Multimethods? (was re: oo)

2009-04-01 Thread Konrad Hinsen

On Apr 1, 2009, at 14:47, Rich Hickey wrote:

 I've added get-method (SVN 1338).

Great, thanks!

 Note how you can name methods for diagnostic purposes. This doesn't
 introduce names into the namespace, just puts a name on the fn object.

It's also useful for recursive calls, if you are sure you want to  
stay inside the method and not do a new dispatch.

Konrad.


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Possible Solution for Left-Right Precedence and More when using Multimethods? (was re: oo)

2009-04-01 Thread David Nolen
Very cool.

On Wed, Apr 1, 2009 at 8:47 AM, Rich Hickey richhic...@gmail.com wrote:


 I've added get-method (SVN 1338).

 (derive ::Circle ::Shape)
 (derive ::Rect ::Shape)

 (defmulti area :Shape)

 ;note - you can name methods
 (defmethod area ::Shape area-shape [x] nil)

 (get-method area ::Rect)
 #user$area_shape__43 user$area_shape_...@674a93a6

 (defmethod area ::Rect area-rect [r]
(* (:wd r) (:ht r)))
 (defmethod area ::Circle area-circ [c]
(* (. Math PI) (* (:radius c) (:radius c

 (get-method area ::Rect)
 #user$area_rect__18 user$area_rect_...@4e42751f

 (get-method area ::Circ) ;not there
 nil

 (get-method area ::Circle)
 #user$area_circ__20 user$area_circ_...@74da0c91

 ;if you don't think squares are rectangles, you can still reuse
 implementation (silly example)
 (defmethod area ::Square area-square [sqr]
  ((get-method area ::Rect) {:wd (:dim sqr) :ht (:dim sqr)}))

 (area {:Shape ::Square :dim 20})
 400

 Note how you can name methods for diagnostic purposes. This doesn't
 introduce names into the namespace, just puts a name on the fn object.

 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
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: Possible Solution for Left-Right Precedence and More when using Multimethods? (was re: oo)

2009-03-31 Thread Konrad Hinsen

On Mar 31, 2009, at 16:32, Rich Hickey wrote:

 Here are some problems/limitations of existing OO/GF systems that I
 don't intend to repeat:
...

I agree that these are not desirable features. I have had to work  
around some of them many times in the past. Traditional OO combines  
aspects that should better be handled separately.

 Here are the areas I'm looking to improve:

 - There's no easy way to talk about the method you would get if you
 were dispatch value X. Note that this is not the same as call-next-
 method, which reintroduces global ordering requirements, but allows
 for easy explicit reuse of already-defined methods.

That would be VERY nice to have. More than once I ended up writing a  
private function that I then called from several methods in the same  
multimethod, to avoid code duplication.

 - Currently, a preference doesn't encompass the path through the
 preferred value to its ancestors, but could.

 - If you have a set of common preferences, there's no easy way to
 create them in advance and share them among methods. There are issues
 here related to ensuring preference consistency and caching.

At the moment, a multimethod takes two dispatch-oriented parameters:  
a hierarchy and a dispatch function that returns a single item from  
the hierarchy.

How about generalizing the dispatch function in two ways:
- it can return a sequence of items that will be tried in order
- it can access the hierarchy

Accessing the hierarchy is a minor point since this is already  
possible (write a dispatch function that uses parents, ancestors,  
etc.; for a hierarchy other than the global one, make the dispatch  
function a closure that refers to the hierarchy). Maybe it could be  
made more convenient.

Returning a sequence should be sufficient to let the dispatch  
function handle any kind of preference. prefer-method could thus go  
away. Instead, there would be a set of utility functions to  
facilitate writing dispatch functions for common cases. A single  
dispatch function could be used for any number of multimethods.

I think this should be sufficient to cover all cases you mentioned,  
but of course it needs to be tried in practice.

Konrad.


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Possible Solution for Left-Right Precedence and More when using Multimethods? (was re: oo)

2009-03-31 Thread Mark Engelberg

On Tue, Mar 31, 2009 at 9:45 AM, Konrad Hinsen
konrad.hin...@laposte.net wrote:
 I think this should be sufficient to cover all cases you mentioned,
 but of course it needs to be tried in practice.

I think your idea of specifying a sequence of items to try in the
dispatching function, at the point of definition for the multimethod,
violates the principle of allowing library consumers to easily extend
this on their own without having to contact the library designer.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Possible Solution for Left-Right Precedence and More when using Multimethods? (was re: oo)

2009-03-31 Thread mikel



On Mar 31, 11:45 am, Konrad Hinsen konrad.hin...@laposte.net wrote:
 On Mar 31, 2009, at 16:32, Rich Hickey wrote:

  Here are some problems/limitations of existing OO/GF systems that I
  don't intend to repeat:

 ...

 I agree that these are not desirable features. I have had to work
 around some of them many times in the past. Traditional OO combines
 aspects that should better be handled separately.

  Here are the areas I'm looking to improve:

  - There's no easy way to talk about the method you would get if you
  were dispatch value X. Note that this is not the same as call-next-
  method, which reintroduces global ordering requirements, but allows
  for easy explicit reuse of already-defined methods.

 That would be VERY nice to have. More than once I ended up writing a
 private function that I then called from several methods in the same
 multimethod, to avoid code duplication.

  - Currently, a preference doesn't encompass the path through the
  preferred value to its ancestors, but could.

  - If you have a set of common preferences, there's no easy way to
  create them in advance and share them among methods. There are issues
  here related to ensuring preference consistency and caching.

 At the moment, a multimethod takes two dispatch-oriented parameters:
 a hierarchy and a dispatch function that returns a single item from
 the hierarchy.

 How about generalizing the dispatch function in two ways:
 - it can return a sequence of items that will be tried in order
 - it can access the hierarchy

 Accessing the hierarchy is a minor point since this is already
 possible (write a dispatch function that uses parents, ancestors,
 etc.; for a hierarchy other than the global one, make the dispatch
 function a closure that refers to the hierarchy). Maybe it could be
 made more convenient.

 Returning a sequence should be sufficient to let the dispatch
 function handle any kind of preference. prefer-method could thus go
 away. Instead, there would be a set of utility functions to
 facilitate writing dispatch functions for common cases. A single
 dispatch function could be used for any number of multimethods.

 I think this should be sufficient to cover all cases you mentioned,
 but of course it needs to be tried in practice.

I think the orthogonal elements of multifunction dispatch are type
computations, traversals, and matchers (and the functions being
dispatched to, of course).

Dispatch function is maybe an unfortunate name; those functions
aren't dispatchers, they're type-returning functions--functions that
compute selector values.

If you have a way to compute selector values from inputs and a way to
specify the order in which matches against them will be tried, and a
way to specify how matching is to be performed, then you have the
tools to specify any dispatching algorithm you like. Clojure presently
provides some tools for this: dispatch functions are type-returning
functions; hierarchies are graphs of selector values; isa? and prefer-
method are a control language for describing traversal, and isa? is
also a matching function.

But these are restricted versions: dispatch functions are meant to
return a restricted range of values--symbols, keywords, classes, and
certain collections of those values; multifunction dispatch supports
hierarchies, but not other kinds of graphs; isa? and prefer-method are
the only vocabulary we have for describing traversal, and isa? is the
only matcher (almost the first thing I wanted to do when using
MultiFns was replace isa? with my own matching function).

The tools can be more expressive. Multifunction dispatch can be built
on user-specified traversals of user-designed graphs of selector
values, computed by user-supplied type-returning functions, and using
user-specified matchers. The traversal order, the range of selector
values, the language for describing traversal, and the matching
procedure can all be more first-class and more orthogonal. Special
cases can be provided for specific combinations known to be especially
useful or efficient.

With a full set of tools for describing dispatch, any differences of
individual taste in function dispatching and type relationships
becomes moot, because the tools are there to implement whatever type
relationships and dispatching algorithm you want. Rich doesn't want to
enshrine a particular traversal order in Clojure; I want the power to
comprehensively specify traversal order in advance for certain uses;
very well, any traversal order (or no traversal order) may be defined,
as you like. He wants function dispatching and data definitions to be
separated and so do I; very well, we have the freedom to compute
whatever values we wish for use as types, and to arrange them in
whatever sorts of graphs we like. Everyone wants things to be
efficient, and likely people also want common use cases to be provided
ready-to-wear; very well, those cases can be provided as built-ins or
elements of libraries, with special treatment in 

Re: Possible Solution for Left-Right Precedence and More when using Multimethods? (was re: oo)

2009-03-31 Thread Rich Hickey



On Mar 31, 2:18 pm, mikel mev...@mac.com wrote:
 On Mar 31, 11:45 am, Konrad Hinsen konrad.hin...@laposte.net wrote:



  On Mar 31, 2009, at 16:32, Rich Hickey wrote:

   Here are some problems/limitations of existing OO/GF systems that I
   don't intend to repeat:

  ...

  I agree that these are not desirable features. I have had to work
  around some of them many times in the past. Traditional OO combines
  aspects that should better be handled separately.

   Here are the areas I'm looking to improve:

   - There's no easy way to talk about the method you would get if you
   were dispatch value X. Note that this is not the same as call-next-
   method, which reintroduces global ordering requirements, but allows
   for easy explicit reuse of already-defined methods.

  That would be VERY nice to have. More than once I ended up writing a
  private function that I then called from several methods in the same
  multimethod, to avoid code duplication.

   - Currently, a preference doesn't encompass the path through the
   preferred value to its ancestors, but could.

   - If you have a set of common preferences, there's no easy way to
   create them in advance and share them among methods. There are issues
   here related to ensuring preference consistency and caching.

  At the moment, a multimethod takes two dispatch-oriented parameters:
  a hierarchy and a dispatch function that returns a single item from
  the hierarchy.

  How about generalizing the dispatch function in two ways:
  - it can return a sequence of items that will be tried in order
  - it can access the hierarchy

  Accessing the hierarchy is a minor point since this is already
  possible (write a dispatch function that uses parents, ancestors,
  etc.; for a hierarchy other than the global one, make the dispatch
  function a closure that refers to the hierarchy). Maybe it could be
  made more convenient.

  Returning a sequence should be sufficient to let the dispatch
  function handle any kind of preference. prefer-method could thus go
  away. Instead, there would be a set of utility functions to
  facilitate writing dispatch functions for common cases. A single
  dispatch function could be used for any number of multimethods.

  I think this should be sufficient to cover all cases you mentioned,
  but of course it needs to be tried in practice.

 I think the orthogonal elements of multifunction dispatch are type
 computations, traversals, and matchers (and the functions being
 dispatched to, of course).


What about predicate, or rule based dispatch - why hardwire the notion
of types, traversal or matching?

 Dispatch function is maybe an unfortunate name; those functions
 aren't dispatchers, they're type-returning functions--functions that
 compute selector values.

 If you have a way to compute selector values from inputs and a way to
 specify the order in which matches against them will be tried, and a
 way to specify how matching is to be performed, then you have the
 tools to specify any dispatching algorithm you like. Clojure presently
 provides some tools for this: dispatch functions are type-returning
 functions; hierarchies are graphs of selector values; isa? and prefer-
 method are a control language for describing traversal, and isa? is
 also a matching function.

 But these are restricted versions: dispatch functions are meant to
 return a restricted range of values--symbols, keywords, classes, and
 certain collections of those values; multifunction dispatch supports
 hierarchies, but not other kinds of graphs; isa? and prefer-method are
 the only vocabulary we have for describing traversal, and isa? is the
 only matcher (almost the first thing I wanted to do when using
 MultiFns was replace isa? with my own matching function).

 The tools can be more expressive. Multifunction dispatch can be built
 on user-specified traversals of user-designed graphs of selector
 values, computed by user-supplied type-returning functions, and using
 user-specified matchers. The traversal order, the range of selector
 values, the language for describing traversal, and the matching
 procedure can all be more first-class and more orthogonal. Special
 cases can be provided for specific combinations known to be especially
 useful or efficient.

 With a full set of tools for describing dispatch, any differences of
 individual taste in function dispatching and type relationships
 becomes moot, because the tools are there to implement whatever type
 relationships and dispatching algorithm you want. Rich doesn't want to
 enshrine a particular traversal order in Clojure; I want the power to
 comprehensively specify traversal order in advance for certain uses;
 very well, any traversal order (or no traversal order) may be defined,
 as you like. He wants function dispatching and data definitions to be
 separated and so do I; very well, we have the freedom to compute
 whatever values we wish for use as types, and to arrange them in
 whatever sorts 

Re: Possible Solution for Left-Right Precedence and More when using Multimethods? (was re: oo)

2009-03-31 Thread Konrad Hinsen

On 31.03.2009, at 18:50, Mark Engelberg wrote:

 On Tue, Mar 31, 2009 at 9:45 AM, Konrad Hinsen
 konrad.hin...@laposte.net wrote:
 I think this should be sufficient to cover all cases you mentioned,
 but of course it needs to be tried in practice.

 I think your idea of specifying a sequence of items to try in the
 dispatching function, at the point of definition for the multimethod,
 violates the principle of allowing library consumers to easily extend
 this on their own without having to contact the library designer.

Maybe I wasn't clear about one point: the return sequence is not the  
sequence of concrete implementations to try (the dispatch function  
wouldn't even necessarily know them), but a sequence of starting  
points in the hierarchy from which the standard lookup would start.

Konrad.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Possible Solution for Left-Right Precedence and More when using Multimethods? (was re: oo)

2009-03-30 Thread mikel



On Mar 28, 6:30 pm, David Nolen dnolen.li...@gmail.com wrote:
 Having thought a little about multiple inheritance when implementing Spinoza
 I also ran into this problem. However at the time I wasn't hindered by
 multifn dispatch as much as the fact that parents cannot be ordered (because
 calling parents on a tag returns a set) as pointed out by Mark. I understand
 Rich's point that hierarchies probably shouldn't be directional, but for the
 sake of practicality why not allow the programmer to specify that a tag (or
 even the whole hierarchy) should in fact have its relationships be ordered?
 In general prefer-method seemed to me (I could be wrong) to be a last
 attempt solution- when there is just no other way to resolve an ambiguity,
 and this ambiguity is not of the hierarchy, but of multimethod dispatch. As
 pointed out by Konrad  Rich, you can work around the limitation of
 hierarchies right now with a lot of prefer-methods.  But as Mikel points
 out, with current state of prefer-method you have to hunt through code to
 find out where these prefers were made and for what reason and they assume
 that you've already written your methods (this for me is the deal breaker).

 In anycase my general feeling (in agreement with Mark) is that the problem
 isn't with multifns but rather with how hierarchies are constructed.

 So the achilles heel of hierarchies seems to be that when you call parents
 (and related fns) on a tag you get a set - it has no order.  For single
 inheritance hierarchies this is fine, but for multiple inheritance I think
 this becomes a problem a very fast. Working on Spinoza, I realized I would
 have to keep my own ordered list of parents in order to support left-right
 precedence, basically keeping an ordered copy of the whole hierarchy. Again
 prefer-method is only useful for fixing method-level ambiguities.  There's
 no general way to say, type A always precedes type B without writing quite a
 bit of explicit code (or hiding the problem away with macros).

 Here's something that might kick of a dicussion to a proper solution (I am
 sure there are some gaps in my logic), why not allow something like the
 following?

 ;; allow control of how tags get introduced into the hierarchy
 (def h (make-hierarchy :parents-fn fn1 :ancestors-fn fn2 :descendants-fn
 fn3))

 ;; add a new parent insertion fn to a hierarchy
 (add-parents-fn h fn4) ;; - returns a new hierarchy with the parents fn
 set, all parents sets are converted into vectors

 ;; add a new parent insertion fn to a hierarchy for a specific key, only the
 parents of ::my-tag are converted into a vector
 (add-parents-fn h fn4 ::my-tag)

 ;; a hierarchy fn might look something like the following
 (defn my-parents-fn [parents new-key]
    (conj parents new-key))

 If my thinking is correct this is pretty flexible. This doesn't break the
 meaning of hierarchy for any existing code.  It doesn't change the signature
 of multimethods.  Yet now a user can provide fns that sorts a hierarchy
 anyway they please, and it doesn't even have to be the entire hierarchy.
  This code will probably live in one spot where anyone could look to
 understand how the hierarchy is being constructed.  All high-level
 precedence ambiguities can now be resolved by looking at the hierarchy.
  prefer-method does only what it was intended to do- resolve method level
 ambiguity.

You can build a working generic functions implementation for any
domain that obeys a protocol consisting of four functions:

1. fn [v  [context]] - t

   A type-returning function that returns a usable type-value for any
   input in its intended domain.

2. fn [t1 t2  [context]] - Boolean

   A type-ordering function that returns true if t1 is to
   be considered more specific than t2. This function
   must yield values that permit a stable, monotonic
   sort of types in the domain.

3. fn [t  [context]] - s

   Where s is a sequence of type-values. A supertypes function that,
   given a type, returns a sequence of all types that are to be
   considered supertypes of it.

4. fn [inits  [context]] - t

   A type-creating function that returns new type-values that
   function (1) can produce when applied to domain values,
   that (2) can order, and that (3) can take as input to yield
   a canonical list of supertypes.

The optional context argument is necessary because some domains are
restricted, and operate only with respect to some specific context. An
example is a domain defined in terms of one or more ad hoc
hierarchies.

If you can implement this protocol for a domain, then you can have
generic functions that are defined for that domain, and you can have
deterministic dispatch and next-method for values in that domain.

There's no obvious way to implement (2) for types defined using
Clojure's ad hoc hierarchies, because (parents t) returns a set, which
is unordered. That doesn't mean there's no way at all to implement
(2); it means that any working implementation of (2) imposes an

Possible Solution for Left-Right Precedence and More when using Multimethods? (was re: oo)

2009-03-28 Thread David Nolen
Having thought a little about multiple inheritance when implementing Spinoza
I also ran into this problem. However at the time I wasn't hindered by
multifn dispatch as much as the fact that parents cannot be ordered (because
calling parents on a tag returns a set) as pointed out by Mark. I understand
Rich's point that hierarchies probably shouldn't be directional, but for the
sake of practicality why not allow the programmer to specify that a tag (or
even the whole hierarchy) should in fact have its relationships be ordered?
In general prefer-method seemed to me (I could be wrong) to be a last
attempt solution- when there is just no other way to resolve an ambiguity,
and this ambiguity is not of the hierarchy, but of multimethod dispatch. As
pointed out by Konrad  Rich, you can work around the limitation of
hierarchies right now with a lot of prefer-methods.  But as Mikel points
out, with current state of prefer-method you have to hunt through code to
find out where these prefers were made and for what reason and they assume
that you've already written your methods (this for me is the deal breaker).

In anycase my general feeling (in agreement with Mark) is that the problem
isn't with multifns but rather with how hierarchies are constructed.

So the achilles heel of hierarchies seems to be that when you call parents
(and related fns) on a tag you get a set - it has no order.  For single
inheritance hierarchies this is fine, but for multiple inheritance I think
this becomes a problem a very fast. Working on Spinoza, I realized I would
have to keep my own ordered list of parents in order to support left-right
precedence, basically keeping an ordered copy of the whole hierarchy. Again
prefer-method is only useful for fixing method-level ambiguities.  There's
no general way to say, type A always precedes type B without writing quite a
bit of explicit code (or hiding the problem away with macros).

Here's something that might kick of a dicussion to a proper solution (I am
sure there are some gaps in my logic), why not allow something like the
following?

;; allow control of how tags get introduced into the hierarchy
(def h (make-hierarchy :parents-fn fn1 :ancestors-fn fn2 :descendants-fn
fn3))

;; add a new parent insertion fn to a hierarchy
(add-parents-fn h fn4) ;; - returns a new hierarchy with the parents fn
set, all parents sets are converted into vectors

;; add a new parent insertion fn to a hierarchy for a specific key, only the
parents of ::my-tag are converted into a vector
(add-parents-fn h fn4 ::my-tag)

;; a hierarchy fn might look something like the following
(defn my-parents-fn [parents new-key]
   (conj parents new-key))

If my thinking is correct this is pretty flexible. This doesn't break the
meaning of hierarchy for any existing code.  It doesn't change the signature
of multimethods.  Yet now a user can provide fns that sorts a hierarchy
anyway they please, and it doesn't even have to be the entire hierarchy.
 This code will probably live in one spot where anyone could look to
understand how the hierarchy is being constructed.  All high-level
precedence ambiguities can now be resolved by looking at the hierarchy.
 prefer-method does only what it was intended to do- resolve method level
ambiguity.

David

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---