From mboxrd@z Thu Jan 1 00:00:00 1970 Received: (from majordomo@localhost) by pauillac.inria.fr (8.7.6/8.7.3) id IAA23941; Wed, 13 Oct 2004 08:39:17 +0200 (MET DST) X-Authentication-Warning: pauillac.inria.fr: majordomo set sender to owner-caml-list@pauillac.inria.fr using -f Received: from concorde.inria.fr (concorde.inria.fr [192.93.2.39]) by pauillac.inria.fr (8.7.6/8.7.3) with ESMTP id IAA23920 for ; Wed, 13 Oct 2004 08:39:16 +0200 (MET DST) Received: from mproxy.gmail.com (rproxy.gmail.com [64.233.170.195]) by concorde.inria.fr (8.13.0/8.13.0) with ESMTP id i9D6dF3U000732 for ; Wed, 13 Oct 2004 08:39:16 +0200 Received: by mproxy.gmail.com with SMTP id 76so387117rnl for ; Tue, 12 Oct 2004 23:39:10 -0700 (PDT) Received: by 10.38.82.45 with SMTP id f45mr2766155rnb; Tue, 12 Oct 2004 23:39:10 -0700 (PDT) Received: by 10.38.14.54 with HTTP; Tue, 12 Oct 2004 23:39:10 -0700 (PDT) Message-ID: Date: Wed, 13 Oct 2004 02:39:10 -0400 From: John Prevost Reply-To: John Prevost To: caml-list Subject: Re: [Caml-list] Narrowing class's public interface In-Reply-To: <1097634426.19740.152.camel@pelican.wigram> Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit References: <200410131116.12485.edgin@slingshot.co.nz> <20041013.094903.08315159.garrigue@kurims.kyoto-u.ac.jp> <1097634426.19740.152.camel@pelican.wigram> X-Miltered: at concorde with ID 416CCD93.001 by Joe's j-chkmail (http://j-chkmail.ensmp.fr)! X-Loop: caml-list@inria.fr X-Spam: no; 0.00; prevost:01 prevost:01 caml-list:01 narrowing:01 class's:01 2004:99 sourceforge:01 quadratic:01 subtypes:01 char:01 char:01 val:01 val:01 cows:01 consumed:01 Sender: owner-caml-list@pauillac.inria.fr Precedence: bulk On 13 Oct 2004 12:27:07 +1000, skaller wrote: {...} > Hence OO is useless as a general paradigm. {...} {...} > Don't even both trying to make the character type polymorphic > because the theory says it can't be done. The reason is > also easy to see, as John Provost described, but another > view of the same thing: you'd need one method for every > driver kind/character kind combination. In other words > the number of methods needed is quadratic in the subtypes, > but OO only supports linear -- you can supply a new method > for each derived 'main object' type .. which is why the method > arguments can't also be polymorphic. Er. You're overstating the case here. First, note that OO programming and subtyping-based polymorphism don't have to go together. It's perfectly reasonable, for example, to have a container class that is invariant in the type of its content. And your IO example is flawed as well. The fixed data type is only an issue if you mix input and output in a single object. Example: exception Producer_Empty class type ['a] producer = object method get : unit -> 'a end class type ['a] consumer = object method put : 'a -> unit end class type ['a] producer_consumer = object inherit ['a] producer inherit ['a] consumer end class file_char : filename:string -> char producer_consumer class file_char_input_stream : filename:string -> char producer class char_to_line_stream : char producer -> string producer class map_producer : ('a -> 'b) -> 'a producer -> 'b producer val iter_over_producer : ('a -> unit) -> 'a producer -> unit class type bovine = object method moo : unit -> unit end class type cow = object inherit bovine method milk : unit -> milk end class type supercow = object inherit cow method fly : unit -> unit end val cows : cow producer_consumer The first thing to notice is that you can have a wide variety of I/O oriented classes (and functions over those classes, and classes over those classes) without worrying about the type of the item being produced or consumed. The second thing I want to point out is about "cows" above. cows cannot be used as a bovine producer_consumer or as a supercow producer_consumer. It can, however, be used as either a bovine producer, or a supercow consumer. Just because an object type is invariant does not mean that it cannot be cast to a covariant or contravariant type. In other words: you go too far to extend this argument to this level. When binary methods exist, things are indeed trickier. They are not, however, impossible. Again, remember that casting out the problemmatic methods can always restrict you down to a type with simpler constraints. In the RV example, you can think in terms of a complicated part of the program which manipulates and creates the RV objects, fully understanding that when manipulating those objects, the types must be maintained. But it can feed the objects it creates into a collection of restricted RV objects, which only carry the methods needed to use them, not the methods needed to manipulate them. No more binary methods, no problem having them all be the same type. I have to admit that I don't use the OO features of O'Caml very much--I generally don't need the flexibility. But these features are very very powerful, for a variety of uses. The trick is to get out of the *class* oriented mindset, and back into a mindset where the objects are what matters. After that, it's all a matter of learning what constraints type safety imposes, and the right way to work within those constraints. There are a few odd cases--like the constructor issue we saw on this list fairly recently, with the SQL connection pool--but if you understand the type system, it mostly all just makes sense. John. ------------------- To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/ Beginner's list: http://groups.yahoo.com/group/ocaml_beginners