From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Delivered-To: caml-list@yquem.inria.fr Received: from concorde.inria.fr (concorde.inria.fr [192.93.2.39]) by yquem.inria.fr (Postfix) with ESMTP id 15E06BB81 for ; Thu, 9 Dec 2004 03:07:49 +0100 (CET) Received: from pauillac.inria.fr (pauillac.inria.fr [128.93.11.35]) by concorde.inria.fr (8.13.0/8.13.0) with ESMTP id iB927mY2009541 for ; Thu, 9 Dec 2004 03:07:48 +0100 Received: from concorde.inria.fr (concorde.inria.fr [192.93.2.39]) by pauillac.inria.fr (8.7.6/8.7.3) with ESMTP id DAA06576 for ; Thu, 9 Dec 2004 03:07:48 +0100 (MET) Received: from rdcmx1.safeco.com (rdcmx1.safeco.com [12.144.132.31]) by concorde.inria.fr (8.13.0/8.13.0) with ESMTP id iB927kdS009536 for ; Thu, 9 Dec 2004 03:07:47 +0100 Received: from psmrdcex03.psm.pin.safeco.com (Not Verified[12.144.134.38]) by rdcmx1.safeco.com id ; Wed, 08 Dec 2004 18:07:43 -0800 Received: from safeco.com ([168.147.237.20]) by psmrdcex03.psm.pin.safeco.com with Microsoft SMTPSVC(5.0.2195.6713); Wed, 8 Dec 2004 18:07:43 -0800 X-MimeOLE: Produced By Microsoft Exchange V6.0.6487.1 MIME-Version: 1.0 Subject: environment idiom Date: Wed, 8 Dec 2004 18:07:42 -0800 Message-ID: <9410EC84C0872141B27A2726613EF45D02A52E08@psmrdcex01.psm.pin.safeco.com> Thread-Topic: environment idiom Thread-Index: AcTdk94NgTK5sZddRci+cThhsfzPRQ== From: "HENRIKSON, JEFFREY" To: X-OriginalArrivalTime: 09 Dec 2004 02:07:43.0336 (UTC) FILETIME=[DE568680:01C4DD93] content-class: urn:content-classes:message Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable X-Miltered: at concorde with ID 41B7B374.000 by Joe's j-chkmail (http://j-chkmail.ensmp.fr)! X-Miltered: at concorde with ID 41B7B372.001 by Joe's j-chkmail (http://j-chkmail.ensmp.fr)! X-Spam: no; 0.00; henrikson:01 caml-list:01 threads:01 ocaml:01 variants:01 foo:01 compiler:01 foo:01 val:01 val:01 hashtbl:01 hashtbl:01 failwith:01 failwith:01 idioms:01 X-Spam-Checker-Version: SpamAssassin 3.0.0 (2004-09-13) on yquem.inria.fr X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=disabled version=3.0.0 X-Spam-Level: caml-list, I am interested in the idiom of passing a number of parameters by some kind of "environment" variable. Think of a web server with hundredes of functions for processing markup and other things, only 3 of which need to detect the browser. It's bad maintainability to explicitly pass browserid through hundreds of functions which don't use it. And of course, we must separate the state of the calling threads so as to not cheat with global variables or some such thing. There seem to be two main candidates for such an idiom in Ocaml, objects and polymorphic variants. The object way, roughly: let bar env s =3D env#pear ^ s;; let foo env s =3D let x =3D env#apple in let y =3D env#banana in bar env (x^y^s);; As long as we never name the classes the compiler keeps track of which environment methods the foo call chain has by creating ad hoc classes: # val bar : < pear : string; .. > -> string -> string =3D # val foo : < apple : string; banana : string; pear : string; .. > -> string -> string =3D And the polymorphic variant way, roughly: let h =3D Hashtbl.create 10;; Hashtbl.add h `Banana (`Banana "b");; Hashtbl.add h `Apple (`Apple "a");; Hashtbl.add h `Pear (`Pear "p");; let get_apple h =3D try match Hashtbl.find h `Apple with `Apple n -> n | _ -> failwith "no apple config key" with Not_found -> failwith "no apple config key";; let get_banana h =3D try match Hashtbl.find h `Banana with `Banana n -> n | _ -> failwith "no banana config key" with Not_found -> failwith "no banana config key";; let get_pear h =3D try match Hashtbl.find h `Pear with `Pear n -> n | _ -> failwith "no pear config key" with Not_found -> failwith "no pear config key";; let bar env s =3D (get_pear env) ^ s;; # val bar : ([> `Pear ], [> `Pear of string ]) Hashtbl.t -> string -> string =3D let foo env s =3D let x =3D get_apple env in let y =3D get_banana env in bar env (x^y^s);; # val foo : ([> `Apple | `Banana | `Pear ], [> `Apple of string | `Banana of string | `Pear of string ]) Hashtbl.t -> string -> string =3D foo h "5";; # - : string =3D "pab5" Each of these idioms has its own advantage: In the object way the compiler verifies that the functions are passed objects which contain all their needed configuration keys. But if I understand correctly, we must at some point construct an environment object which has _all_ the keys, even if we don't know them yet. We can add by mutation, but we cannot simply leave them out and add them as we get to functions which need them. This is because while we can write object method apple =3D "a" method banana =3D "b" end;; - : < apple : string; banana : string > =3D we cannot inherit anonymously: let add_pear env =3D object inherit env method pear =3D "p" end;; # Characters 40-43: inherit env ^^^ Unbound class env In the pv way the construction can be made incremental. Ie, if we changed the hashtable to a list or immutable queue, we could add keys as we go. But at least as I have it set up, the variants are not placing restrictions on the existence of keys in the environment, other than saying "we can understand at least this many keys," which is of course meaningless. Is there a way to turn the typing around to say "we require at least these keys"? In general, what are the typing and run-time limitations around each way? Regards, Jeff Henrikson