caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Trevor Smith <trevorsummerssmith@gmail.com>
To: "Török Edwin" <edwin+ml-ocaml@etorok.net>
Cc: caml-list@inria.fr
Subject: Re: [Caml-list] Type Constraints and .mli
Date: Thu, 7 Aug 2014 18:06:33 -0400	[thread overview]
Message-ID: <CAG-KTt9wSje3EbR2Zzzo3CqB8Lfj4iNS1Ki91u0AEC9HZ6ZdBg@mail.gmail.com> (raw)
In-Reply-To: <53E24B96.8080402@etorok.net>

[-- Attachment #1: Type: text/plain, Size: 5334 bytes --]

Edwin,

Thank you for your response.

You are correct that the "val t" in my example should read "type t".

My main goal is one of readability: I want to have large swathes of the
codebase only use the immutable interface. A few, but very few, parts of
the codebase will use the mutable interface. Ideally, I want the developer
reading the .mli files to quickly and easily understand what interfaces do
what. The standard way of adding the type constraints add a lot of syntax
and make it (slightly) harder to read. My entire question is sort of a
nitpick.

I am interested in your use of polymorphic variants to deal with this
issue: that would actually give better compiler errors than what I am
currently implemented. Thank you for the suggestion. I will mull that and
see if I think of any downsides to that approach.

Trevor


On Wed, Aug 6, 2014 at 11:36 AM, Török Edwin <edwin+ml-ocaml@etorok.net>
wrote:

> On 08/06/2014 03:14 PM, Trevor Smith wrote:
> > Hello,
> >
> > I have a question about using .mli files for increased readability. I
> think my question boils down to: "Can one tersely add type constraints to a
> signature defined in a .mli in that same .mli file?"
> >
> > Detailed problem: You want to have a read interface and a write
> interface for the same implementation.
> >
> > We'll use a trivial example with a character and a name.
> >
> > module type CharacterSig = sig
> >   val t
> >   val create : string -> t
> >   val name : t -> string
> > end
> >
> > module type MutableCharacterSig = sig
> >   val t
> >   val create : string -> t
> >   val name : t -> string
> >   val set_name : t -> string -> unit
> > end
> >
> > module CharacterImpl = struct
> >   type t = {name : string ref}
> >   let create name  =
> >     {name = ref name }
> >   let name c = !(c.name <http://c.name/>)
> >   let set_name c name =
> >     c.name <http://c.name/> := name
> > end
> >
> > module Character = (CharacterImpl : CharacterSig with type t =
> CharacterImpl.t)
> > module MutableCharacter = (CharacterImpl : MutableCharacterSig with type
> t = CharacterImpl.t)
> >
> > But what I would like is to specify the read and write signatures in
> .mli files for a more readable codebase.
> >
> > So:
> >
> > character.mli:
> >   val t
>
> shouldn't this be a type?
>
> >   val create : string -> t
> >   val name : t -> string
> >
> > mCharacter.mli:
> >   val t
> >   val create : string -> t
> >   val name : t -> string
> >   val set_name : t -> string -> unit
> >
> > characterImpl.ml (* ... implementation as above ... *)
> >
> > However, it is not clear to me that there is a way to attach the type
> constraint to character.mli and mCharacter.mli, while keeping the terse
> readability of the .mli file. One idea for a solution, would be to
> reference a "this" so that the interface could show that it was being
> implemented by CharacterImpl, and include the type constraint.
>
> Not sure I understood exactly what you want to do, but using 'include
> module type of' and 'type t = CharacterImpl.t' should work:
>
> character.mli
> type t = CharacterImpl.t
> val create : string -> t
> val name : t -> string
>
> character.ml:
> include CharacterImpl
>
> mCharacter.mli:
> include module type of Character
> val set_name : t -> string -> unit
>
> mCharacter.ml:
> include CharacterImpl
>
> characterImpl.ml:
> type t = {name : string ref}
> let create name  =
>   {name = ref name }
> let name c = !(c.name)
> let set_name c name =
>   c.name := name
>
> However in this case Character.t = MCharacter.t = CharacterImpl.t, so you
> won't get the type safety you want
> (A Character.t can still be modified by MCharacter.set_name).
>
> Perhaps it'd be better to use different types, though to_character is not
> the identity function:
>
> character.mli:
> type t
> val create : string -> t
> val name : t -> string
>
> mCharacter.mli:
> include module type of Character
> val set_name : t -> string -> unit
> val to_character : t -> Character.t
>
> character.ml:
> include MCharacter
>
> mCharacter.ml:
> type t = {name : string ref}
> let create name  =
>   {name = ref name }
> let name c = !(c.name)
> let set_name c name =
>   c.name := name
>
> let to_character x = Character.create (name x)
>
> In fact you should probably take a look at String and Bytes type in OCaml
> 4.02 (and the ocaml-bytes compatibility lib for <4.0.2).
>
> I'd prefer something simpler though:
>
> character.ml:
> type u = {name : string ref}
> type 'a t = u
>
> let create name  =
>   {name = ref name }
> let create_ro = create
> let create_rw = create
> let name c = !(c.name)
> let set_name c name =
>   c.name := name
> let readonly x = x
>
> character.mli:
> type 'a t constraint 'a = [< `W | `R]
> val create_ro : string -> [`R] t
> val create_rw : string -> [`R | `W] t
> val name : 'a t -> string
> val set_name : [> `W] t -> string -> unit
> val readonly : [> `R] t -> [`R] t
>
> Best regards,
> --Edwin
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>

[-- Attachment #2: Type: text/html, Size: 7493 bytes --]

  reply	other threads:[~2014-08-07 22:06 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-08-06 12:14 Trevor Smith
2014-08-06 15:36 ` Török Edwin
2014-08-07 22:06   ` Trevor Smith [this message]
2014-08-08  8:19     ` Frédéric Bour
2014-08-06 22:06 ` Nick Lucaroni

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAG-KTt9wSje3EbR2Zzzo3CqB8Lfj4iNS1Ki91u0AEC9HZ6ZdBg@mail.gmail.com \
    --to=trevorsummerssmith@gmail.com \
    --cc=caml-list@inria.fr \
    --cc=edwin+ml-ocaml@etorok.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).