(TL;DR: I commonly want to specify paths -uniquely- for identifiers in local
scopes (function, module) which have no means to do this.)

As I run into this yet again, moments ago...

I do often want the ability to be clear that something is not to be shadowed
by the opened scope... to specify it's from the local (usually function) scope.
Part of the reason is for code clarity, but also to safeguard against possible
later changes in the *opened* module (introducing the same identifier).

  let init flags =
    M.(init (flag1 + flag2 + flags)) (* flags is intended to be 'local', but it could be shadowed by a value in M *)

Where M provides 'init', 'flag1', 'flag2', and '+', but 'flags' is in the
local (function) context. When I do this I try to think of a way to make it
self evident that 'flags' is not from M, but there is no way. Aside from
bringing it outside the local-open, but then it's more difficult to build
an expression.

Vimscript might be one of the worst languages to use as a reference, but this
issue does bring to mind the scope prefixes...

  let init flags =
    M.(init (flag1 + flag2 + l:flags)) (* illustrative -- not a proposal! *)

I sometimes consider using naming conventions, but I don't want to explicitly
make function arguments something like l_flags, l_point, etc. That would be a
horrible widespread style, and doesn't work nicely with named arguments.
Plus, changing names to do this seems wrong -- it's at the access site where
you want to disambiguate, which always leads me to think some sigil or prefix.

There was an earlier sidetrack which went with ^ as an "unopen" prefix. At first,
my interest was piqued. Naturally, the issue of recursive unopen came up...

In response, Gabriel wisely remarked:

 "It is remarkable that programming languages have avoided introducing
  explicit weakening (the popping of a symbol out of scope) for now, and
  I think it is a property that should be preserved. We're not yet ready
  to go there."

Good advice when the thread was spinning out of control and probably not going
to settle on anything realistic or favorable. Even though there might be merit
in pursuing fine-grained scope-popping as its own topic.

I think there is a simpler gain to be had from the idea of being able to specify
the path of the current context. "Current context" would need to be
something sensible, and I'm not sure yet what would be best, as there is a
related issue I encounter commonly:

A way to specify the path of the current module.

There is no way to do this, right? If I'm in "a.ml", I can't refer to
A.identifier, and there is no other way to uniquely specify the path to what
*will become* A.identifier? As the bare "identifier" can be shadowed by any
modules opened afterward. Unlike the general "scope-popping", there is also
a common language feature like this: self or this.

I usually want to be explicit with module paths, especially if I am using an
"identifier" which could reasonably be expected to exist now or later in the
other modules being used. I do keep opens to a minimum, but often an entire
expression will be in a local open (to bring in operators), and there,
again... I would like that clarity, and safeguard against changes which might
happen in the other modules, leading to suprises or need to change *this*
module for no good reason other than a naming conflict which ideally can be
prepared against.

Has there been any discussion about referring to the local module? My guess is
that it might be a mild enough problem to not warrant any proposed solutions.
But if there are ideas, maybe the same thing or something similar can also
apply to this problem of "escaping" a local open? They are very similar, but
one is module-scope, while I think the other would be function-scope (though
module-scope might imply the "right thing" anyway)... I'm not certain, as
haven't been keeping track of the cases I encounter, and others might have
different use-cases.


On Tue, Aug 18, 2015 at 7:00 AM, Gabriel Scherer <gabriel.scherer@gmail.com> wrote:
Note that the dual feature does not exist for variant constructors, because it is easy to define only on the constructor at the toplevel of the pattern, and nested patterns get us in muddy waters.

On Tue, Aug 18, 2015 at 2:52 PM, David Allsopp <dra-news@metastack.com> wrote:
Goswin von Brederlow wrote:
> On Fri, Aug 14, 2015 at 01:28:50PM +0200, Drup wrote:
> >
> > >You can't qualifylocal values or values of the surrounding module so
> > >that is a no go.
> > >
> > >I also often use local open to access records, as in:
> > >
> > >let r = M.({ x = 1; y; z = depth; }) in
> >
> > You can avoid the local open altogether and write it like that:
> >
> >     let r = {M. x = 1; y; z = depth } in
> >
> > It's even shorter.
>
> That only works because newer ocaml disambiguises (is that a word?) record
> So it's implicitly using M.y = y and M.z = depth.
> labels when it determines the record type from the first label, right?

Only since you ask: "disambiguates" :o) That said, it's quite common to see words like "disambiguises" being invented by Americans!

But this isn't related to the disambiguation features of OCaml 4.01+. Those allow you to write things like:

type t = {x : int}
type u = {x : int; y : string}

let foo = {x = 1}
let bar = {x = 42; y = ""}

This is actually a much older notation added in OCaml 3.08. Prior to that, if you hadn't opened a module you had to qualify each label:

{M.x = 1; M.y = y; M.z = depth}

but this was "silly", since it's not possible to use non-equivalent module paths for labels, so OCaml 3.08 changed it so that you only needed to put the module path on one label (and it doesn't have to be the first one, it's just a bit weird to put it in the middle!).

OCaml 3.12 added, amongst other record-related goodies, the shorthand {y} to mean {y = y}. So while you can use local open as you're using it, you've been able to do it as a totally unambiguous language feature for quite some time.


David


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