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.3 required=5.0 tests=AWL autolearn=disabled version=3.1.3 X-Original-To: caml-list@yquem.inria.fr Delivered-To: caml-list@yquem.inria.fr Received: from mail4-relais-sop.national.inria.fr (mail4-relais-sop.national.inria.fr [192.134.164.105]) by yquem.inria.fr (Postfix) with ESMTP id A331DBBCA for ; Wed, 19 Mar 2008 17:29:43 +0100 (CET) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: Ap4BAO7b4EdC+VqymGdsb2JhbACRAwEBAQEBCAMJCRaSIIZN X-IronPort-AV: E=Sophos;i="4.25,525,1199660400"; d="scan'208";a="23962971" Received: from ik-out-1112.google.com ([66.249.90.178]) by mail4-smtp-sop.national.inria.fr with ESMTP; 19 Mar 2008 17:29:43 +0100 Received: by ik-out-1112.google.com with SMTP id b35so273771ika.3 for ; Wed, 19 Mar 2008 09:29:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=beta; h=domainkey-signature:received:received:message-id:date:from:sender:to:subject:mime-version:content-type:content-transfer-encoding:content-disposition:x-google-sender-auth; bh=f8z1wrGUqaOnpigazSMoYS6kdSPnn7IxWwmMT/yO96M=; b=k3j0BOH8/oaTDgV+RepWdQiRbP91Ia56OtoCDhvbqnQzWV3T0RlIpU6Z7uFmQN26O2yx6Kr02sMc0sSWLFrAtCcXdBcE0gH+C2wfoyBsCdUIeCTbY8dyBx8ncZX8+DilZjUn5OgCgy5Rshb23AZaEIChBu6mrucJQk13DwnV32g= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=beta; h=message-id:date:from:sender:to:subject:mime-version:content-type:content-transfer-encoding:content-disposition:x-google-sender-auth; b=reIG05SCegWs0ddRnsD/IOvVwSILNZdOl2Ka6Bw4LVwBLapXza+qVT9HPwHQ7mrwUDvLomAR0lmm5S8OKzkznTrOBhcTF2tqX7QPmWdPMKuUChlKJi+K1dv9iFnT5winZPenPrx6X9k2GcA27zRSg0V9LCNHO6Tden0fiSYui3o= Received: by 10.142.101.17 with SMTP id y17mr386748wfb.20.1205944182036; Wed, 19 Mar 2008 09:29:42 -0700 (PDT) Received: by 10.142.170.20 with HTTP; Wed, 19 Mar 2008 09:29:42 -0700 (PDT) Message-ID: <4a051d930803190929q60d31012kb6c9d2b03a2d2ca6@mail.gmail.com> Date: Wed, 19 Mar 2008 12:29:42 -0400 From: "Christopher L Conway" Sender: christopherleeconway@gmail.com To: "Caml Mailing List" Subject: The Bridge Pattern in OCaml MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline X-Google-Sender-Auth: 31925611295f86ad X-Spam: no; 0.00; ocaml:01 ocaml:01 trivial:01 subtyping:01 polymorphism:01 functorize:01 subtyping:01 functions:01 short:01 interfaces:01 explicitly:02 define:02 argument:02 objects:02 objects:02 It is often said that almost any programming problem can be solved without touching the OO part of OCaml. I have found this to be largely true and try to avoid using objects whenever possible. One design pattern that comes up frequently that I have never found a suitable non-OO solution for is the Bridge Pattern. In short, the Bridge Pattern is applicable when a client needs access to operations F, G which can be provided by a variety of underlying implementations X, Y, or Z. If the specific implementation isn't important, you create an interface B (a "bridge") with operations F and G, and write both the client and the implementations to the interface B. The client should then be able to access X, Y, or Z interchangeably, e.g., by taking the implementation as an argument at initialization. This is trivial in any OO language (including OCaml using objects) and will typically appear in the first or second chapter of any tutorial on OO programming. This is more or less *the* problem that subtyping polymorphism was designed to solve. My question: is there a non-OO way of achieving the same result in OCaml? The naive approach is to substitute module and module types for objects and interfaces in the OO solution. I'm sure everybody who's come to OCaml from an OO background has tried this approach and found it wanting. The problem is you can't "pass around" a module as if it were an object. You have to do an explicit branch to choose between X, Y, and Z anytime you access F or G. (Even if you functorize the client C, you end up having to explicitly branch to choose between C(X), C(Y), C(Z).) Another solution is to define a structure type including F and G, then pass the structure around as a "dictionary." I.e., to code up a fragment of the object type system by hand in order to avoid dealing with objects in their fully generality. This doesn't work if the interface needs to include types as well as functions. At this point, I typically give up and go with the OO solution. Has anyone come up with an elegant solution that does not require objects and object subtyping? Regards, Chris