From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.1.3 (2006-06-01) on yquem.inria.fr X-Spam-Level: * X-Spam-Status: No, score=1.0 required=5.0 tests=AWL,SPF_FAIL autolearn=disabled version=3.1.3 Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by yquem.inria.fr (Postfix) with ESMTP id 2BF4EBBCA for ; Sun, 24 Feb 2008 17:49:22 +0100 (CET) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AgAAAAYvwUfVpUAUmWdsb2JhbACQWwEBAQEBBgQGCQgWgQ+Xfw X-IronPort-AV: E=Sophos;i="4.25,398,1199660400"; d="scan'208";a="7623451" Received: from mail.gmx.net ([213.165.64.20]) by mail2-smtp-roc.national.inria.fr with SMTP; 24 Feb 2008 17:49:21 +0100 Received: (qmail invoked by alias); 24 Feb 2008 16:49:19 -0000 Received: from dialin-145-254-249-030.pools.arcor-ip.net (EHLO dialin-145-254-249-030.pools.arcor-ip.net) [145.254.249.30] by mail.gmx.net (mp036) with SMTP; 24 Feb 2008 17:49:19 +0100 X-Authenticated: #11134691 X-Provags-ID: V01U2FsdGVkX1/IN/BselbIOxk4ErmZW/b1l926K5BQ+Wioj8ih2G agAxhy2AavAYHc Received: from dirk by feanor.private-host.de with local (masqmail 0.2.20) id 1JTJmm-11Y-00 for ; Sun, 24 Feb 2008 17:33:08 +0100 Date: Sun, 24 Feb 2008 17:33:08 +0100 To: caml-list@yquem.inria.fr Subject: Re: [Caml-list] OO programming Message-ID: <20080224163308.GA3459@feanor> References: <47BD44FE.3050001@irisa.fr> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <47BD44FE.3050001@irisa.fr> User-Agent: Mutt/1.5.6+20040523i From: Dirk Thierbach X-Y-GMX-Trusted: 0 X-Spam: no; 0.00; 0100,:01 ocaml:01 typecheck:01 val:01 mutable:01 iter:01 ocaml:01 subtyping:01 mutable:01 parametric:01 initialized:01 mli:01 val:01 subtype:01 didier:01 On Thu, Feb 21, 2008 at 10:31:42AM +0100, Tiphaine Turpin wrote: > After a few unsuccessfull tries with using the object oriented features > of ocaml, I have been looking for ways to write classes that have a > chance to typecheck. The way I handle this is the following: > The usual problem is that objects refer to other objects, I avoid this as much as possible. Instead of "connecting" objects to other objects, I "connect" an objects to "actions" (functions), which may be closures that include other objects. The typical example which has already been given is the observer-pattern, which I use as follows: class ['a] observer = object(self) val mutable actions = [] method register action = actions <- action :: actions method notify (arg : 'a) = List.iter (fun f -> f arg) actions end;; No class for subject needed. Many of the objects I use in the GUI layer just inherit from observer, and it's also handy if the action you want doesn't refer to an explicit object in the OCaml layer (because the state is kept in the external GUI layer) If possible, I try to make each object as independently from the rest of the world as I can (after all, grouping a related part of the world state together is very central to OO), and then I "plug together" all these objects at a higher level. > those objects may refer back to objects referring to them, No problem with the above way of using "actions". > then objects refer to different objects, some of them having more > methods than others (subtyping), I also use objects as parameters, both for classes and functions. That all works as it is intended, the type just collects any method calls that are used in the parameter. The only disadvantage is that a type error is then usually discovered only at the time when I "plug" all these things together. That's somewhat annoying, and if I really cannot figure out what's going on, introducing type declarations into a few places usually helps. > etc. and finally the programmer has to give a type to all those > beautifull mutable fields that are not fully specified, or make them > parametric. That problem often goes away if these fields are initialized, or used in a method (which can be annoying if the class is not yet completely written, but you want to test the stuff you have so far). And of course, I try to use as little mutable state as possible (after all, it's a functional programming language :-) Much more annoying is that one also has to give types to arguments in methods that are unused (they are present make them compatible with another class, which uses them; or they are required by the GUI layer), and that OCaml has now way to seperate method/function declaration and type declaration (unless one uses a mli file, which is again inconvenient because it splits information that belongs together into two complete different places). I'd really appreciate it if one could just mix "val" type declcarations with "let" or "method" code declarations. > Of course, the resulting classes should be reusable, that is, one > should be able to extend a collection of related classes > simultaneously, such that the fields now have the relevant subtype > instead of the type they had before. Not sure what exactly you mean here. Could you give an example? > The best guidelines that I found are in the following course from > Didier Remy [...] For example if a class refer to a method provided > by a related class, this way of writing them does not guarantee that > the method is actually defined. Only when creating and linking the > objects together will the type-checker reject the program, if for > example, the method has been misspelled in one class. So for me this > coding scheme has the drawback that it unplugs the type-checker and > just call it at the end. Yes, see above. You can use class types to get around this problem, but if you keep the classes small, one can live with. > For me the "ideal" use of objects would use mutually recursive > classes with fields defined with a type referring to the name of the > other class. Ugh. No, thanks :-) - Dirk