
On Mon, 2005-01-17 at 16:27 -0800, Ben Rudiak-Gould wrote:
Marcin 'Qrczak' Kowalczyk wrote:
Convenience. I'm worried that it uses separate types for various kinds of streams: files, pipes, arrays (private memory), and sockets. Haskell is statically typed and lacks subsumption. This means that even though streams are unified by using a class, code which uses a stream of an unknown kind must be either polymorphic or use existential quantification.
Yes, this is a problem. In my original proposal InputStream and OutputStream were types, but I enthusiastically embraced Simon M's idea of turning them into classes. As you say, it's not without its disadvantages.
I see several possibilities here.
* We could adopt Avery Lee's suggestion (from the discussion in 2003) to use field labels instead of methods. Advantages: InputStream and OutputStream behave more like their OOP equivalents, with no loss of extensibility. Disadvantages: potentially less efficient (no specialization possible); loses some static type information.
I've often thought it would be nice to have a class and it's most general instance, a record with the same fields as the class has methods. It would be even better if they could share the same name, eg: class IStream s where read :: s -> ... data IStream = IStream { read :: ... } instance IStream IStream where read s = read s --the field selector not the class method Obviously each instance of the IStream class can be converted to an IStream record (loosing type information) which is useful for heterogeneous collections of streams, and other "interface programming" techniques. This technique is perhaps a middle ground, it's a tad more complex that just having a single type for streams but it allows code which does not want to know to use a single type while allowing for static typing in other cases where it is desired for safety or for better performance by specialising. A downside (apart from naming issues) is that while there is an automatic conversion IStream data type -> IStream class instance, there is no automatic conversion the other way round. Compare this with Java interfaces for example, a Java IStream interface is like our IStream data type, but there is automatic conversion from the types implementing the interface to the interface type itself. In Haskell we normally go for the more strongly typed interfaces (Haskell classes) rather than the more dynamic interfaces (record of functions) so the language supports the former more naturally than the latter (eg automatic 'conversion' when accessing an object through a class interface). Duncan