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 0632FBC57 for ; Tue, 5 Oct 2010 17:37:10 +0200 (CEST) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AqkAAAziqkzRVda0kGdsb2JhbACiPggVAQEBAQkJDAcRAx+pBolJgheGSy6IVgEBAwWFQgSKQIVo X-IronPort-AV: E=Sophos;i="4.57,284,1283724000"; d="scan'208";a="60536206" Received: from mail-iw0-f180.google.com ([209.85.214.180]) by mail3-smtp-sop.national.inria.fr with ESMTP; 05 Oct 2010 17:37:09 +0200 Received: by iwn33 with SMTP id 33so550250iwn.39 for ; Tue, 05 Oct 2010 08:37:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:received:in-reply-to :references:date:message-id:subject:from:to:content-type :content-transfer-encoding; bh=XtCrbpKCIR5KDKR3jUexmwPlXQZtzguUdqggVnBMn9g=; b=rpLqMi+B8dtCr8+uCuxeruzm4pBGdtAk7YzsXSJiAa7HZ+Phnj+gG7/5VwvCZC2plb /VVX/YjX/Kc34oLa7MYkmcB/LNqyUIGCYeO9uAineOO4Eu3Lnxg83D1/JHh3x4RFOkk/ ik5OpCj3RPz5ctTm7KZUCNeDdX2n2g7TQ4wQ8= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type:content-transfer-encoding; b=wxrjVbZkbyYmP2VYHwDvEq6anl0SnBtRAeS+HaqGKhPZQEjHSWdXdXM7rbmXCHy47Q 9wLuh7o7iQyo/8NBSZ0urGya/Y4OzP6u8wIKEMOHvWpC3pSilzsyawa/i3Q3WJirwZh9 nBvwztFz3BtJfku9LliKMHyZjv0JigGniRVIM= MIME-Version: 1.0 Received: by 10.231.172.75 with SMTP id k11mr12380461ibz.4.1286293027691; Tue, 05 Oct 2010 08:37:07 -0700 (PDT) Received: by 10.231.152.135 with HTTP; Tue, 5 Oct 2010 08:37:07 -0700 (PDT) In-Reply-To: References: Date: Tue, 5 Oct 2010 17:37:07 +0200 Message-ID: Subject: Re: 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 Content-Transfer-Encoding: quoted-printable X-Spam: no; 0.00; overloading:01 parametrized: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 philippe, use parametrized classes. -- philippe On Mon, Oct 4, 2010 at 7:32 PM, philippe wrote: > 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 =3D Plus1 | Plus2 > > (* a class for storing parameters usefull for the whole pipeline chain *) > class parameters =3D > =A0 =A0object(self) > =A0 =A0 =A0 =A0(* useless here - usefull in the real code *) > =A0 =A0 =A0 =A0val mutable sf =3D 44100 > =A0 =A0 =A0 =A0(* a value we will add in a demo node *) > =A0 =A0 =A0 =A0val mutable add =3D 1 > =A0 =A0 =A0 =A0method get_sf =3D sf > =A0 =A0 =A0 =A0method set_sf sfreq =3D > =A0 =A0 =A0 =A0 =A0 =A0sf <- sfreq ; > =A0 =A0 =A0 =A0method get_add =3D add > =A0 =A0 =A0 =A0method set_add ntoadd =3D > =A0 =A0 =A0 =A0 =A0 =A0add <- ntoadd > =A0 =A0 =A0 =A0(* this is for the cache part of each node: we compute a h= ash > of parameter to distinguish hash entries btwn parameters change *) > =A0 =A0 =A0 =A0method get_parh np (node_id: int) =3D > =A0 =A0 =A0 =A0 =A0 =A0let md5 s =3D Digest.to_hex (Digest.string s) in > =A0 =A0 =A0 =A0 =A0 =A0match np with > =A0 =A0 =A0 =A0 =A0 =A0(* the real code doesn't use always (sf, add) but > parameter influing the processing of a node *) > =A0 =A0 =A0 =A0 =A0 =A0| Plus1 -> md5 (Marshal.to_string (sf, add) [Marsh= al.No_sharing]) > =A0 =A0 =A0 =A0 =A0 =A0| Plus2 -> md5 (Marshal.to_string (sf, add) [Marsh= al.No_sharing]) > end > > (* main code of a node: a boileplate around a hash to cache computed valu= e *) > class virtual node_virt prev parm hn =3D > =A0 =A0object(self) > =A0 =A0 =A0 =A0(* instance of a previous node in the pipeline *) > =A0 =A0 =A0 =A0val previous =3D prev > =A0 =A0 =A0 =A0(* instance of the parameters *) > =A0 =A0 =A0 =A0val parms =3D parm > =A0 =A0 =A0 =A0(* the hash for caching *) > =A0 =A0 =A0 =A0val hres =3D Hashtbl.create hn > =A0 =A0 =A0 =A0(* a serial, bumped up plus one on each cache miss *) > =A0 =A0 =A0 =A0val mutable id =3D 0 > =A0 =A0 =A0 =A0method get_id =3D id > =A0 =A0 =A0 =A0method inc_id =3D > =A0 =A0 =A0 =A0 =A0 =A0id <- id + 1 > =A0 =A0 =A0 =A0(* for passing to (parms #get_parh (self #ptyp ())) in the > real code, when adding a result into the hash *) > =A0 =A0 =A0 =A0method virtual ptyp: unit -> node_parameters > =A0 =A0 =A0 =A0(* the real computation is defined in a non virtual method > later, as simply as possible *) > =A0 =A0 =A0 =A0method virtual process: int -> int > =A0 =A0 =A0 =A0(* process and store: call process, then store in cache. > called on a cache miss *) > =A0 =A0 =A0 =A0method private pstore: (int * int) =3D > =A0 =A0 =A0 =A0 =A0 =A0let prid, data =3D prev #get in > =A0 =A0 =A0 =A0 =A0 =A0(* processing *) > =A0 =A0 =A0 =A0 =A0 =A0let new_data =3D self #process data in > =A0 =A0 =A0 =A0 =A0 =A0(* we're in a cache miss: bump the serial +1 *) > =A0 =A0 =A0 =A0 =A0 =A0self #inc_id ; > =A0 =A0 =A0 =A0 =A0 =A0let myid =3D self #get_id in > =A0 =A0 =A0 =A0 =A0 =A0Hashtbl.add hres (parms #get_parh Plus1 myid) new_= data ; > =A0 =A0 =A0 =A0 =A0 =A0(myid, new_data) > =A0 =A0 =A0 =A0method get =3D > =A0 =A0 =A0 =A0 =A0 =A0try > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(* memoize id to avoid race cond *) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0let myid =3D self #get_id in > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(* here again in the real code, we lookup = the hash > using (parms #get_parh (self #ptyp ()) myid) *) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0let data =3D Hashtbl.find hres (parms #get= _parh Plus1 myid) in > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(myid, data) > =A0 =A0 =A0 =A0 =A0 =A0with Not_found -> Printf.printf "node_virt #get: c= ache > 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 =3D > =A0 =A0object(self) > =A0 =A0 =A0 =A0inherit node_virt prev parm hn > =A0 =A0 =A0 =A0method ptyp () =3D Plus1 > =A0 =A0 =A0 =A0(* > =A0 =A0 =A0 =A0 =A0 =A0MY QUESTION: what is the best way to allow not onl= y int -> > int for this process method, > =A0 =A0 =A0 =A0 =A0 =A0but also: int -> float, float -> int, float -> flo= at ? > =A0 =A0 =A0 =A0 =A0 =A0The method minimizing the code written in this non= virtual > node definition, since I may end with 15 or 30 > =A0 =A0 =A0 =A0 =A0 =A0differents derived class of node_virt like this si= ngle one ? > =A0 =A0 =A0 =A0*) > =A0 =A0 =A0 =A0method process n =3D > =A0 =A0 =A0 =A0 =A0 =A0n + (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 =3D > =A0 =A0object(self) > =A0 =A0 =A0 =A0val parms =3D parm > =A0 =A0 =A0 =A0method get =3D > =A0 =A0 =A0 =A0 =A0 =A0(0, 1) > end > > > let () =3D > =A0 =A0let p =3D new parameters in > =A0 =A0p #set_sf 44100 ; (* useless indeed, just for demo *) > =A0 =A0p #set_add 2 ; (* usefull *) > =A0 =A0let n0 =3D new node_head p in > =A0 =A0let n1 =3D new node_plus n0 p 3 in > =A0 =A0Printf.printf "%d\n" (snd (n0 #get)) ; > =A0 =A0Printf.printf "%d\n" (snd (n1 #get)) ; > =A0 =A0Printf.printf "%d\n" (snd (n1 #get)) ; > =A0 =A0p #set_add 1 ; > =A0 =A0Printf.printf "%d\n" (snd (n1 #get)) >