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 mail3-relais-sop.national.inria.fr (mail3-relais-sop.national.inria.fr [192.134.164.104]) by yquem.inria.fr (Postfix) with ESMTP id 1973DBC57 for ; Mon, 4 Oct 2010 19:33:13 +0200 (CEST) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: ApMBAPGsqUzRVda0kGdsb2JhbACiPggVAQEBAQkJDAcRAx+pM4lJgheGLy6IVgEBAwWFQgSKQA X-IronPort-AV: E=Sophos;i="4.57,279,1283724000"; d="scan'208";a="60264563" Received: from mail-iw0-f180.google.com ([209.85.214.180]) by mail3-smtp-sop.national.inria.fr with ESMTP; 04 Oct 2010 19:33:01 +0200 Received: by iwn8 with SMTP id 8so10020487iwn.39 for ; Mon, 04 Oct 2010 10:32:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:received:date:message-id :subject:from:to:content-type; bh=ZC2i2V0qJNnMmwxtIyT08CUWg/Q5achkeryFQofIpv0=; b=Toq8TC8DPMe7OUxgvhU63souDDV2VKUWj4/GWHSaZyByWdI+3gfdZviuZIzAIseLOq yXYCmfXG0eeEJ9an0w6Twa3TLqN6BYDlrv4LTUsay6ADBaebTY29PZc2UojnDCJsL1td kkewEhJAgkVclZGWSeuU1wL/IWLAcOcxMQ41U= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:content-type; b=YbtBXiHRCZ2lAZYhQAlSy5HWVpG+GPxnvCm/sS8ACFJyJrRPsLLPtMO24j8Q9px51E t+/woc80Xzxl4K7FuGcHsUdmuArKyocNcVS6JoT5vf4VOq3FqEK7I/1KXBO6pX6UzTcY W7ig31t7qN1mT2hCwVBUd+EiR4j48NOZ/lerk= MIME-Version: 1.0 Received: by 10.231.152.143 with SMTP id g15mr10420071ibw.76.1286213578804; Mon, 04 Oct 2010 10:32:58 -0700 (PDT) Received: by 10.231.152.135 with HTTP; Mon, 4 Oct 2010 10:32:58 -0700 (PDT) Date: Mon, 4 Oct 2010 19:32:58 +0200 Message-ID: Subject: objects: the lack of method overloading (looking for a way around it) From: philippe To: caml-list@yquem.inria.fr Content-Type: text/plain; charset=ISO-8859-1 X-Spam: no; 0.00; overloading:01 ocaml:01 overloading:01 node:01 node:01 hash:01 caching:01 polymorphism:01 val:01 mutable:01 val:01 mutable:01 hash:01 computed:01 prev:01 Hello, I'm just beginning a real, usefull usage of the object system in ocaml. I'm a bit stalled on one thing, it's the lack of method overloading like in C++. My need is in a case of building a rather simple pipeline pattern: each instance of an element (a node) in the pipeline can get a numerical value from the previous node, do some computation on it, and store it locally in a hash for caching/efficiency, as returning it using the #get method. The real need see most of the time a 1D array of float (a vector) in input and output of each node. but sometime a Complex.t array. So I need some kind of polymorphism for allowing : float array -> float array Complet.t array -> float array float array -> Complex.t array Complex.t array -> Complex.t array Here's a shorter (a bit dumb) demo code using int -> int. (I would much prefer avoid to store float in the real part of a complex array - in the real (genuine) code the array may be long, 100'000 elements and more, it's code a bit sensitive about performances). Look to the comment MY QUESTION in the definition of the process method in the class node_plus THANK YOU ! -- Philippe Strauss --- 8< --- open Common open Log (* the real code has more usefull type here *) type node_parameters = Plus1 | Plus2 (* a class for storing parameters usefull for the whole pipeline chain *) class parameters = object(self) (* useless here - usefull in the real code *) val mutable sf = 44100 (* a value we will add in a demo node *) val mutable add = 1 method get_sf = sf method set_sf sfreq = sf <- sfreq ; method get_add = add method set_add ntoadd = add <- ntoadd (* this is for the cache part of each node: we compute a hash of parameter to distinguish hash entries btwn parameters change *) method get_parh np (node_id: int) = let md5 s = Digest.to_hex (Digest.string s) in match np with (* the real code doesn't use always (sf, add) but parameter influing the processing of a node *) | Plus1 -> md5 (Marshal.to_string (sf, add) [Marshal.No_sharing]) | Plus2 -> md5 (Marshal.to_string (sf, add) [Marshal.No_sharing]) end (* main code of a node: a boileplate around a hash to cache computed value *) class virtual node_virt prev parm hn = object(self) (* instance of a previous node in the pipeline *) val previous = prev (* instance of the parameters *) val parms = parm (* the hash for caching *) val hres = Hashtbl.create hn (* a serial, bumped up plus one on each cache miss *) val mutable id = 0 method get_id = id method inc_id = id <- id + 1 (* for passing to (parms #get_parh (self #ptyp ())) in the real code, when adding a result into the hash *) method virtual ptyp: unit -> node_parameters (* the real computation is defined in a non virtual method later, as simply as possible *) method virtual process: int -> int (* process and store: call process, then store in cache. called on a cache miss *) method private pstore: (int * int) = let prid, data = prev #get in (* processing *) let new_data = self #process data in (* we're in a cache miss: bump the serial +1 *) self #inc_id ; let myid = self #get_id in Hashtbl.add hres (parms #get_parh Plus1 myid) new_data ; (myid, new_data) method get = try (* memoize id to avoid race cond *) let myid = self #get_id in (* here again in the real code, we lookup the hash using (parms #get_parh (self #ptyp ()) myid) *) let data = Hashtbl.find hres (parms #get_parh Plus1 myid) in (myid, data) with Not_found -> Printf.printf "node_virt #get: cache miss!\n%!"; self #pstore end (* a trivial node: add parm #get_add to the integer we receive from the previous node *) class node_plus prev parm hn = object(self) inherit node_virt prev parm hn method ptyp () = Plus1 (* MY QUESTION: what is the best way to allow not only int -> int for this process method, but also: int -> float, float -> int, float -> float ? The method minimizing the code written in this non virtual node definition, since I may end with 15 or 30 differents derived class of node_virt like this single one ? *) method process n = n + (parm #get_add) end (* a front of line, head node having a get method of the same type than those derived from node_virt *) class node_head parm = object(self) val parms = parm method get = (0, 1) end let () = let p = new parameters in p #set_sf 44100 ; (* useless indeed, just for demo *) p #set_add 2 ; (* usefull *) let n0 = new node_head p in let n1 = new node_plus n0 p 3 in Printf.printf "%d\n" (snd (n0 #get)) ; Printf.printf "%d\n" (snd (n1 #get)) ; Printf.printf "%d\n" (snd (n1 #get)) ; p #set_add 1 ; Printf.printf "%d\n" (snd (n1 #get))