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 mail3-relais-sop.national.inria.fr (mail3-relais-sop.national.inria.fr [192.134.164.104]) by sympa.inria.fr (Postfix) with ESMTPS id CB6A1800BE for ; Fri, 10 Feb 2017 00:37:49 +0100 (CET) Authentication-Results: mail3-smtp-sop.national.inria.fr; spf=None smtp.pra=info@gerd-stolpmann.de; spf=None smtp.mailfrom=info@gerd-stolpmann.de; spf=None smtp.helo=postmaster@mout.kundenserver.de Received-SPF: None (mail3-smtp-sop.national.inria.fr: no sender authenticity information available from domain of info@gerd-stolpmann.de) identity=pra; client-ip=212.227.17.10; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="info@gerd-stolpmann.de"; x-sender="info@gerd-stolpmann.de"; x-conformance=sidf_compatible Received-SPF: None (mail3-smtp-sop.national.inria.fr: no sender authenticity information available from domain of info@gerd-stolpmann.de) identity=mailfrom; client-ip=212.227.17.10; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="info@gerd-stolpmann.de"; x-sender="info@gerd-stolpmann.de"; x-conformance=sidf_compatible Received-SPF: None (mail3-smtp-sop.national.inria.fr: no sender authenticity information available from domain of postmaster@mout.kundenserver.de) identity=helo; client-ip=212.227.17.10; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="info@gerd-stolpmann.de"; x-sender="postmaster@mout.kundenserver.de"; x-conformance=sidf_compatible IronPort-PHdr: =?us-ascii?q?9a23=3AS9s7dBPxsZXmxtGxbsMl6mtUPXoX/o7sNwtQ0KIM?= =?us-ascii?q?zox0I/3zrarrMEGX3/hxlliBBdydsKMYzbqI+Pi9EUU7or+5+EgYd5JNUxJXwe?= =?us-ascii?q?43pCcHRPC/NEvgMfTxZDY7FskRHHVs/nW8LFQHUJ2mPw6arXK99yMdFQviPgRp?= =?us-ascii?q?OOv1BpTSj8Oq3Oyu5pHfeQtFiT6ybL9oLxi7rArdutUWjIB/Nqs/1xzFr2dSde?= =?us-ascii?q?9L321oP1WTnxj95se04pFu9jlbtuwi+cBdT6j0Zrw0QrNEAjsoNWA1/9DrugLY?= =?us-ascii?q?TQST/HscU34ZnQRODgPY8Rz1RJbxsi/9tupgxCmXOND9QL4oVTi+6apgVQTlgz?= =?us-ascii?q?kbOTEn7G7Xi9RwjKNFrxKnuxx/2JPfbIWMOPZjYq/RYdYWSGxcVchTSiNBGJux?= =?us-ascii?q?YYgSAeQBI+hWoYvyp1USohW5CgahH+zvxiNSi3Lsx6A2z+YsHAfb1wIgBdIOt3?= =?us-ascii?q?HUoc30OqgMS+C60bTDwyjfb/NR3Tf98I3IfQonofGKQLl9dsvRyU8hFwPClViQ?= =?us-ascii?q?ppLqPymI2egUqGib8+1gVea3i24isQ5xpD6vyt0xhYbXn48YzE3P+yt+wIYwP9?= =?us-ascii?q?K4SUh7bMarEJROrSGVKpJ6Qtg+Q2FvvCY60rgGtoS9fCgM0pgo2gDQZ+SbfIeS?= =?us-ascii?q?5xLjUPqeITZkhHNlYr6/gAyy8Uemx+bhVce0yE5HojRYntXSrHwByQLf58qdRv?= =?us-ascii?q?dg/EqtwyuD2xzL5uxHIU04j7fXJp0vz7Iql5cetV7PEjL3lUnriqKda18q9fKy?= =?us-ascii?q?6+v9Z7Xrvp+cOJFwigH5Kqkun8u/AfkkMgQUXGib5OK826D98k3/W7VFkOc2kr?= =?us-ascii?q?fHv5DAP8gUu7C2DxdU0oYl9Rm/Ey+r3MoFkXUZNl5JZgyLgorzN13TIv30F+qz?= =?us-ascii?q?j0i0nDdu3f/GP7nhApvXLnjElbfsZbd960hSyAo01t1f6IxbCqscL/7qQU/xqN?= =?us-ascii?q?vYDhshMwyx2ennDtN92pkDVm2RGqOZKr/dsUeU5uIzJOmBfJMatyz4K/gh/vLu?= =?us-ascii?q?iX45mUQBfaSyxpsWaHW4Hux8LEmDYHrshM0BEWYQsQYkQuzqkg7KbTkGXGq/Ua?= =?us-ascii?q?wx4HkADYWiDo6LEpuoh7iC1Q+wBdtdYXpAB1SIV3rkatPAE9UBci+XM4dQmzgA?= =?us-ascii?q?UqDpH54o0RWprCf1zrNmKqzf/ShO5rz5090gyODJmVkJ6TtwF8GU1WfFG2BykG?= =?us-ascii?q?QgSDIs0OVkvUt50lKK164+j/EORo8b3O9ATgpvbc2U9Od9Ed2nH1uZJto=3D?= X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: =?us-ascii?q?A0BmAABH/JxYhwoR49RdDgwBAQEBAgEBA?= =?us-ascii?q?QEIAQEBARYBAQEDAQEBCQEBAYJEgUOBCYNZigiSCogMh3mFMYINJoV8AoJsPxg?= =?us-ascii?q?BAQEBAQEBAQEBARIBAQEIDQkKHS+CMxsBghoBAQEDASMELiQFCwsYKgICITYGA?= =?us-ascii?q?RIJiVMDDQwBCbAQgWs6hzoNhA4BAQEBAQUBAQEBAQEBEg+FW4VgglGCD4JAOoJ?= =?us-ascii?q?fBYkMkiw6gVUChlqBXoNsjlOGS4o1iGAfgTYyHhQ8hFWBMjx0AYl6AQEB?= X-IPAS-Result: =?us-ascii?q?A0BmAABH/JxYhwoR49RdDgwBAQEBAgEBAQEIAQEBARYBAQE?= =?us-ascii?q?DAQEBCQEBAYJEgUOBCYNZigiSCogMh3mFMYINJoV8AoJsPxgBAQEBAQEBAQEBA?= =?us-ascii?q?RIBAQEIDQkKHS+CMxsBghoBAQEDASMELiQFCwsYKgICITYGARIJiVMDDQwBCbA?= =?us-ascii?q?QgWs6hzoNhA4BAQEBAQUBAQEBAQEBEg+FW4VgglGCD4JAOoJfBYkMkiw6gVUCh?= =?us-ascii?q?lqBXoNsjlOGS4o1iGAfgTYyHhQ8hFWBMjx0AYl6AQEB?= X-IronPort-AV: E=Sophos;i="5.35,138,1484002800"; d="asc'?scan'208,217";a="212706199" Received: from mout.kundenserver.de ([212.227.17.10]) by mail3-smtp-sop.national.inria.fr with ESMTP/TLS/DHE-RSA-AES128-GCM-SHA256; 10 Feb 2017 00:37:48 +0100 Received: from office1.lan.sumadev.de ([85.183.69.161]) by mrelayeu.kundenserver.de (mreue103 [212.227.15.183]) with ESMTPSA (Nemesis) id 0MYcc6-1cyOxm45Uw-00VOME; Fri, 10 Feb 2017 00:37:45 +0100 Received: from e130 (unknown [192.168.65.10]) by office1.lan.sumadev.de (Postfix) with ESMTPSA id AE642DC05D; Fri, 10 Feb 2017 00:37:42 +0100 (CET) Message-ID: <1486683451.12698.83.camel@gerd-stolpmann.de> From: Gerd Stolpmann To: Steffen Smolka , Jeremy Yallop Cc: Caml List Date: Fri, 10 Feb 2017 00:37:31 +0100 In-Reply-To: References: Content-Type: multipart/signed; micalg="pgp-sha256"; protocol="application/pgp-signature"; boundary="=-1u7OTUdQo5eG90j1yC/j" X-Mailer: Evolution 3.18.5.2-0ubuntu3.1 Mime-Version: 1.0 X-Provags-ID: V03:K0:ePw9e/CFDxLlJMqVj+4zBHiA/PjY8Ed/fgh5duOrwcVw2FHQvfR /RbGQ9ZTCy26s2V3x31b44OS+V6s51PK46VBW3JomPguSIcsR6+YjrJTU5U5qPf9MgpwicX yWP2wkP5Kw2FVqyRhY89wmLKGXiOH0FdYmm2TQjb+Wf1ah3oLyLGujPjxVFoozfh1yagEWk w6S+XylArBIGTXtw7VQDg== X-UI-Out-Filterresults: notjunk:1;V01:K0:9rmhzW/p1Pw=:fYSTPGEk/n16HFtTaTGtGA i5Tmljogl/7c0m129Obp6K3l/bOHU6xJK7KW5djsxIZAqz4RLgS/5dQpRN0Azx+/s+ArMmwXA FO55KpAhdRIahU7bx9+o5VwvV4TXpx6Y3dNSFLqlvnugXeSt1mpcdsZ7p/d3fVVEIW4gJe+dT 4cmHfd1A1C4GteaQU3jRTaDFh2bibWlk3Dc3t7HG3QQwWzfgSja2179E8Hh5NXYlM1iWynZf4 +0fQyEuxlR6hhezBbbd4Qj4GhDypIpptH0Xxqm7pZHPKxk2R/a4OfPPCBEo5dBwMTbqNbgCJs 6c00Ymg2qSZLTwsIGd7BxbkifZbrleMEG6WDcF+KCPBvLrrtd1ZPYb/b5VafaDqBrU7Bd3OIZ ZIhTZH/3iLBFsjrHHf+gQhmJeGhJhLMa+BQlJCOsPg5U0V71y+symGVF2WTFgBLvSfZM+9Djy 3/HzZrE7y8AMFWsnbKCX1VzB4XDhv7g8rBzp6NkLwaDv2B7HrYOWBpExk3Dz41eN/omZiaYrS GWVQNjYUk5PlJMZsykTsfBS/eA24fRqsRa2PErmacRGYMxrYRWPyHe02yhXmG2T9hsMxJCOHN PHi3iaTme5Jlhp7jYbkpyWFImQ3Zf9TMPxzgpPBnBUJ5s9cW9qap7hLZYqB9/pJUAIPmzbvT+ 0J7ThyS2TREYYlHdpjvn/goQf+OjcohDl8imRxfLgJxeZw2BnA/lcsjWctVIoe/fFyIc= Subject: Re: [Caml-list] namespace inside object? --=-1u7OTUdQo5eG90j1yC/j Content-Type: multipart/alternative; boundary="=-hEpog4qnRjB1HP35gEkq" --=-hEpog4qnRjB1HP35gEkq Content-Type: text/plain; charset="ISO-8859-15" Content-Transfer-Encoding: quoted-printable Am Donnerstag, den 09.02.2017, 18:19 -0500 schrieb Steffen Smolka: > Thanks for the detailed answer, Jeremy! >=20 > > 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 :) )=A0 >=20 > 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. >=20 > 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: =A0Let's assume both the base module and the modified one can use the same module type: module T =3D sig ... end Now, define the base module like module Base : T =3D =A0 =A0... end then, define the modified one: module Mod : T =3D =A0 =A0include Base =A0 =A0... 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 =3D (module Base : T) let mod =3D (module Mod : T) The syntax for unpacking the module is quite cumbersome: let module M =3D (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 con= tainers" * However, there's no dynamic dispatch except you arrange explicitly for t= hat, e.g. with references to functions * Generally, a heavier syntax, but it might be ok Gerd > > > Or you could select the encoding using a=A0> > 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 imple= mentations. I would rather keep them separate. > > -- Steffen > =A0 > On Thu, Feb 9, 2017 at 5:55 PM, Jeremy Yallop > > wrot= e: > > Dear Steffen, > >=20 > >=20 > > On 9 February 2017 at 20:36, Steffen Smolka wro= te: > >=20 > > > Is it possible to create namespaces inside an object? Concretely, I w= ould > >=20 > > > like to write > >=20 > > > > >=20 > > > class buffer =3D object(self) > >=20 > > >=A0 =A0... > >=20 > > >=A0 =A0method get =3D ... > >=20 > > > > >=20 > > >=A0 =A0module Latin1 =3D struct > >=20 > > >=A0 =A0 =A0method get =3D ... > >=20 > > >=A0 =A0end > >=20 > > > > >=20 > > >=A0 =A0module Utf8 =3D struct > >=20 > > >=A0 =A0 =A0method get =3D ... > >=20 > > >=A0 =A0end > >=20 > > > end > >=20 > > > > >=20 > > > so that given an object b : buffer, I can call methods > >=20 > > > b#get > >=20 > > > b#Latin1.get > >=20 > > > b#Utf8.get > >=20 > >=20 > > It's possible to achieve something like this using methods that return > >=20 > > objects.=A0 If your nested objects don't need to access the internal > >=20 > > state of the parent then you might write it like this: > >=20 > >=20 > > =A0 class buffer =3D > >=20 > > =A0 =A0 let latin1 =3D object > >=20 > > =A0 =A0 =A0 method get =3D ... > >=20 > > =A0 =A0end > >=20 > > =A0 =A0and utf8 =3D object > >=20 > > =A0 =A0 =A0 method get =3D ... > >=20 > > =A0 =A0end in > >=20 > > =A0 =A0object(self) > >=20 > > =A0 =A0 =A0... > >=20 > > =A0 =A0 =A0method get =3D ... > >=20 > > =A0 =A0 =A0method latin1 =3D latin1 > >=20 > > =A0 =A0 =A0method utf8 =3D utf8 > >=20 > > =A0 =A0end > >=20 > >=20 > > With this approach you can write > >=20 > >=20 > > =A0 =A0b#get > >=20 > > =A0 =A0b#latin1#get > >=20 > > =A0 =A0b#utf8#get > >=20 > >=20 > > which, apart from some minor orthographic differences, looks like what > >=20 > > you were aiming for. > >=20 > >=20 > > Your intuition that this isn't really idiomatic OCaml is right, > >=20 > > though.=A0 In OCaml, unlike some other languages with classes and > >=20 > > objects, classes are not usually used as namespaces; method names are > >=20 > > globally (or, rather, "ambiently") scoped, and there's no real support > >=20 > > for the kind of nesting that you're interested in.=A0 Instead, people > >=20 > > typically build nested namespaces using modules: > >=20 > >=20 > > =A0 module Buffer =3D > >=20 > > =A0 struct > >=20 > > =A0 =A0 =A0let get =3D ... > >=20 > >=20 > > =A0 =A0 =A0module Latin1 =3D struct > >=20 > > =A0 =A0 =A0 =A0 let get =3D ... > >=20 > > =A0 =A0 =A0end > >=20 > >=20 > > =A0 =A0 =A0module Utf8 =3D struct > >=20 > > =A0 =A0 =A0 =A0 let get =3D ... > >=20 > > =A0 =A0 =A0end > >=20 > > =A0 end > >=20 > >=20 > > With the module approach you write the 'receiver' after the 'method' > >=20 > > rather than before, but that doesn't seem like a huge hardship.=A0 (10% > >=20 > > of the world manages to get by with VSO languages.) > >=20 > >=20 > > =A0 Buffer.get b ... > >=20 > > =A0 Buffer.Latin1.get b ... > >=20 > > =A0 Buffer.Utf8.get b ... > >=20 > >=20 > > If you're keen to stick with objects there are slightly more idiomatic > >=20 > > ways to make it work.=A0 You could, of course, replace the '.' with a > >=20 > > '_' and define methods 'latin1_get', 'utf8_get' in place of > >=20 > > 'Latin1.get', 'Utf8.get'.=A0 Or you could select the encoding using a > >=20 > > variant type: > >=20 > >=20 > > =A0 type enc =3D Latin1 | Utf8 > >=20 > >=20 > > =A0 class buffer =3D > >=20 > > =A0 object (self) > >=20 > > =A0 =A0 =A0method get =3D function > >=20 > > =A0 =A0 =A0 =A0 =A0| Latin1 -> ... > >=20 > > =A0 =A0 =A0 =A0 =A0| Utf8 -> ... > >=20 > > =A0 end > >=20 > >=20 > > Of course, the order of the words in an invocation changes again, but > >=20 > > there's no real increase in complexity for the caller: > >=20 > >=20 > > =A0 b#get Latin1 > >=20 > > =A0 b#get Utf8 > >=20 > >=20 > > This last approach can be taken quite far -- for example, you could > >=20 > > enrich the type 'enc' so that the return type of 'get' varies > >=20 > > according to the encoding. > >=20 > >=20 > > Kind regards, > >=20 > >=20 > > Jeremy > >=20 >=20 --=20 ------------------------------------------------------------ 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 ------------------------------------------------------------ --=-hEpog4qnRjB1HP35gEkq Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: quoted-printable
Am Donnerstag, den 09.02.2017, 18:19 -0500 sc= hrieb Steffen Smolka:
Thank= s for the detailed answer, Jeremy!

If you're keen to stick with objects
<= /blockquote>

Yes, I rely on inheritance and dynami= c dispatch for what I have in mind. (This is actually the first time I'm to= uching the dark object oriented side of OCaml :) ) 

To give some more context, I am refactoring some code that uses modu= les 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. Inheritanc= e + dynamic dispatch allow me to do so with very little trouble: I can simp= ly 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 implementatio= n needs to replace. I think it won't be quite as natural, but I'll give tha= t a try.

First-class modules co= uld also be an option:  Let's assume both the base module and the modi= fied one can use the same module type:

module T = =3D sig ... end

Now, define the base module like

module Base : T =3D
   ...
end

then, define the modified one:

module Mod : T =3D
   include Base
   ... now override what you need to change but note that t= here's no dynamic dispatch ...
end

Of co= urse, you could also use functors for making these modules.

<= /div>
Now turn this into first-class modules and pass them around:

let base =3D (module Base : T)
let mod =3D (= module Mod : T)

The syntax for unpacking the modul= e is quite cumbersome:

let module M =3D (val base = : T) in
M.function ...

Unfortunately, th= ere's nothing simple like base.function.

Compared = with objects you get:

  • You can also put types an= d (to some degree) modules into these "code containers"
  • However, th= ere'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:<= br>

Good idea, and I'm happy with the synta= x 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 th= em separate.

-- Steffen
 

On Thu, Feb 9, = 2017 at 5:55 PM, Jeremy Yallop <yallop@gmail.com> wrote:
<= blockquote type=3D"cite">Dear Steffen,

On 9 February 2017 at 20:36, Steffen Smolka <smolka@cs.cornell.edu> wrote:
> Is it possible to create namespaces inside an object? Concretely, I wo= uld
> like to write
>
> class buffer =3D object(self)
>   ...
>   method get =3D ...
>
>   module Latin1 =3D struct
>     method get =3D ...
>   end
>
>   module Utf8 =3D struct
>     method get =3D ...
>   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 retu= rn
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 =3D
    let latin1 =3D object
      method get =3D ...
   end
   and utf8 =3D object
      method get =3D ...
   end in
   object(self)
     ...
     method get =3D ...
     method latin1 =3D latin1
     method utf8 =3D 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 =3D
  struct
     let get =3D ...

     module Latin1 =3D struct
        let get =3D ...
     end

     module Utf8 =3D struct
        let get =3D ...
     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%<= br> 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 =3D Latin1 | Utf8

  class buffer =3D
  object (self)
     method get =3D 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


--=20
------------------------------------------------------------
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
------------------------------------------------------------

= --=-hEpog4qnRjB1HP35gEkq-- --=-1u7OTUdQo5eG90j1yC/j Content-Type: application/pgp-signature; name="signature.asc" Content-Description: This is a digitally signed message part Content-Transfer-Encoding: 7bit -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQEcBAABCAAGBQJYnP07AAoJEAaM4b9ZLB5Tj7sH/3S5z/G4u2i32nHf+iX4MgPF zDz01xojKxpox6wnKriOzogpJ0bM/nnsN2qMnb05qOqvHB0ZSXYt/2B9FKudnrMR YRckwUyU4OgMBKFKNF3yRuG7k0fUDAsXsC5Poai1YZtMoMSI8GWsAhWUfXpS0BMM n3jx/IRFyCATWXDtpdfPTWFczU4byszRxvP1YRuJ1UFqdn7u+4t+kVI8O7wDU0vK rnG0t6rvGtEnwAXEIrL6LTYkFidtuDZjs662nRUi6NUZ6jJhJIdzK7QF61hohvxO o8qB/83qUHA5nc59DE1WCrni//BorZMyubJRP0X9YDUakiw99CXUgbne0QlqIzY= =PVrk -----END PGP SIGNATURE----- --=-1u7OTUdQo5eG90j1yC/j--