On Wed, Aug 19, 2015 at 9:52 AM, Hendrik Boom <hendrik@topoi.pooq.com> wrote:

The way to make this explicit is to write

  let init flags =
    (M.init (M.flag1 + M.flag2 + flags) (* flags is 'local', and is not shadowed by a value in M *)

THe code is one characte longer, and even the comment becomes smaller!


The '+' operator is also from M, not just normal addition. And, instead of M, it
might be "Sdl.Init". :)

Local open has been fantastic for code hygene and clarity -- previously it was
very common to define local module aliases (even though they weren't actual
aliases at the time!): module S = Sdl.Init... and then prefixing everything
with S, similar to your example. But this is ugly, still redundant, plus it adds
cognitive indirection (alias).

Often when I use a local open it's in an expression which uses mostly values
from the opened module, with a few from local scope, very much like the
example I gave. If it's not heavily from the external module, of course I only
prefix the relevant identifiers rather than opening scope.

I've always hated the following function-call sloppiness in several languages:

  Namespace::func( Namespace::arg1, Namespace::Enum::arg2, myArg );

I felt like the arguments should be implicitly open to the namespace of the called
function.

Then local-open in OCaml, particularly with the short syntax M.(), provided an
elegant solution -- without need for anything implicit! I facepalmed that day.

  Module.(func arg1 Enum.arg2) myarg

Fantabulous!

Now the minor quibble to this otherwise luxurious syntax is that there is no way
to make it clear when something really is local rather than coming from an opened
scope -- and this arises when currying doesn't pan out as nice as the above, or
more often: once binary operators are involved.

But as I said, there has been the related (at least conceptually) thorn of the
inability to specify the path of the current module. I'm hoping someone familiar
with OCaml internals and style has a bright idea.