re: oo

2009-03-24 Thread Raoul Duke

question: what do people think about the general topic of inheritance?
my take on it so far is that inheritance apparently sounds like a good
idea at first to some folks, but quickly turns into something of a
nightmare if one is actually concerned with keeping a coherent
semantics (so that (a) people can learn it (b) simulate it in their
heads and (c) so you can have tools to check things maybe and (d)
ultimately so the code using it sucks less -- things like LSP and Java
Generics show how fubar it can easily be). so people have come up with
mixins, and then traits. and interfaces. and stuff.

mainly, i just hope that whatever OO Clojurians finally coalesce
towards doesn't make the same mistakes that have already been made by
plenty of other languages, from old C++ through to new Scala. (not
that i have the Programming Language Theory chops to help much there,
myself.)

sincerely.

--~--~-~--~~~---~--~~
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: oo

2009-03-24 Thread mikel



On Mar 24, 12:58 pm, Raoul Duke  wrote:
> question: what do people think about the general topic of inheritance?
> my take on it so far is that inheritance apparently sounds like a good
> idea at first to some folks, but quickly turns into something of a
> nightmare if one is actually concerned with keeping a coherent
> semantics (so that (a) people can learn it (b) simulate it in their
> heads and (c) so you can have tools to check things maybe and (d)
> ultimately so the code using it sucks less -- things like LSP and Java
> Generics show how fubar it can easily be). so people have come up with
> mixins, and then traits. and interfaces. and stuff.
>
> mainly, i just hope that whatever OO Clojurians finally coalesce
> towards doesn't make the same mistakes that have already been made by
> plenty of other languages, from old C++ through to new Scala. (not
> that i have the Programming Language Theory chops to help much there,
> myself.)

I'm not a big fan of inheritance; neither am I ardently opposed to it.
It's basically an automated facility for copying common code. On the
plus side, it's one approach to providing support for the principle of
"Don't Repeat Yourself". On the minus side, most systems with
inheritance combine the inheritance of behavior with the inheritance
of data structure, which are two totally different things. As always,
conflating orthogonal concerns leads to gratuitous duplication: you
inherit from a class because you want its data layout, but end up
writing gratuitous extra code because the inherited behavior is no
good to you (or vice versa). Also on the minus side, systems with
inheritance encourage you to scatter your API definition over lots of
places, which can be an obstacle to maintenance and judicious use.

I personally like Haskell's philosophy in this area: there is a
facility for defining data layouts, and there is a facility for
defining protocols, and they are completely separate. You can define a
new data layout without any reference to any behavior. Similarly, you
can define a new protocol and the behaviors it supports, without any
reference to any particular data layout. You can implement any
protocol you like at any time for any data layout you want, without
needeing to change the definitions of any data layouts. And,
conversely, you can add and extend data layouts any time you want,
without affecting existing implementations of behavior.

A Clojure system with a similar philosophy might consist of two
facilities: a facility for defining record types with named fields,
with record-extension that enables you to say "this record is that
other record over there plus these fields"; and a facility for
defining multifunctions that dispatch on some computable
characteristic of their arguments.

Clojure's built-in defstruct provides a way to specify record types,
but not to extend them. Konrad Hinsen is experimenting with a
typesystem that provides another way to define data layouts. Clojure's
built-in MultiFns provide one way to define functions that dispatch on
computable characteristics of their arguments. I'm experimenting with
implementing CLOS-style generic functions, which is another approach
(I have found Clojure MultiFns awkward to use thus far, especially
when trying to design extensible APIs around them; client code has to
know too much about the implementation details of MultiFns--e.g. you
have to know when and how to hand-tweak dispatching for the particular
MultiFns you are given).

--~--~-~--~~~---~--~~
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: oo

2009-03-25 Thread Konrad Hinsen

On 24.03.2009, at 19:29, mikel wrote:

> I personally like Haskell's philosophy in this area: there is a
> facility for defining data layouts, and there is a facility for
> defining protocols, and they are completely separate. You can define a

I like that as well, and I have been trying to do something similar  
in Clojure with my types module (clojure.contrib.types) and my  
collection of generic interfaces (clojure.contrib.generic). It's too  
early to say if these will work out well, but I do think they are as  
close to Haskell's philosophy as possible in a dynamically typed  
language.

I haven't thought much about extending types yet. It could mean  
opening the can of worms associated with inheritance and all that. I  
am waiting for a concrete situation where extension would be useful  
to think about how best to do it.

> Clojure's built-in defstruct provides a way to specify record types,
> but not to extend them.

It is not really meant to define types, the documentation clearly  
says that struct maps are just an implementation of maps optimized  
for a specific frequent use case.

> (I have found Clojure MultiFns awkward to use thus far, especially
> when trying to design extensible APIs around them; client code has to
> know too much about the implementation details of MultiFns--e.g. you
> have to know when and how to hand-tweak dispatching for the particular
> MultiFns you are given).

Could you elaborate a bit on this? I haven't met any major obstacles  
with multimethods yet. The dispatch functions give quite a lot of  
flexibility in practice. In what situation did you find them  
inconvenient?

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

2009-03-25 Thread Mark Engelberg

On Wed, Mar 25, 2009 at 1:44 AM, Konrad Hinsen
 wrote:
> Could you elaborate a bit on this? I haven't met any major obstacles
> with multimethods yet. The dispatch functions give quite a lot of
> flexibility in practice. In what situation did you find them
> inconvenient?

To summarize, I think the points that have been raised here and on
related threads are that:
1. Structs don't inherently have a type.  If you want to dispatch on
type (a common use-case), you have to make a constructor that inserts
the type information as part of the struct.  Some have expressed
concern that it may be too easy for this "type information" to be
altered, or worse, the data could be "changed" or "removed" in a way
that makes the struct inconsistent with the type label it carries
around.
2. No way to call "next-method" or "super", which limits the ability
to reuse related methods.
3. The dispatch mechanism requires a lot of explicit prefer-methods,
or else it may be hard to guarantee you won't get a run-time error
from a situation the dispatch system considers ambiguous.  This also
makes code less extensible because to add a method, you must know
about all the other methods that have been implemented in order to
insert all the appropriate preferences.

Honestly, the one time I used Clojure's multimethods (contrib.math),
they suited my needs perfectly, but I definitely see where these
concerns are coming from.  The existing mechanism is very flexible in
one respect: you can dispatch on anything you want, not just type.  In
other respects, it seems like Clojure's multimethods are less
sophisticated than their CLOS/Dylan counterparts.  If there is a way
to achieve the same things in Clojure, it's not readily apparent (see
recent thread about the next-method/super issue, for example).

--~--~-~--~~~---~--~~
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: oo

2009-03-25 Thread mikel



On Mar 25, 4:13 am, Mark Engelberg  wrote:
> On Wed, Mar 25, 2009 at 1:44 AM, Konrad Hinsen
>
>  wrote:
> > Could you elaborate a bit on this? I haven't met any major obstacles
> > with multimethods yet. The dispatch functions give quite a lot of
> > flexibility in practice. In what situation did you find them
> > inconvenient?


[... good points snipped...]

I agree with all the points you raise here.

> 3. The dispatch mechanism requires a lot of explicit prefer-methods,
> or else it may be hard to guarantee you won't get a run-time error
> from a situation the dispatch system considers ambiguous.  This also
> makes code less extensible because to add a method, you must know
> about all the other methods that have been implemented in order to
> insert all the appropriate preferences.

[...]

> it seems like Clojure's multimethods are less
> sophisticated than their CLOS/Dylan counterparts

I dunno if I'd go that far. What I can say is that you don't need
anything like prefer-method to prevent dispatching ambiguities in
either CLOS or Dylan. The requirement to hand-tweak dispatching
strikes me as particularly ugly. How can I design an extensible API on
MutiFns? I have no idea. Defining a new method can introduce an
ambiguity in dispatching that requires a prefer-method call to fix.
When I'm implementing the library, that's just a minor annoyance, but
when I contemplate delivering it to someone else for use and
extension, it suddenly turns into a major headache. Users of that
library can break existing code by defining new methods, because new
methods may introduce dispatching ambiguities. In order to fix the
breakage, they need to know the right prefer-method calls to make.
That means they need to understand esoteric details of the library
implementation for no good reason--for no reason at all, except that
if they don't know them, they won't be able to make the right prefer-
method calls.

Yuck.




--~--~-~--~~~---~--~~
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: oo

2009-03-25 Thread Konrad Hinsen

On 25.03.2009, at 10:13, Mark Engelberg wrote:

> 1. Structs don't inherently have a type.  If you want to dispatch on
> type (a common use-case), you have to make a constructor that inserts
> the type information as part of the struct.  Some have expressed

And/or in the metadata.

> concern that it may be too easy for this "type information" to be
> altered, or worse, the data could be "changed" or "removed" in a way
> that makes the struct inconsistent with the type label it carries
> around.

I am one of those who have expressed concerns, but I must also say  
that until now I have not encountered such a problem in real life. I  
have come to the conclusion that interfaces and types work  
differently in Clojure than in other languages that most of us are  
more familiar with. So perhaps we are expecting problems that really  
aren't there once you figure out how to do it "right".

> 2. No way to call "next-method" or "super", which limits the ability
> to reuse related methods.

Again, I'd like to see a real-life situation where this is an issue.

> 3. The dispatch mechanism requires a lot of explicit prefer-methods,
> or else it may be hard to guarantee you won't get a run-time error
> from a situation the dispatch system considers ambiguous.  This also

And there as well.

> makes code less extensible because to add a method, you must know
> about all the other methods that have been implemented in order to
> insert all the appropriate preferences.

This would only be an issue in complex hierarchies. As long as each  
library just adds its types to a hierarchy and implements methods for  
them, there is no problem. That's why I'd like to see the real-life  
situation where there is one.

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

2009-03-25 Thread Marko Kocić

Does anybody know of some minimal clos implementation that is easily
portable?

I suppose that it contain base functions that are implemented in CL,
and the rest of clos built on top of that.
It might be interesting to try to adapt such a library to clojure.

I remember people mentioning PCL and closette as clos implementations,
but actualy never looked at them.


Regards,
Marko Kocić
--~--~-~--~~~---~--~~
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: oo

2009-03-25 Thread mikel



On Mar 25, 12:35 pm, Konrad Hinsen  wrote:
> On 25.03.2009, at 10:13, Mark Engelberg wrote:
>
> > 1. Structs don't inherently have a type.  If you want to dispatch on
> > type (a common use-case), you have to make a constructor that inserts
> > the type information as part of the struct.  Some have expressed
>
> And/or in the metadata.
>
> > concern that it may be too easy for this "type information" to be
> > altered, or worse, the data could be "changed" or "removed" in a way
> > that makes the struct inconsistent with the type label it carries
> > around.
>
> I am one of those who have expressed concerns, but I must also say  
> that until now I have not encountered such a problem in real life. I  
> have come to the conclusion that interfaces and types work  
> differently in Clojure than in other languages that most of us are  
> more familiar with. So perhaps we are expecting problems that really  
> aren't there once you figure out how to do it "right".
>
> > 2. No way to call "next-method" or "super", which limits the ability
> > to reuse related methods.
>
> Again, I'd like to see a real-life situation where this is an issue.
>
> > 3. The dispatch mechanism requires a lot of explicit prefer-methods,
> > or else it may be hard to guarantee you won't get a run-time error
> > from a situation the dispatch system considers ambiguous.  This also
>
> And there as well.
>
> > makes code less extensible because to add a method, you must know
> > about all the other methods that have been implemented in order to
> > insert all the appropriate preferences.
>
> This would only be an issue in complex hierarchies. As long as each  
> library just adds its types to a hierarchy and implements methods for  
> them, there is no problem. That's why I'd like to see the real-life  
> situation where there is one.

I repeatedly ran into all the problems Mark mentioned when trying to
write an extensible set of codecs for serializing and deserializing
game data, and for building a extensible set of data structures for
representing game state. The game in question is a relatively large
multiplayer RPG-style game whose data library needs to describe a
large number of different kinds of objects, support transfer of those
objects over networks and storage and retrieval on various kinds of
repositories, and which needs to be extended by a number of people on
an ongoing basis. I need to be able to clearly say what the protocols
are for creating existing objects, and for defining new kinds of
objects, and for serializing and deserializing them.

With a large number of types of objects, name collisions in field-
names becomes an issue. I can solve it by providing a mechanism to
define the names allowed in a particular kind of object, and a way to
declare requirements about the values allowed on those names. Storing
type tags in metadata is handy in that the type function then returns
the tag you want, and it's easy to make MultFns dispatch on those
values. On the other hand, not all objects that one might want to
dispatch on support metadata. That leaves storing type tags in the
object itself, which is fairly convenient, but as the disadvantages
Mark mentions. A partial workaround is to implement a feature for
decalring the fields allowed and required in maps, and to implement
consistency checking to ensure (to the extent that one can) that no
one uses the type-tag field for anything other than type-tags.

It's possible to provide a polymorphic API that covers each of the
various defined kinds of objects, but building that API involves a lot
of prefer-method calls. The inconvenience of that necessity increases,
seemingly without bound, as people add new kinds of objects and
methods to handle them. Each addition potentially requires its
implementor to examine an ever-increasing set of previously-defined
data descriptions and methods to determine what the correct prefer-
method calls are. There may not always be a correct set. When there
isn't, finding the data description and method definition that cause
the unsolvable problem isn't necessarily easy. I'm extremely
uncomfortable with any library that requires its user to be familiar
with all of its internals and all its dependencies; that's exactly
what libraries are meant to avoid. Therefore I am even more
uncomfortable with library-building tools that guarantee that's the
sort of library I'll be building.

The set of game data objects describes features of an imaginary world.
Those features (creatures, crafted items, factions, and so on)
naturally cluster into related taxonomies of shared and specialized
features. If you can say "this is just like those things except for
these features", you save a lot of duplicated code. Type extension is
one part of that ability; next-method is the other.

This is one "real-world" situation where all the issues Mark raised
are real and pressing issues for development, but it's not a special
situation. I've run into these issues many many t

Re: oo

2009-03-25 Thread mikel



On Mar 25, 2:51 pm, Marko Kocić  wrote:
> Does anybody know of some minimal clos implementation that is easily
> portable?
>
> I suppose that it contain base functions that are implemented in CL,
> and the rest of clos built on top of that.
> It might be interesting to try to adapt such a library to clojure.
>
> I remember people mentioning PCL and closette as clos implementations,
> but actualy never looked at them.

Tinyclos is decent, and lots of people have made good use of it. For
example, it's a "standard" extension to Chicken Scheme (insofar as
anything to do with Chicken Scheme can be called "standard") and has
lots of enhancements provided by Felix.

The reason I didn't port Tinyclos to Clojure is that CLOS assumes a
specific model of classes, and I wanted to concentrate specifically on
generic functions, not add yet another typesystem to Clojure. You
could make a counterargument that the CLOS typesystem is specifically
designed to interoperate seamlessly with legacy typesystems, and you
would have a point.
--~--~-~--~~~---~--~~
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: oo

2009-03-26 Thread Marko Kocić



On 25 мар, 21:41, mikel  wrote:
> Tinyclos is decent, and lots of people have made good use of it. For
> example, it's a "standard" extension to Chicken Scheme (insofar as
> anything to do with Chicken Scheme can be called "standard") and has
> lots of enhancements provided by Felix.

I'll take a look at it. Haven't heard of if before.

> The reason I didn't port Tinyclos to Clojure is that CLOS assumes a
> specific model of classes, and I wanted to concentrate specifically on
> generic functions, not add yet another typesystem to Clojure. You
> could make a counterargument that the CLOS typesystem is specifically
> designed to interoperate seamlessly with legacy typesystems, and you
> would have a point.

Generic functions are part of clos that are the most interesting.
Addition of clos like generic function to clojure that will work with
existing types will be excellent addition. But ability to define new
closs classes would make them even mose usefull. The hard part would
be to answer to the following questions:

Q1 - How to integrate existing java types, clojure types and clos
types into one consistent hierarchy wrt generic functions?
Q2 - How to support defining methods with the same name as existing
functions and let them be used seamlessly?
Q3 - How to handle arity overloads?
Q4 - How to approach immutability? Should clos class instances be
immutable maps or references to immutabe maps?
Qx - ...


Regards,
Marko Kocć

--~--~-~--~~~---~--~~
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: oo

2009-03-26 Thread Rich Hickey



On Mar 25, 6:47 am, mikel  wrote:
> On Mar 25, 4:13 am, Mark Engelberg  wrote:
>
> > On Wed, Mar 25, 2009 at 1:44 AM, Konrad Hinsen
>
> >  wrote:
> > > Could you elaborate a bit on this? I haven't met any major obstacles
> > > with multimethods yet. The dispatch functions give quite a lot of
> > > flexibility in practice. In what situation did you find them
> > > inconvenient?
>
> [... good points snipped...]
>
> I agree with all the points you raise here.
>
> > 3. The dispatch mechanism requires a lot of explicit prefer-methods,
> > or else it may be hard to guarantee you won't get a run-time error
> > from a situation the dispatch system considers ambiguous.  This also
> > makes code less extensible because to add a method, you must know
> > about all the other methods that have been implemented in order to
> > insert all the appropriate preferences.
>
> [...]
>
> > it seems like Clojure's multimethods are less
> > sophisticated than their CLOS/Dylan counterparts
>
> I dunno if I'd go that far. What I can say is that you don't need
> anything like prefer-method to prevent dispatching ambiguities in
> either CLOS or Dylan. The requirement to hand-tweak dispatching
> strikes me as particularly ugly. How can I design an extensible API on
> MutiFns? I have no idea. Defining a new method can introduce an
> ambiguity in dispatching that requires a prefer-method call to fix.
> When I'm implementing the library, that's just a minor annoyance, but
> when I contemplate delivering it to someone else for use and
> extension, it suddenly turns into a major headache. Users of that
> library can break existing code by defining new methods, because new
> methods may introduce dispatching ambiguities. In order to fix the
> breakage, they need to know the right prefer-method calls to make.
> That means they need to understand esoteric details of the library
> implementation for no good reason--for no reason at all, except that
> if they don't know them, they won't be able to make the right prefer-
> method calls.
>
> Yuck.

I wonder about the generality of this concern. Defining new methods
that break existing code implies both defining new methods on existing
super-types *and* some crosscutting multiple inheritance. I've seen it
happen only when first building method sets on existing hierarchies
not designed with this system in mind, e.g. when superimposing methods
on Java hierarchies. If you have an existing hierarchy from CLOS and
are disappointed that Clojure's multimethods don't work like CLOS,
well, ok.

However, all is not rosy with CLOS, and I've run into problems with
the left-to-right semantics of both arglists and superclass lists many
times, trying to game precedence lists etc. There's somethjing
inherently broken with not being able to derive from two superclasses
that have the same bases, just because they have different derivation
orders - see bottom of:

http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/sec_4-3-5-2.html

Plus the inability to dispatch on other than class or eql, the
inability to superimpose another taxonomy without redefining the
class, the inability to have multiple independent taxonomies...

The reason Clojure doesn't have an elaborate system like CLOS, or even
like Python et al is that all of those systems have limits and quirks
and hardwiring one into a language is a bad idea, IMO.  Clojure's
hierarchies and multimethods are just libraries - there's no reason
you couldn't define a CLOS-like object system for Clojure (although
any such system will have problems integrating Java's type hierarchy
because there is no definitive superclass ordering). I'm just trying
to tease out the useful ingredients of OO and make them available a la
carte.

Two things contribute to the sometimes-convenient default resolution
policy of CLOS:

One is left-to-right argument order precedence, which roughly
translates to vector precedence in Clojure (although the mapping to a
vector need not follow arg order). The other is default precedence of
classes based upon left-to-right declaration in defclass, and
topological sort based thereupon.

Right now, both matching and precedence follow isa?, but the latter
need not, or could be supplemented. Here are the characteristics I
think are important:

- It should be possible to superimpose a parent on an existing child
without modifying the child. This is a critical feature of Clojure's a
la carte hierarchies and one which I have desired in every OO language
(including CLOS) I have ever worked in. Requiring a client of
(independently developed) A and B to have to modify A in order to have
it work with B is unworkable.

- It should work transparently with Java hierarchies, which also
implies the above.

- It should support independent and order-independent assertions about
the hierarchy. Anything based upon canonic master definitions is
brittle and inextensible.

What I like about preference declarations is that you are
acknowledging a definite ambi

Re: oo

2009-03-26 Thread Konrad Hinsen

On 26.03.2009, at 14:59, Rich Hickey wrote:

> Plus the inability to dispatch on other than class or eql, the
> inability to superimpose another taxonomy without redefining the
> class, the inability to have multiple independent taxonomies...

The ability to have multiple taxonomies is indeed very useful in my  
(limited) experience.

> One is left-to-right argument order precedence, which roughly
> translates to vector precedence in Clojure (although the mapping to a
> vector need not follow arg order).

I am not sure I'd want such a precedence. If I dispatch on several  
arguments, their role is sometimes symmetric, sometimes not, and  
where it is not, it is not necessarily the first argument that takes  
precedence.

However, what I wished I had on some occasions is a way to specify a  
sequence of dispatching values as a result of the dispatch function.  
For example, in a two-argument dispatch, I'd like to be able to write  
something like

(defmulti foo
   (fn [x y]
 (let [tx (type x) ty (type y)]
   (list [tx ty] (cond (isa? tx ty) ty (isa? ty tx) tx :else #{tx  
ty})))

with the result of calling a method for [tx ty] if available and one  
of tx/ty/#{tx ty} otherwise. Without such an option, I sometimes have  
to write several methods with an identical implementation but  
different dispatch signatures.

One way to make this and other generalizations possible would be to  
have access to the multimethod's implementation list (and perhaps  
preference order) in the dispatch function.

> What I like about preference declarations is that you are
> acknowledging a definite ambiguity in a pure derivation hierarchy
> rather than poisoning the notion of hierarchy with directionality.

What I like about them is that an ambiguity often points to a design  
problem that should better be fixed than circumvented.

> That said, perhaps the preference specifications at the method level
> aren't as reusable/convenient as preferences declared at another level
> or somewhere else.

How about a preference function on each multimethod, along with the  
dispatch function? One could then easily use one such function for  
several multimethods. But what I suggested above (access to the  
dispatch signatures and preferences in the dispatch function) should  
be even more general.

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

2009-03-26 Thread mikel



On Mar 26, 8:59 am, Rich Hickey  wrote:
> On Mar 25, 6:47 am, mikel  wrote:

[...my misgivings snipped...]

> I wonder about the generality of this concern. Defining new methods
> that break existing code implies both defining new methods on existing
> super-types *and* some crosscutting multiple inheritance. I've seen it
> happen only when first building method sets on existing hierarchies
> not designed with this system in mind, e.g. when superimposing methods
> on Java hierarchies. If you have an existing hierarchy from CLOS and
> are disappointed that Clojure's multimethods don't work like CLOS,
> well, ok.

I don't have such a hierarchy. Rather, I have a domain-specified set
of data and a set of requirements for APIs. I know how to build a data
dictionary and API for these requirements in several languages; I
don't (yet) know how to do it in Clojure.

> However, all is not rosy with CLOS, and I've run into problems with
> the left-to-right semantics of both arglists and superclass lists many
> times, trying to game precedence lists etc. There's somethjing
> inherently broken with not being able to derive from two superclasses
> that have the same bases, just because they have different derivation
> orders - see bottom of:
>
> http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/sec...

I'll take your word for it that you've run into problems on this
point. I haven't.

The page that you cite explains what the potential conflicts are and
tells you what not to do, so that you can avoid those conflicts. Is
there an equally clear explanation of what not to do in Clojure, so as
to avoid visiting dispatch conflicts on users of my libraries? I
looked for such an explanation, but haven't found it yet. I hope I've
just missed it; I'd really rather use the built-in features of the
language.

> Plus the inability to dispatch on other than class or eql, the
> inability to superimpose another taxonomy without redefining the
> class, the inability to have multiple independent taxonomies...

At least two of the projects I've worked on using CLOS (Apple's
Bauhaus and SK8 projects) did all of those things. If you mean, those
things are not ready to go out-of-the-box in CLOS, you're right. All
the CLOS implementations I've worked with, however, provide good
support for implementing those sorts of alternatives if you want them.
That's no slight on Clojure; I've found that Clojure also provides the
tools I need to build alternatives to the built-in features.

> The reason Clojure doesn't have an elaborate system like CLOS, or even
> like Python et al is that all of those systems have limits and quirks
> and hardwiring one into a language is a bad idea, IMO.  Clojure's
> hierarchies and multimethods are just libraries - there's no reason
> you couldn't define a CLOS-like object system for Clojure (although
> any such system will have problems integrating Java's type hierarchy
> because there is no definitive superclass ordering). I'm just trying
> to tease out the useful ingredients of OO and make them available a la
> carte.

I wholeheartedly endorse this approach. I just have this one problem
with MultiFns: as far as I can tell, they expose the internals of my
library implementations in unfortunate ways. Suppose you're using an
extensible codec API and you add support for a novel combination of
data formats. You write a new method and discover a brand new error
caused by a dispatch ambiguity. Now what? How do you find out what the
cause of the error is? What should the library provider have done to
ensure that you would not have this problem? What do you do to ensure
that your colleagues and customers won't have this problem?

The question isn't rhetorical; I actually encountered this exact
situation more than once, and it's the reason that I diverted time
from getting my main application done to writing a generic-function
library that makes that problem go away. The generic function library
works: the problem goes away, and all the relevant tests pass.

Go ahead and tell me that I failed to understand MultiFns correctly;
that would be good news. If you can tell me how to prevent the
aforementioned situation using MultiFns, then I can abandon generic
functions without regret, and get back to my actual goal. Note that I
am not asking for an estimate of how likely that sort of problem is.
Several people have mentioned that they don't think it very likely.
Their optimism aside, what interests me is a deterministic method of
preventing problems that have actually arisen.


> What I like about preference declarations is that you are
> acknowledging a definite ambiguity in a pure derivation hierarchy
> rather than poisoning the notion of hierarchy with directionality.

Why is it poison? The DAG will be traversed in some order; you're just
saying that you're not going to say what that order is. That's fine as
long as *I* can specify the traversal order, and I can, in part. But,
unless I've missed something impor

Re: oo

2009-03-26 Thread Laurent PETIT
2009/3/26 Konrad Hinsen 

>
> On 26.03.2009, at 14:59, Rich Hickey wrote:
>
> > Plus the inability to dispatch on other than class or eql, the
> > inability to superimpose another taxonomy without redefining the
> > class, the inability to have multiple independent taxonomies...
>
> The ability to have multiple taxonomies is indeed very useful in my
> (limited) experience.
>
> > One is left-to-right argument order precedence, which roughly
> > translates to vector precedence in Clojure (although the mapping to a
> > vector need not follow arg order).
>
> I am not sure I'd want such a precedence. If I dispatch on several
> arguments, their role is sometimes symmetric, sometimes not, and
> where it is not, it is not necessarily the first argument that takes
> precedence.
>
> However, what I wished I had on some occasions is a way to specify a
> sequence of dispatching values as a result of the dispatch function.
> For example, in a two-argument dispatch, I'd like to be able to write
> something like
>
> (defmulti foo
>   (fn [x y]
> (let [tx (type x) ty (type y)]
>   (list [tx ty] (cond (isa? tx ty) ty (isa? ty tx) tx :else #{tx
> ty})))
>
> with the result of calling a method for [tx ty] if available and one
> of tx/ty/#{tx ty} otherwise. Without such an option, I sometimes have
> to write several methods with an identical implementation but
> different dispatch signatures.
>
> One way to make this and other generalizations possible would be to
> have access to the multimethod's implementation list (and perhaps
> preference order) in the dispatch function.
>
> > What I like about preference declarations is that you are
> > acknowledging a definite ambiguity in a pure derivation hierarchy
> > rather than poisoning the notion of hierarchy with directionality.
>
> What I like about them is that an ambiguity often points to a design
> problem that should better be fixed than circumvented.
>
> > That said, perhaps the preference specifications at the method level
> > aren't as reusable/convenient as preferences declared at another level
> > or somewhere else.
>
> How about a preference function on each multimethod, along with the
> dispatch function? One could then easily use one such function for
> several multimethods. But what I suggested above (access to the
> dispatch signatures and preferences in the dispatch function) should
> be even more general.


I wanted to write something along those lines, but you Konrad did this
better than I could have done :-)

Though I don't have any concrete need currently:

Am I the only one to have the feeling that the current functionalities
provided by multimethods are too tied with the idea that the dispatching
will be based on type hierarchies ?

I think the current implementation closes the door to a lot of possibly
interesting experiments/applications, because, as Konrad said, both the way
the mechanism of discovering candidate methods, and the way to disambiguing
them is somewhat hardcoded for a certain vision of type hierarchies.

The current implementation, while maybe a good default (I don't have strong
arguments against or pro for saying it is the right default mechanism) could
certainly be just an implementation of a redefinable more generic solution.

The way I understand it, the algorithm for discovering candidate methods is
 1- compute a value from the arguments of the call,
 2- and then determine for each method's declared dispatch-value if it is a
relevant candidate

Why not make the behavior of 2- user redefinable in the defmulti declaration
?
Such a method could have the following definition :
(fn [computed-value dispatch-values])

This method could return either nil (then a method with a default
dispatch-value would be searched as usual), either a list of candidate
dispatch-values (no requirement on the order of the returned values, this
would be the job of the disambuating method).

And the way I understand it, the algorithm for disambiguating candidate
methods is
1- call a method that will apply an algorithm only based on deterministic
relations between known-to-the-implementer-or-user existing methods.

Why not make this 1- behavior just a "default" behaviour, and let the
possibility for the user to totally use another one, by passing it to the
defmulti declaration as a function :
(fn [computed-value candidate-values])
(I'm not sure computed-value is interesting here, though, but maybe better
have it than not)

This method could return an ordered list of candidates.
a) if the list is empty, then prefer-method will be called in a last resort
b) else the first item of the list is the method to dispatch to. And the
rest of the list could be passed to the method in a non intrusive way (could
it be via rebinding a global ?)


Thanks if you read past through this :-) And I'll be happy to see comments
on this one. This really reflects what I had in mind for some time, so if
I'm wrong in certain (or totally) areas, I'll be happy to learn from my own
er

Re: oo

2009-03-27 Thread Mark Engelberg

I'm very interested in this thread.  I'm having trouble figuring out
exactly which situations require prefer-method and which do not.  One
thing that would help me understand the issues more deeply would be if
someone could post the simplest possible multimethod that requires
prefer-method to disambiguate.

In Rich's list of ideals, I particularly appreciate the desire to be
able impose a parent on a child without changing the child.  This has
come up for me, and I was grateful Clojure had this ability.

I didn't see anything in the list of ideals that explains the lack of
a next-method, and it's not really clear to me how to reap some of the
benefits of inheritance without this.

On a somewhat related note, as my code grows, and I'm using more
complicated data structures, representing all of them as hash tables
is starting to feel a little too, well, unstructured.  Can anyone else
report from the Clojure trenches on ways to manage this complexity?

--~--~-~--~~~---~--~~
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: oo

2009-03-27 Thread Mark Engelberg

I think I've answered at least part of my own question.  This is the
simplest ambiguous case I've found:

ab
| |
--
|
c

user> (defmulti test-prefer :tag)
#'user/test-prefer
user> (defmethod test-prefer ::a [h] "a")
#
user> (defmethod test-prefer ::b [h] "b")
#
user> (derive ::c ::a)
nil
user> (derive ::c ::b)
nil
user> (test-prefer {:tag ::a})
"a"
user> (test-prefer {:tag ::b})
"b"
user> (test-prefer {:tag ::c})
; Evaluation aborted.
user> (prefer-method test-prefer ::a ::b)
#
user> (test-prefer {:tag ::c})
"a"

So if I understand correctly, the crux of the problem is that this
preference information is not part of the actual derive hierarchy.
This gives added flexibility to customize on a method by method basis,
but at a cost.
One cost seems to be that if an outside user wants to write a new
method on this very same type hierarchy, he can only do it if he knows
how the types are derived from one another inside the library so that
he can restate all the necessary precedences with appropriate
prefer-method calls on his own new method.

Another interesting question is whether at least test-prefer is safe
for extension.  Here's a potential problem I see.  Let's say that in
the above example, type ::c is what is intended to be publicly
visible, and the base classes ::a or ::b just provide the base
implementation for various methods, including prefer-method.

I may come along and want to extend test-prefer to a type ::d which
derives from ::c and ::e, where ::e provides an alternative
implementation.

ab   (a and b are intended to be hidden from end-user)
| |
--
|
c  e
|   |

 |
 d


(derive ::d ::c)
(derive ::d ::e)
(defmethod test-prefer ::e [h] "e")

Now, as an external user, I know nothing about where test-prefer on
::c gets its behavior.  Obviously, I have to disambiguate between
whether test-prefer chooses ::c over ::e, so I may try something like
this:
(prefer-method test-prefer ::c ::e)

But this will not work.  I still get an error saying I need to
disambiguate between ::a and ::e.  And not knowing anything about ::a,
I could be very confused, and not know how to provide this
information.

Considering how complex the situation can get with single dispatch, I
imagine it gets even more complex in multiple dispatch situations.  In
the multimethods example at clojure.org/multimethods, an example is
given of disambiguating between [::shape ::rect] and [::rect ::shape].
 But again, if you're writing the bar method from outside of the
library which defines ::shape and ::rect, you might not even know
which is more specific.  It might be easier to choose a strategy, such
as more specific on the leftmost taking precedence, than to know the
details of how the various types in the library interact.

Anyway, this is my attempt to digest and restate what I've learned
from this thread and from tinkering around.  Any other good examples
that illustrate some of the difficulties?

--~--~-~--~~~---~--~~
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: oo

2009-03-27 Thread Konrad Hinsen

On Mar 27, 2009, at 9:25, Mark Engelberg wrote:

> I think I've answered at least part of my own question.  This is the
> simplest ambiguous case I've found:
>
> ab
> | |
> --
> |
> c

Indeed. An ambiguous situation can occur whenever the type hierarchy  
graph is not a tree. Since it takes at least three nodes to make a  
graph that is not a tree, your example is the simplest one possible.

> So if I understand correctly, the crux of the problem is that this
> preference information is not part of the actual derive hierarchy.

That is one way to put it, but I think there are other possible  
solutions than putting the preference information into the hierarchy.

> One cost seems to be that if an outside user wants to write a new
> method on this very same type hierarchy, he can only do it if he knows
> how the types are derived from one another inside the library so that
> he can restate all the necessary precedences with appropriate
> prefer-method calls on his own new method.

That could be avoided with a set of utility functions/macros for  
placing types into a hierarchy and for defining multimethods. These  
utility functions could take care of adding prefer-method calls as  
necessary.

Of course, if this is a frequent need, explicitly language support  
would be preferable, but at least that would be a way to experiment  
with design options to figure out what works best.

> Now, as an external user, I know nothing about where test-prefer on
> ::c gets its behavior.  Obviously, I have to disambiguate between
> whether test-prefer chooses ::c over ::e, so I may try something like
> this:
> (prefer-method test-prefer ::c ::e)
>
> But this will not work.  I still get an error saying I need to
> disambiguate between ::a and ::e.  And not knowing anything about ::a,
> I could be very confused, and not know how to provide this
> information.

True. It would be nice if prefer-method could itself figure out  
that ::a provides the implementation for ::c. But again that  
functionality can be added with utility functions, as the hierarchy  
can be explored using the functions parents, ancestors, and descendants.

> Considering how complex the situation can get with single dispatch, I
> imagine it gets even more complex in multiple dispatch situations.  In
> the multimethods example at clojure.org/multimethods, an example is
> given of disambiguating between [::shape ::rect] and [::rect ::shape].
>  But again, if you're writing the bar method from outside of the
> library which defines ::shape and ::rect, you might not even know
> which is more specific.  It might be easier to choose a strategy, such
> as more specific on the leftmost taking precedence, than to know the
> details of how the various types in the library interact.

I am not so sure about this. I wonder if there is a real-life use  
case where a client library would need to solve dispatching issues on  
types in another library about which it doesn't know anything. If  
there isn't, the problem is not relevant, and if there is, I'd like  
to see a demonstration that something like left-to-right precedence  
is indeed a reasonable default.

On the other hand, I would definitely like to be able to implement  
left-to-right precedence myself on top of Clojure's multimethods, and  
it seems that at the moment this is not possible.

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

2009-03-27 Thread Laurent PETIT
2009/3/27 Konrad Hinsen 

>
> On the other hand, I would definitely like to be able to implement
> left-to-right precedence myself on top of Clojure's multimethods, and
> it seems that at the moment this is not possible.


Yes.

And also the ability to redefine the method that tries to determine
candidate dispatch values, so that one could write polymorphic functions not
only based on ahead of time defined data hierarchy graphs.

One solution could be to add more options to defmulti.
Another solution could be to have a *defmulti-flavor* global var that could
have for value some hashmap : { :dispatch-value-matcher function1
:dispatch-value-narrower function2 } that could be bound to a different
flavor for certain multifunctions by library creators.

Without that, for example, I don't know how one could prevent the
combinatorial explosion of the prefer-method calls to make, even inside the
boundaries of a library, even with simple hierarchies without multiple
inheritence, for the following problem:

A, B, C, D, E, F all inherit from Z.
The library implementor wants to provide specialized functions such as:
(defmethod a-method [A B C D] [a b c d] ...)
(defmethod a-method [A B D C] [a b d c] ...)

If the implementor is able to concisely describe the resolution mechanism
with an algorithm (a function), he still will have to implement the results
of his algorithm in terms of prefer-method declarations.

For example, the classic above cited resolution mechanism "the leftmost
specific wins" must be manually hard-coded. And in this special case it gets
even worse for extension purpose as well.


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

2009-03-27 Thread mikel



On Mar 27, 5:56 am, Konrad Hinsen  wrote:
> On Mar 27, 2009, at 9:25, Mark Engelberg wrote:

> > Considering how complex the situation can get with single dispatch, I
> > imagine it gets even more complex in multiple dispatch situations.  In
> > the multimethods example at clojure.org/multimethods, an example is
> > given of disambiguating between [::shape ::rect] and [::rect ::shape].
> >  But again, if you're writing the bar method from outside of the
> > library which defines ::shape and ::rect, you might not even know
> > which is more specific.  It might be easier to choose a strategy, such
> > as more specific on the leftmost taking precedence, than to know the
> > details of how the various types in the library interact.
>
> I am not so sure about this. I wonder if there is a real-life use  
> case where a client library would need to solve dispatching issues on  
> types in another library about which it doesn't know anything.

No, because such a library won't get used. If I offered a customer a
library with the caveat that his people might run into unexpected
dispatch conflicts that could be solved simply by reading the library
sources, he'd say, "thanks, I'll pass."

> If  
> there isn't, the problem is not relevant, and if there is, I'd like  
> to see a demonstration that something like left-to-right precedence  
> is indeed a reasonable default.

I can tell you about large software projects in which left-to-right
precedence worked well. "Demonstrate"? That's a lot of code to
recapitulate!

There is nothing magical about left-to-right precedence, except that
*you know in advance what it is*. You can reason about it, because you
know what it is. You can predict what kinds of uses will be a problem,
and therefore can avoid those problems. For purposes of writing
reusable and extensible subsystems, *any* defined order is better than
no defined order.

> On the other hand, I would definitely like to be able to implement  
> left-to-right precedence myself on top of Clojure's multimethods, and  
> it seems that at the moment this is not possible.

There it is: it's fine if Clojure doesn't define a default and
universal traversal order for MultiFn dispatch, as long as I can
define such an order when I need it. prefer-method isn't quite enough,
because it only works on dispatch values that are already defined. In
order to make a safely-extensible library, I need to be able to
prescribe a traversal order over dispatch values that haven't yet been
created.

I have a separate issue with prefer-method, in that it defines
traversal order implicitly, in a way that is hard to digest. That is,
you can't look in one place to find out what the traversal is; you
instead have to search out all the prefer-method calls and piece the
order together from examining each of them. That's tangential to the
present discussion, though.

If none of these considerations moves Rich much, that's okay. He gave
us the tools we need to write our own solutions.
--~--~-~--~~~---~--~~
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: oo

2009-03-27 Thread Rich Hickey

On Fri, Mar 27, 2009 at 4:58 PM, mikel  wrote:
>
>
>
> On Mar 27, 5:56 am, Konrad Hinsen  wrote:
>> On Mar 27, 2009, at 9:25, Mark Engelberg wrote:
>
>> > Considering how complex the situation can get with single dispatch, I
>> > imagine it gets even more complex in multiple dispatch situations.  In
>> > the multimethods example at clojure.org/multimethods, an example is
>> > given of disambiguating between [::shape ::rect] and [::rect ::shape].
>> >  But again, if you're writing the bar method from outside of the
>> > library which defines ::shape and ::rect, you might not even know
>> > which is more specific.  It might be easier to choose a strategy, such
>> > as more specific on the leftmost taking precedence, than to know the
>> > details of how the various types in the library interact.
>>
>> I am not so sure about this. I wonder if there is a real-life use
>> case where a client library would need to solve dispatching issues on
>> types in another library about which it doesn't know anything.
>
> No, because such a library won't get used. If I offered a customer a
> library with the caveat that his people might run into unexpected
> dispatch conflicts that could be solved simply by reading the library
> sources, he'd say, "thanks, I'll pass."
>
>> If
>> there isn't, the problem is not relevant, and if there is, I'd like
>> to see a demonstration that something like left-to-right precedence
>> is indeed a reasonable default.
>
> I can tell you about large software projects in which left-to-right
> precedence worked well. "Demonstrate"? That's a lot of code to
> recapitulate!
>
> There is nothing magical about left-to-right precedence, except that
> *you know in advance what it is*. You can reason about it, because you
> know what it is. You can predict what kinds of uses will be a problem,
> and therefore can avoid those problems. For purposes of writing
> reusable and extensible subsystems, *any* defined order is better than
> no defined order.
>
>> On the other hand, I would definitely like to be able to implement
>> left-to-right precedence myself on top of Clojure's multimethods, and
>> it seems that at the moment this is not possible.
>
> There it is: it's fine if Clojure doesn't define a default and
> universal traversal order for MultiFn dispatch, as long as I can
> define such an order when I need it. prefer-method isn't quite enough,
> because it only works on dispatch values that are already defined. In
> order to make a safely-extensible library, I need to be able to
> prescribe a traversal order over dispatch values that haven't yet been
> created.
>
> I have a separate issue with prefer-method, in that it defines
> traversal order implicitly, in a way that is hard to digest. That is,
> you can't look in one place to find out what the traversal is; you
> instead have to search out all the prefer-method calls and piece the
> order together from examining each of them. That's tangential to the
> present discussion, though.
>

There is prefers:

(prefers print-method)

-> {clojure.lang.ISeq #{clojure.lang.IPersistentCollection
java.util.Collection}, clojure.lang.IPersistentList
#{clojure.lang.ISeq}}

> If none of these considerations moves Rich much, that's okay. He gave
> us the tools we need to write our own solutions.

Hang tight - I hear your concerns and am thinking about them.

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

2009-03-27 Thread mikel



On Mar 25, 3:44 am, Konrad Hinsen  wrote:

> I haven't thought much about extending types yet. It could mean  
> opening the can of worms associated with inheritance and all that. I  
> am waiting for a concrete situation where extension would be useful  
> to think about how best to do it.

The main thread of this conversation has wandered off into multiple
dispatch and various approaches to dealing with that, but the topic
you touch on here is also interesting. It's probably about time I
experimented with your types library. I've been using my own extremely
simple model library, but I've been eyeballing clojure.contrib.types,
meaning to see if I like it better.

(Why would I use either one? Because I want a convenient way to write
definitions in source code that say what fields are to be expected and
allowed in application 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
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: oo

2009-03-28 Thread Michael Wood

On Thu, Mar 26, 2009 at 12:49 PM, Marko Kocić  wrote:
>
> On 25 мар, 21:41, mikel  wrote:
>> Tinyclos is decent, and lots of people have made good use of it. For
>> example, it's a "standard" extension to Chicken Scheme (insofar as
>> anything to do with Chicken Scheme can be called "standard") and has
>> lots of enhancements provided by Felix.
>
> I'll take a look at it. Haven't heard of if before.
[...]

I just saw this on Planet Lisp:

http://www.foldr.org/~michaelw/log/programming/lisp/clos
http://www.foldr.org/~michaelw/projects/jclos/

It's a port of Tiny-CLOS to Java by Michael Weber.

-- 
Michael Wood 

--~--~-~--~~~---~--~~
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: oo

2009-03-28 Thread mikel



On Mar 28, 4:22 am, Michael Wood  wrote:
> On Thu, Mar 26, 2009 at 12:49 PM, Marko Kocić  wrote:
>
> > On 25 мар, 21:41, mikel  wrote:
> >> Tinyclos is decent, and lots of people have made good use of it. For
> >> example, it's a "standard" extension to Chicken Scheme (insofar as
> >> anything to do with Chicken Scheme can be called "standard") and has
> >> lots of enhancements provided by Felix.
>
> > I'll take a look at it. Haven't heard of if before.
>
> [...]
>
> I just saw this on Planet Lisp:
>
> http://www.foldr.org/~michaelw/log/programming/lisp/closhttp://www.foldr.org/~michaelw/projects/jclos/
>
> It's a port of Tiny-CLOS to Java by Michael Weber.

Note that just porting Tinyclos might not give you what you're looking
for. You probably want to do some work on figuring out how to
integrate Clojure's various types. Scheme's system of types is simple
enough that it's not hard to fit CLOS to it. In the case of Common
Lisp it's a lot more work, but the work's already been done for you,
if you use any standard implementation of Common Lisp with a standard
CLOS in it.

The work to integrate Clojure is probably more akin to the work to
integrate Common Lisp, and it hasn't been done yet. In order to
compute slots and applicable methods, you need class precedence lists
for all possible values. That means you need a function that returns a
class for any input value. The clojure function named "class" doesn't
do the right thing, because the information it gives you for some
values is not correct; for example, if the input is an object with a
type tag in its metadata, the output of class is irrelevant. The
function named "type" doesn't work either, because it's possible to
construct perfectly good Clojure values for which that function is
undefined.

So, at minimum, to make a solid port, you need to add a function that
can return a sensible type value for any input, and you need to devise
a means of constructing some way of traversing any arbitrary set of
types to deterministically obtain a class-precedence list for it, so
that you can resolve dispatch. This can be done: doing it for Common
Lisp was no less troublesome than doing it for Clojure would be; but
it was significant work to do it, and you should expect that it would
be significant work to do it for Clojure, too.

And you should expect, as the designers of CLOS did, that not everyone
will be happy with your algorithm for constructing class-precedence
lists. Fortunately, the entire point of building CLOS on a MOP, as in
Tinyclos, is that anyone who doesn't like your solution has the tools
to make his own.

As an aside, Dylan was an example of a brand new Lisp that was
designed from the start to be built on CLOS. Dylan's fundamental model
of types was CLOS; every value (including classes and methods) was an
instance of a CLOS class. Of course, once the language was built, it
wasn't called "CLOS" anymore, because it wasn't Common Lisp. Nowadays
it doesn't look as much like a Lisp anymore, since s-expression syntax
was abandoned. It did contribute at least one thing of potential
relevance, though, for anyone considering implementing a CLOS-like
object system: the C3 class-linearization algorithm. Given any set of
classes, C3 gives you either a single, reliable ordering, or a clear
error that is capable of telling you what you need to fix.
--~--~-~--~~~---~--~~
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: oo

2009-03-28 Thread David Nolen
On Sat, Mar 28, 2009 at 4:40 PM, mikel  wrote:

>
> So, at minimum, to make a solid port, you need to add a function that
> can return a sensible type value for any input


Enjoying the thread. Out of curiosity for which Clojure values is the return
value of the type function undefined?

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



Re: oo

2009-03-28 Thread mikel



On Mar 28, 4:28 pm, David Nolen  wrote:
> On Sat, Mar 28, 2009 at 4:40 PM, mikel  wrote:
>
> > So, at minimum, to make a solid port, you need to add a function that
> > can return a sensible type value for any input
>
> Enjoying the thread. Out of curiosity for which Clojure values is the return
> value of the type function undefined?

Try this:

(type (proxy [clojure.lang.IMeta clojure.lang.IRef][]))

java.lang.UnsupportedOperationException: meta (NO_SOURCE_FILE:0)
  [Thrown class clojure.lang.Compiler$CompilerException]


No doubt someone is going to point out that the proxy object I created
there is useless; that's true, but beside the point. The point is that
it's straightforward to create some value v for which (type v) is
undefined. In order to make a Clojure-friendly version of CLOS, you
need some concept of object type such that you can define a function
that returns a sensible type for any value.

The way that Dylan handled situations similar to Clojure's proxy
objects was with objects called singletons; a singleton is an object
that represents a specific value as a class. For example, (singleton
5) returns an object that is a class, but is also the integer 5. You
can define methods that specialize on such objects.

For example, below is an excerpt from the UI libraries of Apple's long-
ago Bauhaus project. Notice the first line:

  (define-method build-form ((key (singleton label:))

The equivalent syntax in Clojure (if clojure had these mechanisms)
would be:

  (define-method build-form [[key (singleton :label)]


(There was no equivalent of defn in Dylan; there was only define-
method, because all values were instances of Dylan classes, and in
that environment a defn is no different from a define-method without
value constraints. Consequently, all functions were polymorphic; all
unsealed functions could be extended by adding new method
definitions.)



(define-method build-form ((key (singleton label:))
   remaining-spec
   form
   current-x
   current-y
   layout-vector)
  (ignore key)
  (bind ((label-string (car remaining-spec))
 (next (rest remaining-spec)))
  (add-feature-to-form
   (make 
 string: label-string
 top: current-y
 left: current-x
 style-array: $espy-10-bold-pointer)
   next form current-x current-y layout-vector)))


--~--~-~--~~~---~--~~
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: oo

2009-03-28 Thread David Nolen
On Sun, Mar 29, 2009 at 1:25 AM, mikel  wrote:
>
> (type (proxy [clojure.lang.IMeta clojure.lang.IRef][]))
>
> java.lang.UnsupportedOperationException: meta (NO_SOURCE_FILE:0)
>  [Thrown class clojure.lang.Compiler$CompilerException]
>
>
> No doubt someone is going to point out that the proxy object I created
> there is useless; that's true, but beside the point. The point is that
> it's straightforward to create some value v for which (type v) is
> undefined. In order to make a Clojure-friendly version of CLOS, you
> need some concept of object type such that you can define a function
> that returns a sensible type for any value.
>

Not totally following you here as:

(proxy [clojure.lang.IMeta clojure.lang.IRef][])

immediately throws an error. I can't think of a situation in Clojure where
the type function does not return a usable value. Let me know if I'm wrong,
but your example is not a case as far as I can tell.

--~--~-~--~~~---~--~~
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: oo

2009-03-29 Thread Meikel Brandmeyer

Hi,

Am 29.03.2009 um 08:34 schrieb David Nolen:


Not totally following you here as:

(proxy [clojure.lang.IMeta clojure.lang.IRef][])

immediately throws an error. I can't think of a situation in Clojure  
where the type function does not return a usable value. Let me know  
if I'm wrong, but your example is not a case as far as I can tell.


The point that Mikel wants to make is, that you can
easily provide a proxy, which implements clojure.lang.IMeta.
But when you don't provide a "meta" implementation,
the proxy will throw a UnsupportedOperation exception.
Hence type will not work.

I personally consider this a non-issue. What is the point
of providing an interface and then yell "I WONT DO IT" at
the system, when it tries to do the advertised action? In
my opinion, you should provide the advertised methods.
What's the point of the interface otherwise?

Sincerely
Meikel



smime.p7s
Description: S/MIME cryptographic signature


Re: oo

2009-03-29 Thread Meikel Brandmeyer

Hi,

Am 27.03.2009 um 09:25 schrieb Mark Engelberg:


I may come along and want to extend test-prefer to a type ::d which
derives from ::c and ::e, where ::e provides an alternative
implementation.

ab   (a and b are intended to be hidden from  
end-user)

| |
--
   |
   c  e
   |   |
   
|
d


(derive ::d ::c)
(derive ::d ::e)
(defmethod test-prefer ::e [h] "e")

Now, as an external user, I know nothing about where test-prefer on
::c gets its behavior.  Obviously, I have to disambiguate between
whether test-prefer chooses ::c over ::e, so I may try something like
this:
(prefer-method test-prefer ::c ::e)

But this will not work.  I still get an error saying I need to
disambiguate between ::a and ::e.  And not knowing anything about ::a,
I could be very confused, and not know how to provide this
information.


Is there some special reason, why choosing ::c is not enough in
prefer-method? As soon as I preferred ::c over ::e. Why should
I then need to go further up the tree?

Sincerely
Meikel



smime.p7s
Description: S/MIME cryptographic signature


Re: oo

2009-03-29 Thread Konrad Hinsen

On 29.03.2009, at 07:25, mikel wrote:

>> Enjoying the thread. Out of curiosity for which Clojure values is  
>> the return
>> value of the type function undefined?
>
> Try this:
>
> (type (proxy [clojure.lang.IMeta clojure.lang.IRef][]))
>
> java.lang.UnsupportedOperationException: meta (NO_SOURCE_FILE:0)
>   [Thrown class clojure.lang.Compiler$CompilerException]
>
>
> No doubt someone is going to point out that the proxy object I created
> there is useless; that's true, but beside the point.

Not entirely. Your example object is not only useless, it is as close  
as possible to an object created intentionally to cause trouble. You  
create an object that derives from IMeta, thus claiming that it  
handles metadata, but then don't provide an implementation that would  
actually make metadata work.

BTW, the function type could easily be fixed to handle your problem.  
At the moment it does

(or (:type (meta x)) (class x))

Adding an exception handler that returns (class x) whenever (meta x)  
fails would take care of your pathological object. I can't say if  
this would add much runtime overhead, not being much of a JVM expert.

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

2009-03-29 Thread mikel



On Mar 29, 1:34 am, David Nolen  wrote:
> On Sun, Mar 29, 2009 at 1:25 AM, mikel  wrote:
>
> > (type (proxy [clojure.lang.IMeta clojure.lang.IRef][]))
>
> > java.lang.UnsupportedOperationException: meta (NO_SOURCE_FILE:0)
> >  [Thrown class clojure.lang.Compiler$CompilerException]
>
> > No doubt someone is going to point out that the proxy object I created
> > there is useless; that's true, but beside the point. The point is that
> > it's straightforward to create some value v for which (type v) is
> > undefined. In order to make a Clojure-friendly version of CLOS, you
> > need some concept of object type such that you can define a function
> > that returns a sensible type for any value.
>
> Not totally following you here as:
>
> (proxy [clojure.lang.IMeta clojure.lang.IRef][])
>
> immediately throws an error. I can't think of a situation in Clojure where
> the type function does not return a usable value. Let me know if I'm wrong,
> but your example is not a case as far as I can tell.

If you type that expression at the REPL, it throws for the same reason
that calling type on it throws: because the print method for it calls
meta, which is not implemented.
--~--~-~--~~~---~--~~
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: oo

2009-03-29 Thread David Nolen
I see, thanks for the clarification. It does seem like you are purposefully
creating a situation in which type will fail since something more likely:
(type (proxy [clojure.lang.IRef][]))

works fine.

I'm wondering if a CLOS-like system would really have to handle such a
degenerate (in the technical sense :) case as the one you've pointed out?
I'm interested in hearing reasons if there is one.

David

On Sun, Mar 29, 2009 at 5:22 PM, mikel  wrote:

>
>
>
> On Mar 29, 1:34 am, David Nolen  wrote:
> > On Sun, Mar 29, 2009 at 1:25 AM, mikel  wrote:
> >
> > > (type (proxy [clojure.lang.IMeta clojure.lang.IRef][]))
> >
> > > java.lang.UnsupportedOperationException: meta (NO_SOURCE_FILE:0)
> > >  [Thrown class clojure.lang.Compiler$CompilerException]
> >
> > > No doubt someone is going to point out that the proxy object I created
> > > there is useless; that's true, but beside the point. The point is that
> > > it's straightforward to create some value v for which (type v) is
> > > undefined. In order to make a Clojure-friendly version of CLOS, you
> > > need some concept of object type such that you can define a function
> > > that returns a sensible type for any value.
> >
> > Not totally following you here as:
> >
> > (proxy [clojure.lang.IMeta clojure.lang.IRef][])
> >
> > immediately throws an error. I can't think of a situation in Clojure
> where
> > the type function does not return a usable value. Let me know if I'm
> wrong,
> > but your example is not a case as far as I can tell.
>
> If you type that expression at the REPL, it throws for the same reason
> that calling type on it throws: because the print method for it calls
> meta, which is not implemented.
> >
>

--~--~-~--~~~---~--~~
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: oo

2009-03-29 Thread mikel



On Mar 29, 7:22 am, Konrad Hinsen  wrote:
> On 29.03.2009, at 07:25, mikel wrote:
>
> >> Enjoying the thread. Out of curiosity for which Clojure values is  
> >> the return
> >> value of the type function undefined?
>
> > Try this:
>
> > (type (proxy [clojure.lang.IMeta clojure.lang.IRef][]))
>
> > java.lang.UnsupportedOperationException: meta (NO_SOURCE_FILE:0)
> >   [Thrown class clojure.lang.Compiler$CompilerException]
>
> > No doubt someone is going to point out that the proxy object I created
> > there is useless; that's true, but beside the point.
>
> Not entirely. Your example object is not only useless, it is as close  
> as possible to an object created intentionally to cause trouble. You  
> create an object that derives from IMeta, thus claiming that it  
> handles metadata, but then don't provide an implementation that would  
> actually make metadata work.

Sure, that's right. Maybe constructing such a value in the first place
is an error.

The fact remains that it's a Clojure value. If you want to write a
Clojure implementation of CLOS, then you need your dispatching code to
be able to handle all Clojure values. If it doesn't, you have not
written a Clojure implementation of CLOS. This "pathological object"
is a Clojure value. Clojure's "type" function doesn't presently return
a type for such values, so, in order to implement CLOS, you're going
to need to write another type-returning function.

Discussions of whether such values make sense is beside the point. As
long as Clojure allows you to make them, any implementation of CLOS
for Clojure needs to deal with them.

--~--~-~--~~~---~--~~
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: oo

2009-03-29 Thread mikel



On Mar 29, 4:40 pm, David Nolen  wrote:
> I see, thanks for the clarification. It does seem like you are purposefully
> creating a situation in which type will fail since something more likely:
> (type (proxy [clojure.lang.IRef][]))
>
> works fine.
>
> I'm wondering if a CLOS-like system would really have to handle such a
> degenerate (in the technical sense :) case as the one you've pointed out?
> I'm interested in hearing reasons if there is one.

Because the design domain of CLOS is the values of the language for
which it's implemented. If Rich says that an object like the one I
created is not a Clojure value--that constructing such a value is an
error--then it makes sense to implement a version of CLOS that traps
them on input and raises an informative exception. Otherwise, we have
to accept that such values, no matter what we may think of them, are
Clojure values, and any implementation of CLOS for Clojure must do
something sensible with them.
--~--~-~--~~~---~--~~
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: oo

2009-03-30 Thread Konrad Hinsen

On Mar 30, 2009, at 0:16, mikel wrote:

> Sure, that's right. Maybe constructing such a value in the first place
> is an error.

I'd say so. If it were up to me to provide a fix for the situation  
you describe, I'd fix proxy to make it impossible to create an object  
that doesn't implement the interfaces it claims to implement.  
However, it is well possible that such a fix would be difficult,  
impossible, or imply a high run-time penalty. I don't know enough  
about the JVM to judge.

However, I consider this case sufficiently pathological, and highly  
unlikely to occur by mistake, that I'd accept functions raising  
exceptions when presented with such an inconsistent object. In other  
words, I'd declare such objects "not a valid Clojure object", without  
necessarily enforcing that rule at object creation time.

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

2009-03-31 Thread Rich Hickey



On Mar 29, 8:08 am, Meikel Brandmeyer  wrote:
> Hi,
>
> Am 27.03.2009 um 09:25 schrieb Mark Engelberg:
>
>
>
> > I may come along and want to extend test-prefer to a type ::d which
> > derives from ::c and ::e, where ::e provides an alternative
> > implementation.
>
> > ab   (a and b are intended to be hidden from
> > end-user)
> > | |
> > --
> >|
> >c  e
> >|   |
> >
> > |
> > d
>
> > (derive ::d ::c)
> > (derive ::d ::e)
> > (defmethod test-prefer ::e [h] "e")
>
> > Now, as an external user, I know nothing about where test-prefer on
> > ::c gets its behavior.  Obviously, I have to disambiguate between
> > whether test-prefer chooses ::c over ::e, so I may try something like
> > this:
> > (prefer-method test-prefer ::c ::e)
>
> > But this will not work.  I still get an error saying I need to
> > disambiguate between ::a and ::e.  And not knowing anything about ::a,
> > I could be very confused, and not know how to provide this
> > information.
>
> Is there some special reason, why choosing ::c is not enough in
> prefer-method? As soon as I preferred ::c over ::e. Why should
> I then need to go further up the tree?
>

No, this was just a conservative decision on my part, but prefer-
method could prefer the path through ::c and not just ::c and its
descendants. I'm working on supporting this now.

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: OO design in clojure

2010-10-03 Thread Mark Engelberg
The real challenge is to reconceptualize your problem domain into a
non-destructive framework.
In other words, you need to transform your way of thinking from:
move function (or method) takes a Shape and destructively updates the
shape's x and y, returning void
to
move function takes a Shape and returns a new Shape with an updated x and y.

Technically, Object Oriented programming handles both approaches, but
in practice, most OO programmers tend to think of programming in terms
of breaking down problems into objects that destructively update.  So
this is really the big change for most people in how to think about
programming in Clojure.

Once you've figured out a way to work your problem into this way of
thinking, then the details of whether you use multimethods, protocols,
or just a big cond statement dispatching on type, don't matter that
much and can be easily adjusted.  A cond statement works just fine if
you don't care about having other users extend the function to new
types.  Protocols work fine if you don't care about inheritance.
Multimethods handle everything else.

-- 
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: OO Programmer trying to move to Clojure: Encapsulation

2015-02-07 Thread James Reeves
I think there's less difference than you imagine. In C# you might write:

repository.Save(account)

Whereas in Clojure:

(save repository account)

The parameter lists are wider in Clojure only because Clojure doesn't have
an explicit method call syntax.

- James

On 7 February 2015 at 16:07, Dru Sellers  wrote:

> Greetings,
>
> I am trying to convert my mind from OO (C#) to one more functionally
> friendly. I am increasingly comfortable with simple applications in
> clojure, but as I start to build more complex applications, I start to fall
> down about how to structure my application. I don't want to just shove OO
> ideas into the functional nature of Clojure. I'm looking for any help
> someone can provide to help shimmy my brain into the right mental patterns.
>
> Background: Long time C# developer who leans heavily on IoC / DI /
> Interfaces / Testing / Object Encapsulation.
>
>
> *Specific Question: Object Encapsulation*
> I feel like my function parameter lists are much "wider" than they would
> be in C#. This is due to the "lack" of a constructor. So if I previously
> had a C# class that looked like:
>
>
> public class AccountRepository : IAccountRepository
> {
>   IDatabaseConnection _connection;
>
>   public AccountRepository(IDatabaseConnection connection)
>   {
> _connection = connection;
>   }
>
>   public void Save(Account account)
>   {
> _connection.Execute("UPDATE accounts SET coupon=@coupon WHERE id=@id",
> { coupon = account.Coupon, id=account.Id});
>   }
> }
>
> In the above I have encapsulated the "_connection", the other methods
> don't have to deal with it. In Clojure (especially if you are following
> Sierra's Component pattern) you end up with
>
> (defn save [db account]
>   (update db (:coupon account) (:id account))
> )
>
> I end up having to pass this 'db' around all over the place. I think that
> this is just something I'll have to get used to more than anything. Am I
> missing anything?
>
> Thank you for your time.
>
> -d
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: OO Programmer trying to move to Clojure: Encapsulation

2015-02-08 Thread Jony Hudson
To put take a different angle on it: you might soon get to *like* that it's 
usual to pass in everything as a parameter explicitly. It has the advantage 
that it's easy to reason about what a function does just by looking at the 
function. In the example above, when reading AccountRepository.Save you 
need to check elsewhere to see how _connection is defined. Whereas with the 
function save, so long as the parameters you feed in are sensible, then you 
can be pretty sure what it will do.

Making the functions self-contained like this is also a boon when it comes 
to working at the REPL. The OO approach you have often makes it difficult 
(for less trivial examples) to run a particular function in the right 
context. But with the self-contained function it's just a case of getting 
the parameters right, which is often easier to think about.


Jony

On Saturday, 7 February 2015 16:07:45 UTC, Dru Sellers wrote:
>
> Greetings,
>
> I am trying to convert my mind from OO (C#) to one more functionally 
> friendly. I am increasingly comfortable with simple applications in 
> clojure, but as I start to build more complex applications, I start to fall 
> down about how to structure my application. I don't want to just shove OO 
> ideas into the functional nature of Clojure. I'm looking for any help 
> someone can provide to help shimmy my brain into the right mental patterns.
>
> Background: Long time C# developer who leans heavily on IoC / DI / 
> Interfaces / Testing / Object Encapsulation.
>
>
> *Specific Question: Object Encapsulation*
> I feel like my function parameter lists are much "wider" than they would 
> be in C#. This is due to the "lack" of a constructor. So if I previously 
> had a C# class that looked like:
>
>
> public class AccountRepository : IAccountRepository
> {
>   IDatabaseConnection _connection;
>
>   public AccountRepository(IDatabaseConnection connection)
>   {
> _connection = connection;
>   }
>
>   public void Save(Account account)
>   {
> _connection.Execute("UPDATE accounts SET coupon=@coupon WHERE id=@id", 
> { coupon = account.Coupon, id=account.Id});
>   }
> }
>
> In the above I have encapsulated the "_connection", the other methods 
> don't have to deal with it. In Clojure (especially if you are following 
> Sierra's Component pattern) you end up with 
>
> (defn save [db account]
>   (update db (:coupon account) (:id account))
> )
>
> I end up having to pass this 'db' around all over the place. I think that 
> this is just something I'll have to get used to more than anything. Am I 
> missing anything?
>
> Thank you for your time.
>
> -d
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: OO Programmer trying to move to Clojure: Encapsulation

2015-02-08 Thread Colin Yates
+1 This separation of behaviour and state is a key part of Clojure's
philosophy. That isn't to say that stateful components are bad as such
(Stuart Sierra's https://github.com/stuartsierra/component is an
obvious analog here) only that they aren't a given as they are in OO
languages.

As Jony says, when functions only depend on their parameters it makes
many things simpler and more flexible, but can appear 'noisy'.

http://thinkrelevance.com/blog/2009/08/12/rifle-oriented-programming-with-clojure-2
is another good resource here, although I must say I haven't seen some
of those examples in the wild :).

>From a similar background (Java) and having learnt some lessons, I
wish somebody hammered me on the head with the following:
 - get real familiar with the notion of data transformations, particularly maps
 - internalise map, reduce, filter, apply, loop/recur and into
 - before writing any code check the API doesn't already provide it
 - repeat the above three points
 - embrace vanilla maps, they really are all you need (and also watch
https://www.youtube.com/watch?v=ZQkIWWTygio)
 - small functions (10 lines is uncomfortable) always
 - embrace pre/post conditions, documentation (defn doc and
marginalia) and prismatic schema
 - read as much Clojure code as you can get your hands on
 - TDD is still a helpful process/technique in Clojure ;)

Longer term, watch anything from Rich Hickey.

By far the biggest conceptual shift was thinking in terms of data
being the public API and data transformation over blobs of state and
data.

Hope this helps.


On 8 February 2015 at 14:21, Jony Hudson  wrote:
> To put take a different angle on it: you might soon get to *like* that it's
> usual to pass in everything as a parameter explicitly. It has the advantage
> that it's easy to reason about what a function does just by looking at the
> function. In the example above, when reading AccountRepository.Save you need
> to check elsewhere to see how _connection is defined. Whereas with the
> function save, so long as the parameters you feed in are sensible, then you
> can be pretty sure what it will do.
>
> Making the functions self-contained like this is also a boon when it comes
> to working at the REPL. The OO approach you have often makes it difficult
> (for less trivial examples) to run a particular function in the right
> context. But with the self-contained function it's just a case of getting
> the parameters right, which is often easier to think about.
>
>
> Jony
>
>
> On Saturday, 7 February 2015 16:07:45 UTC, Dru Sellers wrote:
>>
>> Greetings,
>>
>> I am trying to convert my mind from OO (C#) to one more functionally
>> friendly. I am increasingly comfortable with simple applications in clojure,
>> but as I start to build more complex applications, I start to fall down
>> about how to structure my application. I don't want to just shove OO ideas
>> into the functional nature of Clojure. I'm looking for any help someone can
>> provide to help shimmy my brain into the right mental patterns.
>>
>> Background: Long time C# developer who leans heavily on IoC / DI /
>> Interfaces / Testing / Object Encapsulation.
>>
>>
>> Specific Question: Object Encapsulation
>> I feel like my function parameter lists are much "wider" than they would
>> be in C#. This is due to the "lack" of a constructor. So if I previously had
>> a C# class that looked like:
>>
>>
>> public class AccountRepository : IAccountRepository
>> {
>>   IDatabaseConnection _connection;
>>
>>   public AccountRepository(IDatabaseConnection connection)
>>   {
>> _connection = connection;
>>   }
>>
>>   public void Save(Account account)
>>   {
>> _connection.Execute("UPDATE accounts SET coupon=@coupon WHERE id=@id",
>> { coupon = account.Coupon, id=account.Id});
>>   }
>> }
>>
>> In the above I have encapsulated the "_connection", the other methods
>> don't have to deal with it. In Clojure (especially if you are following
>> Sierra's Component pattern) you end up with
>>
>> (defn save [db account]
>>   (update db (:coupon account) (:id account))
>> )
>>
>> I end up having to pass this 'db' around all over the place. I think that
>> this is just something I'll have to get used to more than anything. Am I
>> missing anything?
>>
>> Thank you for your time.
>>
>> -d
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with your
> first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.c

Re: OO Programmer trying to move to Clojure: Encapsulation

2015-02-08 Thread Colin Yates
I missed the salient point about data transformations which is that of 
abstractions. In OO (Java at least) almost everything was a special case, 
in Clojure it is the polar opposite; almost nothing is a special case. 

It is astonishing how many domains can be sufficiently modeled as a 
sequence of maps [{..} {..} ...] and can be sufficiently transformed with 
the 'map' function (with assoc/assoc-in).

On Sunday, 8 February 2015 17:16:40 UTC, Colin Yates wrote:
>
> +1 This separation of behaviour and state is a key part of Clojure's 
> philosophy. That isn't to say that stateful components are bad as such 
> (Stuart Sierra's https://github.com/stuartsierra/component is an 
> obvious analog here) only that they aren't a given as they are in OO 
> languages. 
>
> As Jony says, when functions only depend on their parameters it makes 
> many things simpler and more flexible, but can appear 'noisy'. 
>
>
> http://thinkrelevance.com/blog/2009/08/12/rifle-oriented-programming-with-clojure-2
>  
> is another good resource here, although I must say I haven't seen some 
> of those examples in the wild :). 
>
> From a similar background (Java) and having learnt some lessons, I 
> wish somebody hammered me on the head with the following: 
>  - get real familiar with the notion of data transformations, particularly 
> maps 
>  - internalise map, reduce, filter, apply, loop/recur and into 
>  - before writing any code check the API doesn't already provide it 
>  - repeat the above three points 
>  - embrace vanilla maps, they really are all you need (and also watch 
> https://www.youtube.com/watch?v=ZQkIWWTygio) 
>  - small functions (10 lines is uncomfortable) always 
>  - embrace pre/post conditions, documentation (defn doc and 
> marginalia) and prismatic schema 
>  - read as much Clojure code as you can get your hands on 
>  - TDD is still a helpful process/technique in Clojure ;) 
>
> Longer term, watch anything from Rich Hickey. 
>
> By far the biggest conceptual shift was thinking in terms of data 
> being the public API and data transformation over blobs of state and 
> data. 
>
> Hope this helps. 
>
>
> On 8 February 2015 at 14:21, Jony Hudson  wrote: 
> > To put take a different angle on it: you might soon get to *like* that 
> it's 
> > usual to pass in everything as a parameter explicitly. It has the 
> advantage 
> > that it's easy to reason about what a function does just by looking at 
> the 
> > function. In the example above, when reading AccountRepository.Save you 
> need 
> > to check elsewhere to see how _connection is defined. Whereas with the 
> > function save, so long as the parameters you feed in are sensible, then 
> you 
> > can be pretty sure what it will do. 
> > 
> > Making the functions self-contained like this is also a boon when it 
> comes 
> > to working at the REPL. The OO approach you have often makes it 
> difficult 
> > (for less trivial examples) to run a particular function in the right 
> > context. But with the self-contained function it's just a case of 
> getting 
> > the parameters right, which is often easier to think about. 
> > 
> > 
> > Jony 
> > 
> > 
> > On Saturday, 7 February 2015 16:07:45 UTC, Dru Sellers wrote: 
> >> 
> >> Greetings, 
> >> 
> >> I am trying to convert my mind from OO (C#) to one more functionally 
> >> friendly. I am increasingly comfortable with simple applications in 
> clojure, 
> >> but as I start to build more complex applications, I start to fall down 
> >> about how to structure my application. I don't want to just shove OO 
> ideas 
> >> into the functional nature of Clojure. I'm looking for any help someone 
> can 
> >> provide to help shimmy my brain into the right mental patterns. 
> >> 
> >> Background: Long time C# developer who leans heavily on IoC / DI / 
> >> Interfaces / Testing / Object Encapsulation. 
> >> 
> >> 
> >> Specific Question: Object Encapsulation 
> >> I feel like my function parameter lists are much "wider" than they 
> would 
> >> be in C#. This is due to the "lack" of a constructor. So if I 
> previously had 
> >> a C# class that looked like: 
> >> 
> >> 
> >> public class AccountRepository : IAccountRepository 
> >> { 
> >>   IDatabaseConnection _connection; 
> >> 
> >>   public AccountRepository(IDatabaseConnection connection) 
> >>   { 
> >> _connection = connection; 
> >>   } 
> >> 
> >>   public void Save(Account account) 
> >>   { 
> >> _connection.Execute("UPDATE accounts SET coupon=@coupon WHERE 
> id=@id", 
> >> { coupon = account.Coupon, id=account.Id}); 
> >>   } 
> >> } 
> >> 
> >> In the above I have encapsulated the "_connection", the other methods 
> >> don't have to deal with it. In Clojure (especially if you are following 
> >> Sierra's Component pattern) you end up with 
> >> 
> >> (defn save [db account] 
> >>   (update db (:coupon account) (:id account)) 
> >> ) 
> >> 
> >> I end up having to pass this 'db' around all over the place. I think 
> that 
> >> this is just something I'll have

Re: OO Programmer trying to move to Clojure: Encapsulation

2015-02-09 Thread Henrik Eneroth
If you find yourself passing the same argument over and over, you can 
always work in a partial:

(def save-account (partial save db))


On Sunday, February 8, 2015 at 6:47:29 PM UTC+1, Colin Yates wrote:
>
> I missed the salient point about data transformations which is that of 
> abstractions. In OO (Java at least) almost everything was a special case, 
> in Clojure it is the polar opposite; almost nothing is a special case. 
>
> It is astonishing how many domains can be sufficiently modeled as a 
> sequence of maps [{..} {..} ...] and can be sufficiently transformed with 
> the 'map' function (with assoc/assoc-in).
>
> On Sunday, 8 February 2015 17:16:40 UTC, Colin Yates wrote:
>>
>> +1 This separation of behaviour and state is a key part of Clojure's 
>> philosophy. That isn't to say that stateful components are bad as such 
>> (Stuart Sierra's https://github.com/stuartsierra/component is an 
>> obvious analog here) only that they aren't a given as they are in OO 
>> languages. 
>>
>> As Jony says, when functions only depend on their parameters it makes 
>> many things simpler and more flexible, but can appear 'noisy'. 
>>
>>
>> http://thinkrelevance.com/blog/2009/08/12/rifle-oriented-programming-with-clojure-2
>>  
>> is another good resource here, although I must say I haven't seen some 
>> of those examples in the wild :). 
>>
>> From a similar background (Java) and having learnt some lessons, I 
>> wish somebody hammered me on the head with the following: 
>>  - get real familiar with the notion of data transformations, 
>> particularly maps 
>>  - internalise map, reduce, filter, apply, loop/recur and into 
>>  - before writing any code check the API doesn't already provide it 
>>  - repeat the above three points 
>>  - embrace vanilla maps, they really are all you need (and also watch 
>> https://www.youtube.com/watch?v=ZQkIWWTygio) 
>>  - small functions (10 lines is uncomfortable) always 
>>  - embrace pre/post conditions, documentation (defn doc and 
>> marginalia) and prismatic schema 
>>  - read as much Clojure code as you can get your hands on 
>>  - TDD is still a helpful process/technique in Clojure ;) 
>>
>> Longer term, watch anything from Rich Hickey. 
>>
>> By far the biggest conceptual shift was thinking in terms of data 
>> being the public API and data transformation over blobs of state and 
>> data. 
>>
>> Hope this helps. 
>>
>>
>> On 8 February 2015 at 14:21, Jony Hudson > > wrote: 
>> > To put take a different angle on it: you might soon get to *like* that 
>> it's 
>> > usual to pass in everything as a parameter explicitly. It has the 
>> advantage 
>> > that it's easy to reason about what a function does just by looking at 
>> the 
>> > function. In the example above, when reading AccountRepository.Save you 
>> need 
>> > to check elsewhere to see how _connection is defined. Whereas with the 
>> > function save, so long as the parameters you feed in are sensible, then 
>> you 
>> > can be pretty sure what it will do. 
>> > 
>> > Making the functions self-contained like this is also a boon when it 
>> comes 
>> > to working at the REPL. The OO approach you have often makes it 
>> difficult 
>> > (for less trivial examples) to run a particular function in the right 
>> > context. But with the self-contained function it's just a case of 
>> getting 
>> > the parameters right, which is often easier to think about. 
>> > 
>> > 
>> > Jony 
>> > 
>> > 
>> > On Saturday, 7 February 2015 16:07:45 UTC, Dru Sellers wrote: 
>> >> 
>> >> Greetings, 
>> >> 
>> >> I am trying to convert my mind from OO (C#) to one more functionally 
>> >> friendly. I am increasingly comfortable with simple applications in 
>> clojure, 
>> >> but as I start to build more complex applications, I start to fall 
>> down 
>> >> about how to structure my application. I don't want to just shove OO 
>> ideas 
>> >> into the functional nature of Clojure. I'm looking for any help 
>> someone can 
>> >> provide to help shimmy my brain into the right mental patterns. 
>> >> 
>> >> Background: Long time C# developer who leans heavily on IoC / DI / 
>> >> Interfaces / Testing / Object Encapsulation. 
>> >> 
>> >> 
>> >> Specific Question: Object Encapsulation 
>> >> I feel like my function parameter lists are much "wider" than they 
>> would 
>> >> be in C#. This is due to the "lack" of a constructor. So if I 
>> previously had 
>> >> a C# class that looked like: 
>> >> 
>> >> 
>> >> public class AccountRepository : IAccountRepository 
>> >> { 
>> >>   IDatabaseConnection _connection; 
>> >> 
>> >>   public AccountRepository(IDatabaseConnection connection) 
>> >>   { 
>> >> _connection = connection; 
>> >>   } 
>> >> 
>> >>   public void Save(Account account) 
>> >>   { 
>> >> _connection.Execute("UPDATE accounts SET coupon=@coupon WHERE 
>> id=@id", 
>> >> { coupon = account.Coupon, id=account.Id}); 
>> >>   } 
>> >> } 
>> >> 
>> >> In the above I have encapsulated the "_connection", the other methods 
>> >> don

Re: OO Programmer trying to move to Clojure: Encapsulation

2015-02-09 Thread Gregg Williams
@Dru, I feel I'm ahead of you in learning Clojure, but I'm not yet to where 
@Colin is. However, I'm close enough that I recognize how accurate and 
concise his advice is--in fact, I'm saving it to remind myself!

Also, I just finished reading Functional Programming Patterns in Scala and 
Clojure, by Michael Bevilacqua-Linn (Pragmatic Programmer, publisher). In 
it, he takes standard OO patterns, gives Java examples, then shows how the 
same things are accomplished in functional style in Scala and Clojure. I 
found it to be very instructive.

A similar book by Brian Marick, a well-known Clojure programmer, is at 
https://leanpub.com/fp-oo. I haven't read it, but it looks promising.

Good luck on your learning!

-- Gregg

On Sunday, February 8, 2015 at 9:16:40 AM UTC-8, Colin Yates wrote:
>
> +1 This separation of behaviour and state is a key part of Clojure's 
> philosophy. That isn't to say that stateful components are bad as such 
> (Stuart Sierra's https://github.com/stuartsierra/component is an 
> obvious analog here) only that they aren't a given as they are in OO 
> languages. 
>
> As Jony says, when functions only depend on their parameters it makes 
> many things simpler and more flexible, but can appear 'noisy'. 
>
>
> http://thinkrelevance.com/blog/2009/08/12/rifle-oriented-programming-with-clojure-2
>  
> is another good resource here, although I must say I haven't seen some 
> of those examples in the wild :). 
>
> From a similar background (Java) and having learnt some lessons, I 
> wish somebody hammered me on the head with the following: 
>  - get real familiar with the notion of data transformations, particularly 
> maps 
>  - internalise map, reduce, filter, apply, loop/recur and into 
>  - before writing any code check the API doesn't already provide it 
>  - repeat the above three points 
>  - embrace vanilla maps, they really are all you need (and also watch 
> https://www.youtube.com/watch?v=ZQkIWWTygio) 
>  - small functions (10 lines is uncomfortable) always 
>  - embrace pre/post conditions, documentation (defn doc and 
> marginalia) and prismatic schema 
>  - read as much Clojure code as you can get your hands on 
>  - TDD is still a helpful process/technique in Clojure ;) 
>
> Longer term, watch anything from Rich Hickey. 
>
> By far the biggest conceptual shift was thinking in terms of data 
> being the public API and data transformation over blobs of state and 
> data. 
>
> Hope this helps. 
>
>
> On 8 February 2015 at 14:21, Jony Hudson > 
> wrote: 
> > To put take a different angle on it: you might soon get to *like* that 
> it's 
> > usual to pass in everything as a parameter explicitly. It has the 
> advantage 
> > that it's easy to reason about what a function does just by looking at 
> the 
> > function. In the example above, when reading AccountRepository.Save you 
> need 
> > to check elsewhere to see how _connection is defined. Whereas with the 
> > function save, so long as the parameters you feed in are sensible, then 
> you 
> > can be pretty sure what it will do. 
> > 
> > Making the functions self-contained like this is also a boon when it 
> comes 
> > to working at the REPL. The OO approach you have often makes it 
> difficult 
> > (for less trivial examples) to run a particular function in the right 
> > context. But with the self-contained function it's just a case of 
> getting 
> > the parameters right, which is often easier to think about. 
> > 
> > 
> > Jony 
> > 
> > 
> > On Saturday, 7 February 2015 16:07:45 UTC, Dru Sellers wrote: 
> >> 
> >> Greetings, 
> >> 
> >> I am trying to convert my mind from OO (C#) to one more functionally 
> >> friendly. I am increasingly comfortable with simple applications in 
> clojure, 
> >> but as I start to build more complex applications, I start to fall down 
> >> about how to structure my application. I don't want to just shove OO 
> ideas 
> >> into the functional nature of Clojure. I'm looking for any help someone 
> can 
> >> provide to help shimmy my brain into the right mental patterns. 
> >> 
> >> Background: Long time C# developer who leans heavily on IoC / DI / 
> >> Interfaces / Testing / Object Encapsulation. 
> >> 
> >> 
> >> Specific Question: Object Encapsulation 
> >> I feel like my function parameter lists are much "wider" than they 
> would 
> >> be in C#. This is due to the "lack" of a constructor. So if I 
> previously had 
> >> a C# class that looked like: 
> >> 
> >> 
> >> public class AccountRepository : IAccountRepository 
> >> { 
> >>   IDatabaseConnection _connection; 
> >> 
> >>   public AccountRepository(IDatabaseConnection connection) 
> >>   { 
> >> _connection = connection; 
> >>   } 
> >> 
> >>   public void Save(Account account) 
> >>   { 
> >> _connection.Execute("UPDATE accounts SET coupon=@coupon WHERE 
> id=@id", 
> >> { coupon = account.Coupon, id=account.Id}); 
> >>   } 
> >> } 
> >> 
> >> In the above I have encapsulated the "_connection", the other methods 
> >> don't hav

Re: OO Programmer trying to move to Clojure: Encapsulation

2015-02-11 Thread Dru Sellers
Thank you everyone for all of the helpful ideas.

I def like the Component library and I will have to sit down and figure out 
how to best work that into my application while it is still young.
All of the links have been consumed and I am starting to absorb more and 
more. Thank you for taking the time to share your thoughts and ideas with 
me.

-d

On Saturday, February 7, 2015 at 10:07:45 AM UTC-6, Dru Sellers wrote:
>
> Greetings,
>
> I am trying to convert my mind from OO (C#) to one more functionally 
> friendly. I am increasingly comfortable with simple applications in 
> clojure, but as I start to build more complex applications, I start to fall 
> down about how to structure my application. I don't want to just shove OO 
> ideas into the functional nature of Clojure. I'm looking for any help 
> someone can provide to help shimmy my brain into the right mental patterns.
>
> Background: Long time C# developer who leans heavily on IoC / DI / 
> Interfaces / Testing / Object Encapsulation.
>
>
> *Specific Question: Object Encapsulation*
> I feel like my function parameter lists are much "wider" than they would 
> be in C#. This is due to the "lack" of a constructor. So if I previously 
> had a C# class that looked like:
>
>
> public class AccountRepository : IAccountRepository
> {
>   IDatabaseConnection _connection;
>
>   public AccountRepository(IDatabaseConnection connection)
>   {
> _connection = connection;
>   }
>
>   public void Save(Account account)
>   {
> _connection.Execute("UPDATE accounts SET coupon=@coupon WHERE id=@id", 
> { coupon = account.Coupon, id=account.Id});
>   }
> }
>
> In the above I have encapsulated the "_connection", the other methods 
> don't have to deal with it. In Clojure (especially if you are following 
> Sierra's Component pattern) you end up with 
>
> (defn save [db account]
>   (update db (:coupon account) (:id account))
> )
>
> I end up having to pass this 'db' around all over the place. I think that 
> this is just something I'll have to get used to more than anything. Am I 
> missing anything?
>
> Thank you for your time.
>
> -d
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: OO Programmer trying to move to Clojure: Encapsulation

2015-02-11 Thread Herwig Hochleitner
Hm, the most common way to encapsulate in clojure is with a closure:

Your account repository would be:

(defn account-repository [connection]
  ;; <- here goes additional constructor logic
  (fn save [account]
(sql-save connection account))

If the repository has more methods than just save, you can return a map of
functions, or an implementation of a protocol / interface.

In my experience, component is most useful when talking to stateful APIs at
the fringes of the application. There you need lifecycle methods to let the
user (or system) nudge the application from one state to the next,
observing and doing stuff along the edges. But the meat of an application
(calculating what to do) can normally be stateless functions over data.

A recent alternative for when there are only two lifecycle events around a
single updater method (construct, finish, step), are transducers.

hth, kind regards
​

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: OO Programmer trying to move to Clojure: Namespace Organization

2015-02-08 Thread Atamert Ölçgen
Hi Dru,

I find it easier to organize things when I follow TDD. It's easier for me
to spot something is in the wrong place (module or maybe as a
responsibility of a function) by looking at the tests. (This is true for
any language I work with.)

http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd


On Sat, Feb 7, 2015 at 6:23 PM, Dru Sellers  wrote:

> Greetings,
>
> I am trying to convert my mind from OO (C#) to one more functionally
> friendly. I am increasingly comfortable with simple applications in
> clojure, but as I start to build more complex applications, I start to fall
> down about how to structure my application. I don't want to just shove OO
> ideas into the functional nature of Clojure. I'm looking for any help
> someone can provide to help shimmy my brain into the right mental patterns.
>
> Background: Long time C# developer who leans heavily on IoC / DI /
> Interfaces / Testing / Object Encapsulation.
>
> Specific Questions: Namespace Organization
>
> Now I know this is almost entirely personal preference, but I'm playing
> with a namespace model that looks like this and I'd love some feed back.
> Tear it about, bust that red pen out and help me to better think of things
> in clojure way. I only have my C# / OO background to lean on and need some
> fresh brain juice. :)
>
> I currently organize my projects like this. a spin off of 'duct'
> https://github.com/weavejester/duct but i'm looking for a bit more detail.
>
> Context: Project name is going to be "ford", feature is going to be a
> simple log of text
>
>
> ~/
>   src/
> ford/ - the project
>   log/ - the feature name
> http.clj - contains clojure routes at 'http/routes' - orchestrate
> the business calls
> model.clj - contains my 'defrecords' / yesql / db calls
> core.clj - the "business" calls
>
>
> I def have a preference for shorter files rather than longer files
> I also tend to have a heavy use of 'ceremony' - right now I need a lot of
> structure because I'm still learning to think in terms of clojure. and I
> spend a lot of time still reading it rather than thinking about it.
>
> Again, thank you.
>
> -d
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>



-- 
Kind Regards,
Atamert Ölçgen

-+-
--+
+++

www.muhuk.com

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: OO Programmer trying to move to Clojure: Namespace Organization

2015-02-08 Thread Timothy Baldridge
When I first came to Clojure (from C# of all things), I had questions like
this too. But over time I've become convinced that it was something I
worried to much about. The guiding rule for code organization should be
this: does it slow you down from the complexity? Are there so many files,
that you're constantly context switching from one file to another? Are
there so few files that you're having problems introducing new programmers
to the code. I don't think there's any one size fits all solution to this.
I think it's different from one project to another.

I have clojure files with just 4 lines of code, and others with 3000 lines
of code (that's a lot for Clojure). It's also not hard to refactor these
things when needed. Especially if you don't use :refer :all in your
namespace declarations. Use one of these forms:

(ns my-ns
  (:require [foo.bar :as f]
[foo.baz :refer [qux qox]]))

Both of these allow for rather quick namespace conversion. If a function
moves locations, it's fairly easy to just do a find/replace on the code.
And the Clojure compiler will also help you, complaining about undefined
vars.

I hope this helps, in short, relax, it's not as big of a problem as it
seems.

Timothy

On Sun, Feb 8, 2015 at 2:48 AM, Atamert Ölçgen  wrote:

> Hi Dru,
>
> I find it easier to organize things when I follow TDD. It's easier for me
> to spot something is in the wrong place (module or maybe as a
> responsibility of a function) by looking at the tests. (This is true for
> any language I work with.)
>
> http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
>
>
> On Sat, Feb 7, 2015 at 6:23 PM, Dru Sellers  wrote:
>
>> Greetings,
>>
>> I am trying to convert my mind from OO (C#) to one more functionally
>> friendly. I am increasingly comfortable with simple applications in
>> clojure, but as I start to build more complex applications, I start to fall
>> down about how to structure my application. I don't want to just shove OO
>> ideas into the functional nature of Clojure. I'm looking for any help
>> someone can provide to help shimmy my brain into the right mental patterns.
>>
>> Background: Long time C# developer who leans heavily on IoC / DI /
>> Interfaces / Testing / Object Encapsulation.
>>
>> Specific Questions: Namespace Organization
>>
>> Now I know this is almost entirely personal preference, but I'm playing
>> with a namespace model that looks like this and I'd love some feed back.
>> Tear it about, bust that red pen out and help me to better think of things
>> in clojure way. I only have my C# / OO background to lean on and need some
>> fresh brain juice. :)
>>
>> I currently organize my projects like this. a spin off of 'duct'
>> https://github.com/weavejester/duct but i'm looking for a bit more
>> detail.
>>
>> Context: Project name is going to be "ford", feature is going to be a
>> simple log of text
>>
>>
>> ~/
>>   src/
>> ford/ - the project
>>   log/ - the feature name
>> http.clj - contains clojure routes at 'http/routes' - orchestrate
>> the business calls
>> model.clj - contains my 'defrecords' / yesql / db calls
>> core.clj - the "business" calls
>>
>>
>> I def have a preference for shorter files rather than longer files
>> I also tend to have a heavy use of 'ceremony' - right now I need a lot of
>> structure because I'm still learning to think in terms of clojure. and I
>> spend a lot of time still reading it rather than thinking about it.
>>
>> Again, thank you.
>>
>> -d
>>
>> --
>> You received this message because you are subscribed to the Google
>> Groups "Clojure" group.
>> To post to this group, send email to clojure@googlegroups.com
>> Note that posts from new members are moderated - please be patient with
>> your first post.
>> To unsubscribe from this group, send email to
>> clojure+unsubscr...@googlegroups.com
>> For more options, visit this group at
>> http://groups.google.com/group/clojure?hl=en
>> ---
>> You received this message because you are subscribed to the Google Groups
>> "Clojure" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to clojure+unsubscr...@googlegroups.com.
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>
>
> --
> Kind Regards,
> Atamert Ölçgen
>
> -+-
> --+
> +++
>
> www.muhuk.com
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For 

Re: OO Programmer trying to move to Clojure: Namespace Organization

2015-02-08 Thread David James
I often group functions that operate on similar data structures together in 
a namespace. This isn't always clear-cut, because some functions may "fit" 
in more than one namespace. I sometimes use a (soft) convention to group 
functions by the first argument. Yes, this means that my Clojure projects 
resemble OO projects, at least in terms of what logic goes where. See what 
works for you.

Some Clojure projects I see use fairly long files. I tend to prefer smaller 
files myself. In my opinion, just as a function that is too long often 
indicates unnecessary complexity, I think files/namespaces that are too 
large indicates a complicated design.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: OO Programmer trying to move to Clojure: Namespace Organization

2015-02-08 Thread Sean Corfield
On Feb 8, 2015, at 6:42 PM, David James  wrote:
> I often group functions that operate on similar data structures together in a 
> namespace. This isn't always clear-cut, because some functions may "fit" in 
> more than one namespace. I sometimes use a (soft) convention to group 
> functions by the first argument. Yes, this means that my Clojure projects 
> resemble OO projects, at least in terms of what logic goes where. See what 
> works for you.

At World Singles we’ve ended up with just over 40 main namespaces that  
correspond to the major "domain concepts" in our application, with a handful of 
more generic names that match external system integration points or clearly 
defined subsystems, and then sub-namespaces for implementation variants and 
general decomposition (e.g., worldsingles.payment, 
worldsingles.payment.braintree, worldsingles.payment.sbw, 
worldsingles.transparensee - search engine, worldsingles.data - our general 
persistence layer). Our average namespace is about 200 lines long (we have just 
over 100 namespaces in our main app - they range from 16 lines to 1,266).

Sean Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/

"Perfection is the enemy of the good."
-- Gustave Flaubert, French realist novelist (1821-1880)



-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: OO Programmer trying to move to Clojure: Namespace Organization

2015-02-11 Thread Dru Sellers
Yeah, it wouldn't surprise me if I'm over thinking it too much. But in the 
model of 'shu-ha-ri' I am still very much in the shu stage so i'm looking 
for concrete stuff to imitate. :) 

Thank you everyone for the ideas and thoughts,

-d

On Saturday, February 7, 2015 at 10:23:43 AM UTC-6, Dru Sellers wrote:
>
> Greetings,
>
> I am trying to convert my mind from OO (C#) to one more functionally 
> friendly. I am increasingly comfortable with simple applications in 
> clojure, but as I start to build more complex applications, I start to fall 
> down about how to structure my application. I don't want to just shove OO 
> ideas into the functional nature of Clojure. I'm looking for any help 
> someone can provide to help shimmy my brain into the right mental patterns.
>
> Background: Long time C# developer who leans heavily on IoC / DI / 
> Interfaces / Testing / Object Encapsulation.
>
> Specific Questions: Namespace Organization
>
> Now I know this is almost entirely personal preference, but I'm playing 
> with a namespace model that looks like this and I'd love some feed back. 
> Tear it about, bust that red pen out and help me to better think of things 
> in clojure way. I only have my C# / OO background to lean on and need some 
> fresh brain juice. :)
>
> I currently organize my projects like this. a spin off of 'duct' 
> https://github.com/weavejester/duct but i'm looking for a bit more detail.
>
> Context: Project name is going to be "ford", feature is going to be a 
> simple log of text
>
>
> ~/
>   src/
> ford/ - the project
>   log/ - the feature name
> http.clj - contains clojure routes at 'http/routes' - orchestrate 
> the business calls
> model.clj - contains my 'defrecords' / yesql / db calls
> core.clj - the "business" calls
>
>
> I def have a preference for shorter files rather than longer files
> I also tend to have a heavy use of 'ceremony' - right now I need a lot of 
> structure because I'm still learning to think in terms of clojure. and I 
> spend a lot of time still reading it rather than thinking about it.
>
> Again, thank you.
>
> -d
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: OO Programmer trying to move to Clojure: Namespace Organization

2015-02-11 Thread Colin Yates
I wouldn't get too hung up on imitation as whilst there are style
guides [1] I you will find a lot of diversity in "published" Clojure
code.

I would suggest you internalise the style guide, lean on "lein kibit"
and "lein eastwood" and then do some navel gazing and ask yourself
what problem you are trying to solve. Not to get all meta, but I often
find seemingly "obvious" questions can hide a whole bunch of risk and
complexity.

For example, some answers (as to why you are looking for this
"standardisation") are:
 - I obsess over details whilst not actually caring about the answer -
somebody just make a decision!
 - I care very much about this and have a strong opinion on how I
should do it but I want to make sure I am not in conflict with prior
art
 - I plan on publishing this work and want the lowest barrier to entry
 - I want to make this future proof and/or I have a team of people who
all need to find this intuitive

and so on. Each answer would leave to a slightly different direction.

Alternatively, ignore completely the above (except the style guide and
lein references ;)), grab a cup of coffee and just start writing some
code :)

[1] https://duckduckgo.com/?t=lm&q=clojure+style+guide

On 11 February 2015 at 15:21, Dru Sellers  wrote:
> Yeah, it wouldn't surprise me if I'm over thinking it too much. But in the
> model of 'shu-ha-ri' I am still very much in the shu stage so i'm looking
> for concrete stuff to imitate. :)
>
> Thank you everyone for the ideas and thoughts,
>
> -d
>
>
> On Saturday, February 7, 2015 at 10:23:43 AM UTC-6, Dru Sellers wrote:
>>
>> Greetings,
>>
>> I am trying to convert my mind from OO (C#) to one more functionally
>> friendly. I am increasingly comfortable with simple applications in clojure,
>> but as I start to build more complex applications, I start to fall down
>> about how to structure my application. I don't want to just shove OO ideas
>> into the functional nature of Clojure. I'm looking for any help someone can
>> provide to help shimmy my brain into the right mental patterns.
>>
>> Background: Long time C# developer who leans heavily on IoC / DI /
>> Interfaces / Testing / Object Encapsulation.
>>
>> Specific Questions: Namespace Organization
>>
>> Now I know this is almost entirely personal preference, but I'm playing
>> with a namespace model that looks like this and I'd love some feed back.
>> Tear it about, bust that red pen out and help me to better think of things
>> in clojure way. I only have my C# / OO background to lean on and need some
>> fresh brain juice. :)
>>
>> I currently organize my projects like this. a spin off of 'duct'
>> https://github.com/weavejester/duct but i'm looking for a bit more detail.
>>
>> Context: Project name is going to be "ford", feature is going to be a
>> simple log of text
>>
>>
>> ~/
>>   src/
>> ford/ - the project
>>   log/ - the feature name
>> http.clj - contains clojure routes at 'http/routes' - orchestrate
>> the business calls
>> model.clj - contains my 'defrecords' / yesql / db calls
>> core.clj - the "business" calls
>>
>>
>> I def have a preference for shorter files rather than longer files
>> I also tend to have a heavy use of 'ceremony' - right now I need a lot of
>> structure because I'm still learning to think in terms of clojure. and I
>> spend a lot of time still reading it rather than thinking about it.
>>
>> Again, thank you.
>>
>> -d
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with your
> first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


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



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

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

2009-03-31 Thread Rich Hickey

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

A) They provide only a single declaration point for all superclasses
of a class
B) They consider the local declaration order of superclasses to be
significant
C) They conflate hierarchies and graphs containing sideways edges
having nothing to do with hierarchy
D) They provide only a single slot for type/class per object
E) They allow conflicting local superclass declaration orders,
creating cycles in the graph not detected until subsequent derivation

Image:

(class Horse :supers [Animal])

Now suppose some user of Horses, but not the library author, wants to
consider Horses to be Transportation. Due to (A) they can't, without
convincing the author of the library to change the declaration to
include Transportation in the supers:

(class Horse :supers [Animal Transportation])

Here's where (B) rears its ugly head. At this point in time there may
be no significant basis for determining the order in which these
declarations should occur. It is not an inherent property of the
derivation relationship (C), but must be specified here and now due to
the fact that the derivation declaration does 2 jobs (derivation +
precedence). It might never matter, but if it does matter it will be
because eventually some method is defined on both Animal and
Transportation, and a decision needs to be made as to which should
apply to Horse, e.g.:

(allowed-on-road Animal) -> false
(allowed-on-road Transportation) -> true

in order to make (allowed-on-road Horse) work the way we want (i.e.
true), and presuming we want to inherit our behavior rather than
specify it (the laziness presumption), we'd prefer Transportation
precede Animal in the supers declaration of Horse. Another trip to the
library author.

Here's where (D) rears its ugly head - this is a global declaration
that universally applies. One could easily imagine another method
where it would be preferable that Animal preceded Transportation when
applied to Horses (the library author might say no)

As for (E), if we later create:

(class Camel :supers [Transportation Animal])

no advances in genetics can allow us to make a HorseCamel, since the
resulting graph can't be ordered. (We can't put HC on the front of a
merge of H->A->T and C->T->A that preserves their relative orders)

These are just OO devices, not logical systems - they are just
arbitrary mechanisms full of corner cases and creeping complexity. I
don't know why we are in such a hurry to recreate them.


Here's how I think about it:

- Hierarchies have nothing to do with multimethods/GFs per se.
- They are created by independent, atomic, logical statements about
derivation relationships
- Those statements can come in any order, or place
- The logical statements are validated to not create cycles (i.e. when
considered as a set of logical assertions, they include a transitivity
rule and one asserting a parent can't be a child of its child, plus a
consistency check)

This gives us a nice logical construct with general applicability.

We can then think about leveraging hierarchy in a dispatch mechanism.
Using a hierarchical system in dispatch matching means we can inherit
behavior, and, within a lineage, ensures a logical precedence due to
the, well, linear nature of lineages. Multiple inheritance is also not
a problem, as separate multimethods can be defined on separate trees
without conflict or ambiguity.

It is only when you have defined methods of the same multimethod on
two independent paths to the same child that things cannot be
logically resolved. This is something you should do only with great
reluctance, as it represents a true logical ambiguity, e.g. you've
said animals aren't allowed in the street, but transportation is, and
a horse is both. I still contend you'll encounter it most frequently
when trying to incorporate existing Java hierarchies. If you find you
need it frequently other than in that case, you have a sloppy design
IMO.

A monotonic ordering of the entire graph is not an essential property
of a hierarchy, in fact, I think it is more of a crutch than a
feature. Making logical ambiguities go away mechanically only
encourages more ambiguity and brittleness in the dependencies on the
mechanical resolution.

So, when there's an ambiguity we can always define a specific method,
and usually should. Being lazy, we also have prefer-method to resolve
it in favor of one inherited method, at the point we have the facts
about the particular ambiguity, and differently for each method if we
desire.

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.

- Currently, a preference doesn't encompass the path through the
preferred value to its anc

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

2009-03-31 Thread mikel



On Mar 31, 9:32 am, Rich Hickey  wrote:


> Can we please move forward in trying to implement something better
> than CLOS GFs?

Maybe. Let me know when you think of something better, and I'll do the
same. When we agree, I'll toss my GF implementation out the door. In
the meantime, it's made my life better, so I'll keep using it. I can
stop talking about it in the Clojure group, if you like.

> I have no interest in going backwards.

Nice. Me either. I'll do my own navigating, though. I just got my
HorseCamel out of the weeds.
--~--~-~--~~~---~--~~
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 Laurent PETIT
Hi,

2009/3/31 Rich Hickey 

> Here's how I think about it:
>
> - Hierarchies have nothing to do with multimethods/GFs per se.


True,

So, along the lines of my previous post, could it be made possible to let
the user provide its own multimethods "candidate dispatch-values filtering"
and "candidate dispatch-values narrowing" if needed ?

And also, maybe, try to not add hierarchies concerns in general multimethods
declarations :
Currently, defmulti accepts a hierarchy as an optional parameter, and it
seems to me that it contradicts what you wrote above, that "Hierarchies have
nothing to do with multimethods/GFs per se."

Or maybe it's a problem with my comprehension of a subtlety of english ?

Making multimethods more generic could also help the clojure ecosystem work
on a solution to the problem of multimethods working on hierarchies (which
could still be made the default "flavor" of multimethods, thus allowing the
'hierarchy' optional parameter to remain valid with the "clojure
hierarchies" multimethods flavor), while still starting from the same
"building block".


Sorry for using this thread as a way to speak one more time about the
possibility to make multimethods more general, but since nobody reacted to
my previous posts either bashing me or plussing me, I'm still not knowing if
you consider it a good idea or not, and for which reasons.

Regards,

-- 
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
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 David Nolen
Many thanks for the long and reasoned reply (and to mikel as well for adding
his thoughts). I apologize for my slowness in understanding the nature of
multimethods- it's tricky converting my existing knowledge ;)

On Tue, Mar 31, 2009 at 10:32 AM, Rich Hickey  wrote:
>
>
> 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.


This is the last bit of multimethod reflection I would love to see.
Combining prefers and this feature would make it simple to provide
functionality like call-next-method/super in a performant way (I believe).


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


This would be awesome.


>
>
> Can we please move forward in trying to implement something better
> than CLOS GFs? I have no interest in going backwards.
>
> Rich


I'm ready to move on, and these thoughts sound great. Onward! ;)

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



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

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  wrote:
> On Mar 31, 11:45 am, Konrad Hinsen  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,

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
>  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-31 Thread mikel



On Mar 31, 2:25 pm, Rich Hickey  wrote:
> On Mar 31, 2:18 pm, mikel  wrote:


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

Those are different names for the same pieces.

> This is simply an exhausting amount of talk - how about a prototype?

I promised to stop talking about my gf implementation.

> I'm skeptical there will be much utility left in the harness that
> hosted all of these plugin components. With no knowledge of how the
> pieces fit, it couldn't even do the most basic cache management or
> consistency checking jobs.

Okay. It works for me. No one else has to use it.
--~--~-~--~~~---~--~~
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 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
>>  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 Rich Hickey



On Mar 31, 12:45 pm, Konrad Hinsen  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.
>

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

(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)
#

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

(get-method area ::Circle)
#

;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-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  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)
> #
>
> (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)
> #
>
> (get-method area ::Circ) ;not there
> nil
>
> (get-method area ::Circle)
> #
>
> ;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
-~--~~~~--~~--~--~---