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=0.0 required=5.0 tests=none 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 09D03BBC4 for ; Wed, 1 Apr 2009 01:52:50 +0200 (CEST) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: Am0BAPhJ0knZSMDqi2dsb2JhbACBU5RBAQEBCgsKBw8Ft3yDegY X-IronPort-AV: E=Sophos;i="4.39,304,1235948400"; d="scan'208";a="23682234" Received: from fmmailgate03.web.de ([217.72.192.234]) by mail2-smtp-roc.national.inria.fr with ESMTP; 01 Apr 2009 01:52:49 +0200 Received: from smtp05.web.de (fmsmtp05.dlan.cinetic.de [172.20.4.166]) by fmmailgate03.web.de (Postfix) with ESMTP id 2EBC2F9CEDBB; Wed, 1 Apr 2009 01:52:49 +0200 (CEST) Received: from [78.43.226.218] (helo=frosties.localdomain) by smtp05.web.de with asmtp (TLSv1:AES256-SHA:256) (WEB.DE 4.110 #277) id 1LonlA-0008NG-00; Wed, 01 Apr 2009 01:52:48 +0200 Received: from mrvn by frosties.localdomain with local (Exim 4.69) (envelope-from ) id 1Lonl9-0000LE-Ih; Wed, 01 Apr 2009 01:52:47 +0200 From: Goswin von Brederlow To: Martin Jambon Cc: Goswin von Brederlow , caml-list@yquem.inria.fr Subject: Re: [Caml-list] Bug? Constraints get ignored in methods References: <87ab71ic1f.fsf@frosties.localdomain> <49D2A0AF.1080300@ens-lyon.org> Date: Wed, 01 Apr 2009 01:52:47 +0200 In-Reply-To: <49D2A0AF.1080300@ens-lyon.org> (Martin Jambon's message of "Wed, 01 Apr 2009 01:01:03 +0200") Message-ID: <87tz596yi8.fsf@frosties.localdomain> User-Agent: Gnus/5.110006 (No Gnus v0.6) XEmacs/21.4.21 (linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Sender: goswin-v-b@web.de X-Sender: goswin-v-b@web.de X-Provags-ID: V01U2FsdGVkX1+I6zIOvZ+ov7CU6DUZc8G5Pk73FjJ7rGnF8dHO GyoPuasXQv8uFTZXPSKe2by+giJDsOHTn7t85bfkIdC6eRu0d9 WVM3ym2OM= X-Spam: no; 0.00; bug:01 ens-lyon:01 subset:01 ocaml:01 polymorphism:01 constructors:01 subset:01 val:01 mutable:01 val:01 mutable:01 foo:01 foo:01 superset:01 ocaml:01 Martin Jambon writes: > Goswin von Brederlow wrote: >> Hi, >> >> I want to keep a linked list of structures that have a common subset >> of functionality. I thought this would be a good use of ocaml objects. > > It is not a good use of objects. You'll notice this pretty soon as you'll run > into a variety of problems: > > - polymorphism Works fine without constraint. > - initialization Yep, already run into that one. I basically need 2 constructors. But I solved that. > - verbosity ??? > - performance The disk is the slow part. :) > All of these issues are inexistent if you use records instead of objects for > the list structure (or just a classic list). > > You can still use objects as elements of the list, but the elements would have > to share the base type, as you know. You can not put things of different type into a list. So the elements of the list must be unified to a common type. Since I need virtual functions that means either a record of closures bound to a reference of the actual data (ugly) or objects. So let it be objects. Now with objects as elements of a normal list the problem remains. I need to coerce them to the base type before calling the function(s) handling the base type. And in the real use case there is not a simple list but a more complicated structure (links between objects of state clean, dirty, pending read, pending write, ...) so this occurs on more than one place. > (continued below) > >> A base class with the common subset of functionality and methods to >> link them. And then derived classes for the specific types. Most >> simplified it looks like this: >> >> # class type base_type = object val mutable next : base_type option method set_next : base_type option -> unit end;; >> class type base_type = >> object >> val mutable next : base_type option >> method set_next : base_type option -> unit >> end >> >> # class base : base_type = object val mutable next = None method set_next n = next <- n end;; >> class base : base_type >> >> # class foo = object inherit base method foo = () end;; >> class foo : >> object >> val mutable next : base_type option >> method foo : unit >> method set_next : base_type option -> unit >> end >> >> # let a = new base in >> let b = new foo in >> a#set_next (Some (b :> base_type));; >> - : unit = () >> >> # let a = new base in >> let b = new foo in >> a#set_next (Some b);; >> ^ >> Error: This expression has type foo but is here used with type base_type >> The second object type has no method foo >> >> This last error isn't nice. I don't want to have to cast the objects >> all the time. So I thought there must be a better way using >> polymorphic methods with a constraint. But here is where everything >> breaks down. First lets look at just the set_next method: >> >> # class type virtual vbase_type = object method virtual set_next : 'a. 'a option -> unit constraint 'a = #vbase_type end;; >> class type virtual vbase_type = >> object method virtual set_next : 'a option -> unit end >> >> # class virtual vbase : vbase_type = object method virtual set_next : 'a. 'a option -> unit constraint 'a = #vbase_type end;; >> class virtual vbase : vbase_type >> >> # class base = object inherit vbase method set_next _ = () end;; >> class base : object method set_next : 'a option -> unit end >> >> # let b = new base;; >> val b : base = >> >> # b#set_next (Some 1);; >> - : unit = () >> >> Huh? That should not work. 1 is not a superset of #vbase_type. The >> constraint gets completly ignored by ocaml. Adding back the next gives >> further problems: >> >> # class type virtual vbase_type = object val mutable next : #vbase_type option method virtual set_next : 'a. 'a option -> unit constraint 'a = #vbase_type end;; >> class type virtual vbase_type = >> object >> val mutable next : #vbase_type option >> method virtual set_next : 'a option -> unit >> end >> >> # class virtual vbase : vbase_type = object val mutable next = None method virtual set_next : 'a. 'a option -> unit constraint 'a = #vbase_type end;; >> class virtual vbase : vbase_type >> >> # class base = object inherit vbase >> method set_next n = next <- (n :> vbase_type option) end;; >> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >> Error: This method has type #vbase_type option -> unit >> which is less general than 'a. 'a option -> unit >> >> Again I blame ocaml for dropping the constraint. Given the constraint >> the type would be correct. >> >> >> >> So how do I have to specify the set_next method that any superset of >> #base_type will be accepted as argument? Or is that a bug in ocaml and >> my syntax is perfectly fine? > > > I have no idea. It looks way too complicated. > Use a classic list: > > > class base = ... > class derived = ... (* inherits base *) > > type obj = Base of base | Derived of derived That would make this module depend on all possible types. And the different types depend on this module as they have to alter the location in the list to implement a move-to-front caching algorithm. That would cause all my types and the list handling to be in one huge ml file. No way. Anyway, it currently looks more like this: class base = ... class ['a] data = ... type t1 = M1.t data type t2 = M2.t data type t3 = M3.t data type t3a = M3.A.t data type t3b = M3.B.t data ... where t3a/t3b are derived from t3. > let obj_list = [ Base (new base); Derived (new derived); ... ] > > let iter_base f l = > List.iter (function Base x -> f x | Derived x -> f (x :> base)) l > > let iter_derived f l = > List.iter (function Derived x -> f x | Base _ -> ()) l Now imagine that with 100 types. It really doesn't scale well. Before I do that I will use (x :> base) in all places calling set_next like functions. MfG Goswin