Re: [Haskell-cafe] OO idioms redux
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
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
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
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
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
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
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