From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Original-To: caml-list@sympa.inria.fr Delivered-To: caml-list@sympa.inria.fr Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by sympa.inria.fr (Postfix) with ESMTPS id 1D0B8800BE for ; Fri, 10 Feb 2017 03:01:41 +0100 (CET) Authentication-Results: mail2-smtp-roc.national.inria.fr; spf=None smtp.pra=yminsky@janestreet.com; spf=Pass smtp.mailfrom=yminsky@janestreet.com; spf=None smtp.helo=postmaster@mxout3.mail.janestreet.com Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of yminsky@janestreet.com) identity=pra; client-ip=38.105.200.229; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="yminsky@janestreet.com"; x-sender="yminsky@janestreet.com"; x-conformance=sidf_compatible Received-SPF: Pass (mail2-smtp-roc.national.inria.fr: domain of yminsky@janestreet.com designates 38.105.200.229 as permitted sender) identity=mailfrom; client-ip=38.105.200.229; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="yminsky@janestreet.com"; x-sender="yminsky@janestreet.com"; x-conformance=sidf_compatible; x-record-type="v=spf1" Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of postmaster@mxout3.mail.janestreet.com) identity=helo; client-ip=38.105.200.229; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="yminsky@janestreet.com"; x-sender="postmaster@mxout3.mail.janestreet.com"; x-conformance=sidf_compatible IronPort-PHdr: =?us-ascii?q?9a23=3AeyUtNBFyXGoH+JaPITrKYp1GYnF86YWxBRYc798d?= =?us-ascii?q?s5kLTJ75psqwAkXT6L1XgUPTWs2DsrQf2raQ4/6rAj1Ioc7Y9itdINoUD15NoP?= =?us-ascii?q?5VtjJjKfbNMVf8Iv/uYn5yN+V5f3ghwUuGN1NIEt31fVzYry76xzcTHhLiKVg9?= =?us-ascii?q?fbytScb6xv663OGq+pDVfx4AxH/kOeszf12KqlDqqsQYj4ZkYp00zR/KqzMcYO?= =?us-ascii?q?FRwWBhDVmI2R37/MG9+Jol/ihN7aEP7clFBJTzZaM+BZlZCi8lIihh9cjqswLA?= =?us-ascii?q?XCON730RSXkMnxdURQPC6UepDd/KriLmu78li2GhNsrsQOVxAGz64g=3D=3D?= X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: =?us-ascii?q?A0B2AQACHp1YfeXIaSZdDg0BAQEDAQEBC?= =?us-ascii?q?QEBARUBAQEBAgEBAQEIAQEBAYQHgQkHg1KKepEZiAyHeYUxgg0mhXwCgmUHQRY?= =?us-ascii?q?BAQEBAQEBAQEBARIBAQsUCkyCMwQBFgEEghcBBSMEGQEBEyQBDwsLDQICJgICI?= =?us-ascii?q?QESAQUBHAYTCYlTAxUDC6NDP4saaIFrOoMIAQEFhCwNhA4BAQEBAQEBAQEBAQE?= =?us-ascii?q?BAQEBAQEBARYIEnmFQYRvglGCD4J6gl+JEYc1inc6iDGBXoNsA4QWkQWKNYcZF?= =?us-ascii?q?B6BFSYLgSQfEwgVFTwXBYQZgVJZVwGILIFOAQEB?= X-IPAS-Result: =?us-ascii?q?A0B2AQACHp1YfeXIaSZdDg0BAQEDAQEBCQEBARUBAQEBAgE?= =?us-ascii?q?BAQEIAQEBAYQHgQkHg1KKepEZiAyHeYUxgg0mhXwCgmUHQRYBAQEBAQEBAQEBA?= =?us-ascii?q?RIBAQsUCkyCMwQBFgEEghcBBSMEGQEBEyQBDwsLDQICJgICIQESAQUBHAYTCYl?= =?us-ascii?q?TAxUDC6NDP4saaIFrOoMIAQEFhCwNhA4BAQEBAQEBAQEBAQEBAQEBAQEBARYIE?= =?us-ascii?q?nmFQYRvglGCD4J6gl+JEYc1inc6iDGBXoNsA4QWkQWKNYcZFB6BFSYLgSQfEwg?= =?us-ascii?q?VFTwXBYQZgVJZVwGILIFOAQEB?= X-IronPort-AV: E=Sophos;i="5.35,138,1484002800"; d="scan'208";a="259647449" Received: from mxout3.mail.janestreet.com ([38.105.200.229]) by mail2-smtp-roc.national.inria.fr with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 10 Feb 2017 03:01:39 +0100 Received: from tot-qpr-mailcore1.delacy.com ([172.27.56.68] helo=tot-qpr-mailcore1) by mxout3.mail.janestreet.com with esmtps (TLSv1.2:DHE-RSA-AES256-GCM-SHA384:256) (Exim 4.84_2) (envelope-from ) id 1cc0Wo-0000R2-1x for caml-list@inria.fr; Thu, 09 Feb 2017 21:01:38 -0500 X-JS-Flow: external X-JS-Scanner-attachment: (ok) No attachments Received: by tot-qpr-mailcore1 with JS-mailcore (0.1) (envelope-from ) id BYnR8B-AAADHd-d6; 2017-02-09 21:01:37.959208-05:00 Received: from mail-vk0-f72.google.com ([209.85.213.72]) by mxgoog1.mail.janestreet.com with esmtps (TLSv1.2:AES128-GCM-SHA256:128) (Exim 4.84_2) (envelope-from ) id 1cc0Wn-0004fN-TG for caml-list@inria.fr; Thu, 09 Feb 2017 21:01:37 -0500 Received: by mail-vk0-f72.google.com with SMTP id n125so12514222vke.0 for ; Thu, 09 Feb 2017 18:01:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=janestreet.com; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=Uw6dSonQYDNK1KAxZSbOQvmEJUj0sASYwW+bmIawf2Y=; b=xMrkz+Y4rT3mSckmE3+pHGjUiL9+RM+59z2E13kzfqEE98AsmK1puDLnIsI+fTtT1E 5CozDYDrhR6dSlce7FGsmHu/D7fgJp9mrujWI27z3m9y7OvKu11LE6Buz1diRmFZvw35 LzjkXSV/ttoDNfelRCRRW4cabtnTvbJJFbTUo= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=Uw6dSonQYDNK1KAxZSbOQvmEJUj0sASYwW+bmIawf2Y=; b=D5ntLtan9mbKLcHCgnTkV2oA+74ZznxQkCCjWdBw4HLZQbnoh5sDTYbyNJSdVJpXpX onFKWjXl2WgVrGxQ6LoEXHJJsYk+FPp3qwTsb6CEolHSuB4gitI316a833flyveKnUW6 zmfNPTk8wXP89X97AWkId+m0YS40dOUdu1Ov76zJNTNA4yapmrRh+ELbcipVHEu/ZbSo 4dhIjIiyYM7640t5hMS2wPKCqWdln9vn6GAhL2g7E400RlSYzfLOd0fIBeolMGhP6OAK 5SLGfZ5mdIwgdC7Jfp/RWeJG/3C80+7u87Pj/Q1TjOnewsxLbwDAREezTK3bMx1vk2DU k1Sw== X-Gm-Message-State: AMke39lqSGmuRqyBc+v/S6lZtzW7WLh34/9LNcVAop/EdA+Ls35a46zwKsXXPCwWGr2Rm/fzQgJVogYDWPU9rLbryfoH1CoE78ICGYdHvTOkEwQ2mOWX6z6guTGdbkLhP4BQ1+m3MZj0wbj90+XR X-Received: by 10.31.21.84 with SMTP id 81mr3229118vkv.17.1486692097417; Thu, 09 Feb 2017 18:01:37 -0800 (PST) X-Received: by 10.31.21.84 with SMTP id 81mr3229092vkv.17.1486692097026; Thu, 09 Feb 2017 18:01:37 -0800 (PST) MIME-Version: 1.0 Received: by 10.31.206.133 with HTTP; Thu, 9 Feb 2017 18:01:16 -0800 (PST) In-Reply-To: References: <1486683451.12698.83.camel@gerd-stolpmann.de> From:Yaron Minsky Date: Thu, 9 Feb 2017 21:01:16 -0500 Message-ID: To:Steffen Smolka Cc:Gerd Stolpmann , Jeremy Yallop , Caml List Content-Type: text/plain; charset=UTF-8 X-JS-Processed-by: mailcore Subject: Re: [Caml-list] namespace inside object? I've always been a bit confused about what the term "dynamic dispatch" means, but don't first class modules provide what you want? After all, when you write: let f (module M : S) x = M.g x the specific function M.g is determined dynamically, depending on which first class module is passed into f. y On Thu, Feb 9, 2017 at 6:54 PM, Steffen Smolka wrote: > Yeah, I have seen that there is support for first class modules, that's > pretty cool stuff! > I do need dynamic dispatch, though. > > -- Steffen > > On Thu, Feb 9, 2017 at 6:37 PM, Gerd Stolpmann > wrote: >> >> Am Donnerstag, den 09.02.2017, 18:19 -0500 schrieb Steffen Smolka: >> >> Thanks for the detailed answer, Jeremy! >> >> If you're keen to stick with objects >> >> >> Yes, I rely on inheritance and dynamic dispatch for what I have in mind. >> (This is actually the first time I'm touching the dark object oriented side >> of OCaml :) ) >> >> To give some more context, I am refactoring some code that uses modules >> and no objects. The reason I want to move to objects is that I want to >> derive a slightly enhanced module from some base implementation. Inheritance >> + dynamic dispatch allow me to do so with very little trouble: I can simply >> overwrite a few methods from the base implementation. >> >> I suppose I could achieve the same by turning the base module into a >> functor, and abstracting over the functions that my enhanced implementation >> needs to replace. I think it won't be quite as natural, but I'll give that a >> try. >> >> >> First-class modules could also be an option: Let's assume both the base >> module and the modified one can use the same module type: >> >> module T = sig ... end >> >> Now, define the base module like >> >> module Base : T = >> ... >> end >> >> then, define the modified one: >> >> module Mod : T = >> include Base >> ... now override what you need to change but note that there's no >> dynamic dispatch ... >> end >> >> Of course, you could also use functors for making these modules. >> >> Now turn this into first-class modules and pass them around: >> >> let base = (module Base : T) >> let mod = (module Mod : T) >> >> The syntax for unpacking the module is quite cumbersome: >> >> let module M = (val base : T) in >> M.function ... >> >> Unfortunately, there's nothing simple like base.function. >> >> Compared with objects you get: >> >> You can also put types and (to some degree) modules into these "code >> containers" >> However, there's no dynamic dispatch except you arrange explicitly for >> that, e.g. with references to functions >> Generally, a heavier syntax, but it might be ok >> >> >> Gerd >> >> >> >> Or you could select the encoding using a variant type: >> >> >> Good idea, and I'm happy with the syntax for the caller. But I'm more >> concerned with the organization of the code; this would mix the Latin1 and >> Utf8 implementations. I would rather keep them separate. >> >> -- Steffen >> >> >> On Thu, Feb 9, 2017 at 5:55 PM, Jeremy Yallop wrote: >> >> Dear Steffen, >> >> On 9 February 2017 at 20:36, Steffen Smolka wrote: >> > Is it possible to create namespaces inside an object? Concretely, I >> > would >> > like to write >> > >> > class buffer = object(self) >> > ... >> > method get = ... >> > >> > module Latin1 = struct >> > method get = ... >> > end >> > >> > module Utf8 = struct >> > method get = ... >> > end >> > end >> > >> > so that given an object b : buffer, I can call methods >> > b#get >> > b#Latin1.get >> > b#Utf8.get >> >> It's possible to achieve something like this using methods that return >> objects. If your nested objects don't need to access the internal >> state of the parent then you might write it like this: >> >> class buffer = >> let latin1 = object >> method get = ... >> end >> and utf8 = object >> method get = ... >> end in >> object(self) >> ... >> method get = ... >> method latin1 = latin1 >> method utf8 = utf8 >> end >> >> With this approach you can write >> >> b#get >> b#latin1#get >> b#utf8#get >> >> which, apart from some minor orthographic differences, looks like what >> you were aiming for. >> >> Your intuition that this isn't really idiomatic OCaml is right, >> though. In OCaml, unlike some other languages with classes and >> objects, classes are not usually used as namespaces; method names are >> globally (or, rather, "ambiently") scoped, and there's no real support >> for the kind of nesting that you're interested in. Instead, people >> typically build nested namespaces using modules: >> >> module Buffer = >> struct >> let get = ... >> >> module Latin1 = struct >> let get = ... >> end >> >> module Utf8 = struct >> let get = ... >> end >> end >> >> With the module approach you write the 'receiver' after the 'method' >> rather than before, but that doesn't seem like a huge hardship. (10% >> of the world manages to get by with VSO languages.) >> >> Buffer.get b ... >> Buffer.Latin1.get b ... >> Buffer.Utf8.get b ... >> >> If you're keen to stick with objects there are slightly more idiomatic >> ways to make it work. You could, of course, replace the '.' with a >> '_' and define methods 'latin1_get', 'utf8_get' in place of >> 'Latin1.get', 'Utf8.get'. Or you could select the encoding using a >> variant type: >> >> type enc = Latin1 | Utf8 >> >> class buffer = >> object (self) >> method get = function >> | Latin1 -> ... >> | Utf8 -> ... >> end >> >> Of course, the order of the words in an invocation changes again, but >> there's no real increase in complexity for the caller: >> >> b#get Latin1 >> b#get Utf8 >> >> This last approach can be taken quite far -- for example, you could >> enrich the type 'enc' so that the return type of 'get' varies >> according to the encoding. >> >> Kind regards, >> >> Jeremy >> >> >> -- >> ------------------------------------------------------------ >> Gerd Stolpmann, Darmstadt, Germany gerd@gerd-stolpmann.de >> My OCaml site: http://www.camlcity.org >> Contact details: http://www.camlcity.org/contact.html >> Company homepage: http://www.gerd-stolpmann.de >> ------------------------------------------------------------ >> >