Re: [Haskell-cafe] OO idioms redux

2004-10-17 Thread John Goerzen
On Tuesday 12 October 2004 5:20 pm, Ben Rudiak-Gould wrote:

[ snip -- thanks for the examples and discussion ]


  1. Try replacing implementation inheritance with containment and
 delegation when you translate to Haskell.

I'm not sure I understand what you mean by containment and delegation -- 
could you elaborate?

  2. Try revisiting the original problem and thinking about how to
 solve it in a Haskellish way, rather than solving it in another
 language and then translating.

Thats exactly what I'm trying to do here :-)  I've thought of having a 
type that basically stores a bunch of functions -- an implementation 
would simply provide an instance of that type with the functions, 
maybe.
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] OO idioms redux

2004-10-17 Thread Ben Rudiak-Gould
John Goerzen wrote:
I'm not sure I understand what you mean by containment and delegation 
-- could you elaborate?
This means that instead of inheriting all the member functions of the 
base class and selectively overriding them, you store an object of the 
base class as a member of the derived class, and make use of it in 
your implementation. The standard C++ ColoredPoint example looks like 
this if you use interface inheritance:

   class ColoredPoint : public Point {
   int color;
   public:
   // ColoredPoint-specific methods
   };
and like this if you use CD:
   class ColoredPoint {
   Point p;   // containment
   int color;
   public:
   int getX() { return p.getX(); }// delegation
   void setX(int x) { p.setX(x); }
   // ...
   // ColoredPoint-specific methods
   };
If you want to take advantage of inheritance polymorphism with this 
scheme, then you create an interface IPoint with virtual methods like 
getX and setX, and have both Point and ColoredPoint implement it (by 
inheriting it, in C++).

2. Try revisiting the original problem and thinking about how to
   solve it in a Haskellish way, rather than solving it in another
   language and then translating.
   

Thats exactly what I'm trying to do here :-)  I've thought of having a 
type that basically stores a bunch of functions -- an implementation 
would simply provide an instance of that type with the functions, 
maybe.
 

Yes, this is often a good approach, especially when you combine it with 
labelled constructor fields.

-- Ben
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] OO idioms redux

2004-10-13 Thread Graham Klyne
Haskell type classes don't really behave as one might expect coming from an 
OO perspective;  cf. 
http://www.ninebynine.org/Software/Learning-Haskell-Notes.html#type-class-misuse

That commentary doesn't say anything about interface inheritance.  I don't 
offhand have a good answer for that question.  In my own code, I guess I 
kind-of work around that issue.  As for inheritamnce of implementation, I 
guess that can be done by hand, by building a new type that contains the 
base type.

#g
--
At 18:32 12/10/04 +, John Goerzen wrote:
OK, recently I posed a question about rethinking some OO idioms, and
that spawned some useful discussion.
I now have a followup question.
One of the best features of OO programming is that of inheritance.  It
can be used to slightly alter the behavior of objects without requiring
modification to existing code or breaking compatibility with existing
APIs.
As an example, say I have a ConfigParser class.  This class can read in
configuration files, provides various get/set methods to access them,
and can write them back out.
Now say I would like to make this a little more powerful.  Maybe I want
to support the use of environment variables in my config file, so if
there's a reference to $FOO in the file, it will be replaced by the
contents of $FOO in the environment.
In OO, I would make a new EnvConfigParser class.  I'd override the
read() method.  My new read() would probably start by calling the
parent's read() method, to get parsing for free.  Then it could iterate
over the data, doing its environment variable substitution.
Now, in Haskell, we obviously have no objects like this.  We do have
something that provides some of the same benefits -- typeclasses.
However, from what I can determine, they don't support algorithm
inheritance like objects do in an OOP.  Specifically, it seems impossible to
have two instances of a single typeclass that work on the same type,
while having one share most of the code with the other.
I'm wondering if there is a Haskell design pattern that I'm missing that
would provid ethe kind of benefits that one gets from inheritance in the
OO world.
-- John
--
John Goerzen
Author, Foundations of Python Network Programming
http://www.amazon.com/exec/obidos/tg/detail/-/1590593715
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe

Graham Klyne
For email:
http://www.ninebynine.org/#Contact
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] OO idioms redux

2004-10-13 Thread Duncan Coutts
In message [EMAIL PROTECTED] John Goerzen
[EMAIL PROTECTED] writes:
 OK, recently I posed a question about rethinking some OO idioms, and
 that spawned some useful discussion.
 
 I now have a followup question.
 
 One of the best features of OO programming is that of inheritance.  It
 can be used to slightly alter the behavior of objects without requiring
 modification to existing code or breaking compatibility with existing
 APIs.

Closures can do this:

// in C++/Java
class ConfigParser {
  void read (String);
  int getFoo (String);
}


-- in Haskell
data ConfigParser = ConfigParser {
read :: String - IO ConfigParser
getFoo :: String - Int
  }

This is a structure of functions. The difference from C++/Java style objects is
that this gives us object based polymorphism rather than class based
polymorphism. Because they are Haskell closures rather than C-style functions
they can hold private state by using partial application.

configParser :: ConfigParser
configParser = ConfigParser {
read input = ...
getFoo = ...
  }

envConfigParser :: ConfigParser
envConfigParser = configParser {
read input = do env - getEnvVars
read configParser (substEnvVars input)
  }

Duncan
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] OO idioms redux

2004-10-13 Thread Ben . Yu
The only problem with this is name.

It is too easy to have naming clash in haskell. Field selectors are also
top-level functions and they shared the same namespace with other
functions.
for any reasonable scale program, we'll end up with ModuleA.read x,
ModuleB.read b. (Yes, we can alias the modules as A and B, but then we'll
have to face the module alias naming clash again)

In java/c++, we can name a method in the most meaningful and natural way we
like, rest-assured it won't have a problem just because some other
class/interface happens to use the same name for a different thing.

Plus, module, in my opinion is a logical functionality group, a quite
coarse-grained facility. not an appropriate tool to disambiguate names in a
fine-grained way.

I like the Lightweight Extensible Records for Haskell  paper by Mark
Jones and Simon P. Jones. Very clean IMHO.
Not sure why it did not get implemented.




   
  
  Duncan Coutts
  
  [EMAIL PROTECTED]To:   John Goerzen [EMAIL 
PROTECTED]  
  ford.ac.ukcc:   [EMAIL PROTECTED]   
   
  Sent by:   Subject:  Re: [Haskell-cafe] 
OO idioms redux
  [EMAIL PROTECTED]

  l.org
  
   
  
   
  
  10/13/2004 08:15 AM  
  
   
  




In message [EMAIL PROTECTED] John Goerzen
[EMAIL PROTECTED] writes:
 OK, recently I posed a question about rethinking some OO idioms, and
 that spawned some useful discussion.

 I now have a followup question.

 One of the best features of OO programming is that of inheritance.  It
 can be used to slightly alter the behavior of objects without requiring
 modification to existing code or breaking compatibility with existing
 APIs.

Closures can do this:

// in C++/Java
class ConfigParser {
  void read (String);
  int getFoo (String);
}


-- in Haskell
data ConfigParser = ConfigParser {
read :: String - IO ConfigParser
getFoo :: String - Int
  }

This is a structure of functions. The difference from C++/Java style
objects is
that this gives us object based polymorphism rather than class based
polymorphism. Because they are Haskell closures rather than C-style
functions
they can hold private state by using partial application.

configParser :: ConfigParser
configParser = ConfigParser {
read input = ...
getFoo = ...
  }

envConfigParser :: ConfigParser
envConfigParser = configParser {
read input = do env - getEnvVars
read configParser (substEnvVars input)
  }

Duncan
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe




This message is intended only for the addressee and may contain information
that is confidential or privileged. Unauthorized use is strictly prohibited
and may be unlawful. If you are not the intended recipient, or the person
responsible for delivering to the intended recipient, you should not read,
copy, disclose or otherwise use this message, except for the purpose of
delivery to the addressee. If you have received this email in error, please
delete and advise the IT Security department at [EMAIL PROTECTED]
immediately

___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] OO idioms redux

2004-10-12 Thread John Goerzen
OK, recently I posed a question about rethinking some OO idioms, and
that spawned some useful discussion.

I now have a followup question.

One of the best features of OO programming is that of inheritance.  It
can be used to slightly alter the behavior of objects without requiring
modification to existing code or breaking compatibility with existing
APIs.

As an example, say I have a ConfigParser class.  This class can read in
configuration files, provides various get/set methods to access them,
and can write them back out.

Now say I would like to make this a little more powerful.  Maybe I want
to support the use of environment variables in my config file, so if
there's a reference to $FOO in the file, it will be replaced by the
contents of $FOO in the environment.

In OO, I would make a new EnvConfigParser class.  I'd override the
read() method.  My new read() would probably start by calling the
parent's read() method, to get parsing for free.  Then it could iterate
over the data, doing its environment variable substitution.


Now, in Haskell, we obviously have no objects like this.  We do have
something that provides some of the same benefits -- typeclasses.
However, from what I can determine, they don't support algorithm
inheritance like objects do in an OOP.  Specifically, it seems impossible to
have two instances of a single typeclass that work on the same type,
while having one share most of the code with the other.

I'm wondering if there is a Haskell design pattern that I'm missing that
would provid ethe kind of benefits that one gets from inheritance in the
OO world.

-- John


-- 
John Goerzen
Author, Foundations of Python Network Programming
http://www.amazon.com/exec/obidos/tg/detail/-/1590593715

___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] OO idioms redux

2004-10-12 Thread Ben Rudiak-Gould
On Tue, 12 Oct 2004, John Goerzen wrote:

 One of the best features of OO programming is that of inheritance.  It
 can be used to slightly alter the behavior of objects without requiring
 modification to existing code or breaking compatibility with existing
 APIs.

I hesitate to express a contrary opinion since it'll sound as though I'm
defending Haskell's limitations, but that's actually not the case here --
this was true even before I learned Haskell.

In my own OOP code (mainly C++) I've rarely used implementation
inheritance, and when I have I've never felt entirely happy about the way
it turned out; it always seemed a bit fragile and hacky. When I want to
take advantage of polymorphism I usually use abstract interfaces, and when
I want to share code I usually use containment and delegation, which has
always struck me as more robust.

In any case, Haskell does support polymorphic abstract interfaces and
containment and delegation. In your ConfigParser example you would have an
interface (say IConfigParser) which would be represented as a type class,
and two implementations (ConfigParser and EnvConfigParser) which would be
represented as instances of the type class. E.g.

class IConfigParser a where
  newConfigParser :: IO a
  readConfigFile :: a - FilePath - IO ()
  getFoo :: a - IO Foo
  setFoo :: a - Foo - IO ()
  ...

data ConfigParser = ...

instance IConfigParser ConfigParser where ...

data EnvConfigParser = ECP ConfigParser

instance IConfigParser EnvConfigParser where
  newConfigParser = liftM ECP newConfigParser
  readConfigFile (ECP cp) path =
readConfigFile cp path  envSubst cp
  getFoo (ECP cp) = getFoo cp
  ...

I should say, though, that this is very unidiomatic code. Partly this is
because I don't quite understand the meaning of your ConfigParser class --
does it exist before a configuration file is read? What is the meaning of
having more than one instance? Parsing configuration files strikes me as
more verb than noun, and I'd be more inclined in this case to declare a
single ConfigData type, a single function to write it to a file, and two
functions to read it, one with environment substitution and one without.
So I suppose my advice is twofold:

1. Try replacing implementation inheritance with containment and
   delegation when you translate to Haskell.

2. Try revisiting the original problem and thinking about how to
   solve it in a Haskellish way, rather than solving it in another
   language and then translating.

-- Ben

___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe