From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Original-To: caml-list@yquem.inria.fr Delivered-To: caml-list@yquem.inria.fr Received: from nez-perce.inria.fr (nez-perce.inria.fr [192.93.2.78]) by yquem.inria.fr (Postfix) with ESMTP id 19A07BBBB for ; Tue, 24 Jan 2006 07:44:59 +0100 (CET) Received: from smtp1.adl2.internode.on.net (smtp1.adl2.internode.on.net [203.16.214.181]) by nez-perce.inria.fr (8.13.0/8.13.0) with ESMTP id k0O6iukY023076 for ; Tue, 24 Jan 2006 07:44:58 +0100 Received: from rosella (ppp21-250.lns2.syd7.internode.on.net [59.167.21.250]) by smtp1.adl2.internode.on.net (8.13.5/8.13.5) with ESMTP id k0O6iiOM011852; Tue, 24 Jan 2006 17:14:45 +1030 (CST) (envelope-from skaller@users.sourceforge.net) Subject: Re: [Caml-list] (no subject) From: skaller To: Kathleen Fisher Cc: caml-list@yquem.inria.fr, John Reppy In-Reply-To: References: Content-Type: text/plain Date: Tue, 24 Jan 2006 17:44:44 +1100 Message-Id: <1138085084.24817.239.camel@rosella> Mime-Version: 1.0 X-Mailer: Evolution 2.4.1 Content-Transfer-Encoding: 7bit X-Miltered: at nez-perce with ID 43D5CCE8.000 by Joe's j-chkmail (http://j-chkmail.ensmp.fr)! X-Spam: no; 0.00; caml-list:01 reppy:01 ocaml:01 object-:01 polymorphism:01 polymorphism:01 ocaml:01 variance:01 lexer:01 compiler:01 lexer:01 ocamllex:01 inputs:01 ocamlyacc:01 parser:01 X-Spam-Checker-Version: SpamAssassin 3.0.3 (2005-04-27) on yquem.inria.fr X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=disabled version=3.0.3 On Mon, 2006-01-23 at 11:37 -0800, Kathleen Fisher wrote: > As part of our work on Moby, John Reppy and I are collecting > experiences people have had using the object-oriented features of > Ocaml, as it has been available long enough for people to use it "for > real." > > We are interested in understanding what people use the object- > oriented features for. What works really well? What doesn't work so > smoothly? How do you decide when to use the object-oriented > features? Do you have other observations you'd like to share? OO features provide dynamic binding, which is more powerful than polymorphism provided by any other feature other than higher order polymorphism (which doesn't work properly in Ocaml). However, the utility is heavily constrained by the variance requirements. The effect is that OO is often the best solution for sources and sinks, and cannot be used for most relationships (since they're usually covariant). Thus, I am using Ocaml OO as sources and for relationships where one type is invariant. In particular, I am using it in the lexer phase of my compiler, with classes to handle and factorise the state of the preprocessor/lexer, parameterising Ocamllex action code. Secondly, it is used to manage the inputs supplied to the Ocamlyacc parser mainly to feed a stream of tokens to it. In both cases the type of a token is invariant, and so amenable to an OO solution. In both cases the technology being leveraged -- Ocamllex and Ocamlyacc -- forces me to control invert my logic and program reactively instead of actively -- user actions of both tools are callbacks driven by tool generated logic which provide no or very limited ability to interact actively. These uses are not intended to provide any abstraction, they're just a convenient way to package up the functionality and pass it around as a single value. My back end would also benefit from use of classes. The output data type involved -- strings -- is invariant. Classes would provide abstraction which may assist in making the code generator pluggable: at present it can only generate ISO C++, it would be useful to generate C, C--, Ocaml, or some other languages too. This is not done at the moment, because using classes requires knowing in advance what your abstractions are: classes break badly with design changes. Algebraic data structures are more flexible, adapt more easily, but it is harder to reason about correctness when operating directly on low level representations. In fact, in the lexer classes, the enforced abstraction (variables can't be accessed, you have to write get/set methods) is actually a pain. As the system developed I've had to add more variables and get/set methods .. and declare separately the types in *.mli files .. because much of the time I'm *really* working directly with the representation. Refactoring would be a nightmare ;( In another project I used classes much more heavily. That project (Vyper) was an Ocaml program which implemented the Python programming language. This was not only convenient to model the Python objects as classes, it was also useful for constructing lookup scopes, with methods representing the various lookup rules. There I used abstraction heavily, as a way of separating my Ocaml implementation from the semantics, and this was tenable because the semantics were well specified (by the Python language), which itself is object based. One final comment: classes would be MUCH more useful if, as in C++, one had dynamically loadable code. In that case algorithms can work with class types instantiated at run time, the dynamic binding is fundamental, and the enforced abstraction vital. I exploit this heavily in Felix, which generates shared libraries which are dynamically loaded by a driver program, which runs the code using C++ abstract base methods. In Ocaml you have to link all the instances in anyhow.. so the dynamic binding isn't nearly as useful. For Vyper this was one of the major factors killing the project: there was a need to model all the C extension to Python -- and there are a LOT of them -- the same way Python does: by dynamic loading. The Ocaml emulation had to statically link every extension, which apart from being a pain, introduces the possibility that the intended bindings are not fully abstracted. -- John Skaller Felix, successor to C++: http://felix.sf.net