Version française
Home     About     Download     Resources     Contact us    
Browse thread
Strategy to avoid name collision in signatures
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: michael.le_barbier@l...
Subject: Strategy to avoid name collision in signatures
In some piece of code, I use functors combined with include as a kind
of macro facility. In this scheme, it can happen that an identifier is
exported multiple times from various include directives, this ``name
collision'' is an error, and I am looking for ways to avoid it
whithout much annoyance. (OK, this is very vague, details and example
are coming.)


Let's consider ordered types: one needs only a type and a compare
function to define an ordered type, but one may agree that the
signature

  module type OrderedType.PROTO =
  sig
    type t
    val compare: t -> t -> int
  end

is a bit spartiat and wish for handy shortcuts such as ge, le, gt, lt,
eq (ge means ``greater or equal'', and so on). As a tool to provide
these handy shortcuts in signatures, let's define a OrderedType.Make
functor that takes an OrderedType.PROTO and make an OrderedType.S:

  module type OderedType.S =
    type t
    val compare: t -> t -> int
    val ge: t -> t -> bool
    ...
  end

Now, if one writes a module with a ``compare'' function, he can start
with

  include OrderedType.Make(struct ... end)

to get all these handy shortcuts at hand. Now, let's replicate the
strategy, and define

  module type FunnyType.PROTO = sig type t = ... end
  module type FunnyType.S = sig type t = ... end
  module FunnyType.Make = ...


This is a poor design, as one soon realizes, because one cannot write
something like

  include OrderedType.Make(struct ... end)
  include FunnyType.Make(struct ... end)

By doing so, one gets two definition for type `t', which is an error:

  Multiple definition of the type name t.
  Names must be unique in a given structure or signature.


Of course, one can refrain to name every ``thingie'' type with ``t'',
but this might break other requirements, so one will end up having
duplicate content in module OrderedType. First part is the regular
content above described, second part is replicating the regular
content, with type t getting a new name (e.g. second part consists of
modules S_ALT, Make_alt looking like S and Make with type t renamed to
ordered_type_t; the input signature PROTO doed not need to be
replicated). Having code duplicated is not an agile way of doing
things (first kind of annoyance).

Just saying

  module PreOrderedType = OrderedTypeMake(struct ... end)
  let ge = PreOrderedType.ge
  ...

is totally inefficiant, since any change to OrderedType must be
reflected in every place you use it (second kind of annoyance). Sure,
one can generate appropriate lines automatically, but this is a far
from ideal solution ... let's forget this one!


It is also possible to rely on literate programming tool (such as
NOWEB) to introduce a kind of macro capability and bypass the need of
OrderedType.Make and FunnyType.Make. This is not an ideal solution as
well (third kind of annoyance, cousin of second kind).


I am looking for a way to handle this, that do not deviate too much
from the non-working

  include OrderedType.Make(struct ... end)
  include FunnyType.Make(struct ... end)

(solutions relying on camlp4/5 are an option, yet I cannot use this
tool for now, because of my ignorance.)

BTW, what's the purpose of ``include''? I did not remark any
mention of it in Chailloux et al., and I wonder if the way I try to
use it is weird or regular.

Thanks a lot for having read this long article and for any light you
could bring me up.
-- 
Cheers,
Michaël LB