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 88D09800BE for ; Fri, 10 Feb 2017 00:19:16 +0100 (CET) Authentication-Results: mail2-smtp-roc.national.inria.fr; spf=None smtp.pra=sjs429@cornell.edu; spf=Pass smtp.mailfrom=sjs429@cornell.edu; spf=Pass smtp.helo=postmaster@limerock02.mail.cornell.edu Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of sjs429@cornell.edu) identity=pra; client-ip=128.84.13.242; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="sjs429@cornell.edu"; x-sender="sjs429@cornell.edu"; x-conformance=sidf_compatible Received-SPF: Pass (mail2-smtp-roc.national.inria.fr: domain of sjs429@cornell.edu designates 128.84.13.242 as permitted sender) identity=mailfrom; client-ip=128.84.13.242; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="sjs429@cornell.edu"; x-sender="sjs429@cornell.edu"; x-conformance=sidf_compatible; x-record-type="v=spf1" Received-SPF: Pass (mail2-smtp-roc.national.inria.fr: domain of postmaster@limerock02.mail.cornell.edu designates 128.84.13.242 as permitted sender) identity=helo; client-ip=128.84.13.242; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="sjs429@cornell.edu"; x-sender="postmaster@limerock02.mail.cornell.edu"; x-conformance=sidf_compatible; x-record-type="v=spf1" IronPort-PHdr: =?us-ascii?q?9a23=3AMgOO2R2AH4OmbEFhsmDT+DRfVm0co7zxezQtwd8Z?= =?us-ascii?q?segXK/ad9pjvdHbS+e9qxAeQG96Kt7QU1aGO7uigATVGusnR9ihaMdRlbFwst4?= =?us-ascii?q?Y/p0QYGsmLCEn2frbBThcRO4B8bmJj5GyxKkNPGczzNBX4q3y26iMOSF2kbVIm?= =?us-ascii?q?bsy8IIPZjty22uau4NWTJlwQ3HvuKY91eTe7twjUp4EniI9mLb55ngrApn9PY8?= =?us-ascii?q?xZwGppIRSYmBOqtemq+5s2yDhdtfws8YZ7VKL+fK1wGaddCzAlOkg+/4vgsgPF?= =?us-ascii?q?QA+LoHYQTzNFwVJzHwHZ4USiDd/KuSzgu784gXHCMA=3D=3D?= X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: =?us-ascii?q?A0A5AQB7+JxYh/INVIBdGwEBAQMBAQEJA?= =?us-ascii?q?QEBFgEBAQMBAQEJAQEBgkSCGAMxB4NSgTaJRJEYiAyHeYc/iQgHQxQBAQEBAQE?= =?us-ascii?q?BAQEBARIBAQEKCwkKHS+CMwQBFgEEghYBAQQBIwRSBQsBCAILDSoCAiEBEgEFA?= =?us-ascii?q?RwGDgWJXAMNCAWSSJENP4wCgWs6hzoNRQeDTQEBAQEjEospglGFCYJfAQSQQYp?= =?us-ascii?q?3OogxgV6DbIQZkQWKNYcZFB6BFTaBHx8TCBcTPBcFhkRXiC2BTgEBAQ?= X-IPAS-Result: =?us-ascii?q?A0A5AQB7+JxYh/INVIBdGwEBAQMBAQEJAQEBFgEBAQMBAQE?= =?us-ascii?q?JAQEBgkSCGAMxB4NSgTaJRJEYiAyHeYc/iQgHQxQBAQEBAQEBAQEBARIBAQEKC?= =?us-ascii?q?wkKHS+CMwQBFgEEghYBAQQBIwRSBQsBCAILDSoCAiEBEgEFARwGDgWJXAMNCAW?= =?us-ascii?q?SSJENP4wCgWs6hzoNRQeDTQEBAQEjEospglGFCYJfAQSQQYp3OogxgV6DbIQZk?= =?us-ascii?q?QWKNYcZFB6BFTaBHx8TCBcTPBcFhkRXiC2BTgEBAQ?= X-IronPort-AV: E=Sophos;i="5.35,138,1484002800"; d="scan'208,217";a="259639586" Received: from limerock02.mail.cornell.edu ([128.84.13.242]) by mail2-smtp-roc.national.inria.fr with ESMTP; 10 Feb 2017 00:19:15 +0100 X-CornellRouted: This message has been Routed already. Received: from exchange.cornell.edu (sf-e2013-06.exchange.cornell.edu [10.22.40.53]) by limerock02.mail.cornell.edu (8.14.4/8.14.4_cu) with ESMTP id v19NJ7Jo000722 for ; Thu, 9 Feb 2017 18:19:13 -0500 Received: from sf-e2013-02.exchange.cornell.edu (10.22.40.49) by sf-e2013-06.exchange.cornell.edu (10.22.40.53) with Microsoft SMTP Server (TLS) id 15.0.1210.3; Thu, 9 Feb 2017 18:19:02 -0500 Received: from mail-wr0-f198.google.com (209.85.128.198) by exchange.cornell.edu (10.22.40.49) with Microsoft SMTP Server (TLS) id 15.0.1210.3 via Frontend Transport; Thu, 9 Feb 2017 18:19:02 -0500 Received: by mail-wr0-f198.google.com with SMTP id u65so9824768wrc.6 for ; Thu, 09 Feb 2017 15:19:13 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:sender:in-reply-to:references:from :date:message-id:subject:to:cc; bh=eJ05EGsUM8ec497edNrvuPS8L9/F262C3DMr+5XiWM0=; b=duGe62V7fzuatIMSrhLKRK6sbwkLzAsj1m58hknFkN/Ly/s0lcF4Nj7LxpztnDRum9 B5lf0r81nW0YrRF3+eBfhuKiF1YWAqEZjyZJs/faT40bcqjjTkLg4YIRWbk45lfE8spo Nhv9ZtGQ1fMZ4akkzzetqLhI+ZZ4TWfDKRylaR4ZRdyFG/K5Q/MRYjbZnI9+rrKbyL3P s1zireprMX6DMWt+T+A5/JrfMMEKyfhAt3BSsV7QQAeJLQOs4FaICLqaHJFEo85Lam+0 zvoG3Q/pQe9t5pxRgLInFpXhtWtOLaajkUUfuKTkZBSb/MD/Ar3thXEisiSGt46z75hF vNzg== X-Gm-Message-State: AMke39nNan2MZ8zuJsAlVBtGaX8rP5n62QfmIjpOFtH6RoC4blRXVPDvlP4JMut2CMJ/26gGwQkO9vXd3MNxPCqCtRP7iik/F2ycqp/CEYdGkEnED5IlelqedV6YDRPp13I27h5Vqy1A+Z5yGTcq8SAvePJOpxck8g== X-Received: by 10.28.16.211 with SMTP id 202mr26506668wmq.133.1486682351986; Thu, 09 Feb 2017 15:19:11 -0800 (PST) X-Received: by 10.28.16.211 with SMTP id 202mr26506654wmq.133.1486682351444; Thu, 09 Feb 2017 15:19:11 -0800 (PST) MIME-Version: 1.0 Sender: Received: by 10.28.87.132 with HTTP; Thu, 9 Feb 2017 15:19:10 -0800 (PST) In-Reply-To: References: From: Steffen Smolka Date: Thu, 9 Feb 2017 18:19:10 -0500 X-Google-Sender-Auth: u0pyWofe67DQtmAs9qWNKAgnBhA Message-ID: To: Jeremy Yallop CC: Caml List Content-Type: multipart/alternative; boundary="001a11452ad873bf150548213585" X-ORG-HybridRouting: 35742ba36f6a5b9edb7a20c45e3c6bcc X-ORG-RouteOnPrem: False X-ORG-MsgSource: cmail X-PMX-CORNELL-AUTH-RESULTS: dkim-out=none; Subject: Re: [Caml-list] namespace inside object? --001a11452ad873bf150548213585 Content-Type: text/plain; charset="UTF-8" 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. 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 > --001a11452ad873bf150548213585 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
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 hav= e in mind. (This is actually the first time I'm touching the dark objec= t oriented side of OCaml :) )=C2=A0

To give some m= ore context, I am refactoring some code that uses modules and no objects. T= he reason I want to move to objects is that I want to derive a slightly enh= anced module from some base implementation. Inheritance + dynamic dispatch = allow me to do so with very little trouble: I can simply overwrite a few me= thods from the base implementation.

I suppose I co= uld achieve the same by turning the base module into a functor, and abstrac= ting 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.

Or you could select the encoding using a=C2=A0variant type:
Good idea, and I'm happy with the syntax for the caller. B= ut 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
=C2=A0

On Thu, Feb 9, 2017 at 5:55 PM= , Jeremy Yallop <yallop@gmail.com> wrote:
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)
>=C2=A0 =C2=A0...
>=C2=A0 =C2=A0method get =3D ...
>
>=C2=A0 =C2=A0module Latin1 =3D struct
>=C2=A0 =C2=A0 =C2=A0method get =3D ...
>=C2=A0 =C2=A0end
>
>=C2=A0 =C2=A0module Utf8 =3D struct
>=C2=A0 =C2=A0 =C2=A0method get =3D ...
>=C2=A0 =C2=A0end
> 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.=C2=A0 If your nested objects don't need to access the internal=
state of the parent then you might write it like this:

=C2=A0 class buffer =3D
=C2=A0 =C2=A0 let latin1 =3D object
=C2=A0 =C2=A0 =C2=A0 method get =3D ...
=C2=A0 =C2=A0end
=C2=A0 =C2=A0and utf8 =3D object
=C2=A0 =C2=A0 =C2=A0 method get =3D ...
=C2=A0 =C2=A0end in
=C2=A0 =C2=A0object(self)
=C2=A0 =C2=A0 =C2=A0...
=C2=A0 =C2=A0 =C2=A0method get =3D ...
=C2=A0 =C2=A0 =C2=A0method latin1 =3D latin1
=C2=A0 =C2=A0 =C2=A0method utf8 =3D utf8
=C2=A0 =C2=A0end

With this approach you can write

=C2=A0 =C2=A0b#get
=C2=A0 =C2=A0b#latin1#get
=C2=A0 =C2=A0b#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.=C2=A0 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 rea= l support
for the kind of nesting that you're interested in.=C2=A0 Instead, peopl= e
typically build nested namespaces using modules:

=C2=A0 module Buffer =3D
=C2=A0 struct
=C2=A0 =C2=A0 =C2=A0let get =3D ...

=C2=A0 =C2=A0 =C2=A0module Latin1 =3D struct
=C2=A0 =C2=A0 =C2=A0 =C2=A0 let get =3D ...
=C2=A0 =C2=A0 =C2=A0end

=C2=A0 =C2=A0 =C2=A0module Utf8 =3D struct
=C2=A0 =C2=A0 =C2=A0 =C2=A0 let get =3D ...
=C2=A0 =C2=A0 =C2=A0end
=C2=A0 end

With the module approach you write the 'receiver' after the 'me= thod'
rather than before, but that doesn't seem like a huge hardship.=C2=A0 (= 10%
of the world manages to get by with VSO languages.)

=C2=A0 Buffer.get b ...
=C2=A0 Buffer.Latin1.get b ...
=C2=A0 Buffer.Utf8.get b ...

If you're keen to stick with objects there are slightly more idiomatic<= br> ways to make it work.=C2=A0 You could, of course, replace the '.' w= ith a
'_' and define methods 'latin1_get', 'utf8_get' in = place of
'Latin1.get', 'Utf8.get'.=C2=A0 Or you could select the enc= oding using a
variant type:

=C2=A0 type enc =3D Latin1 | Utf8

=C2=A0 class buffer =3D
=C2=A0 object (self)
=C2=A0 =C2=A0 =C2=A0method get =3D function
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0| Latin1 -> ...
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0| Utf8 -> ...
=C2=A0 end

Of course, the order of the words in an invocation changes again, but
there's no real increase in complexity for the caller:

=C2=A0 b#get Latin1
=C2=A0 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' vari= es
according to the encoding.

Kind regards,

Jeremy

--001a11452ad873bf150548213585--