[m-dev.] shims
Peter Wang
novalazy at gmail.com
Mon Sep 15 15:46:13 AEST 2014
Hi Mark,
On Sun, 14 Sep 2014 12:51:44 +1000, Mark Brown <mark at mercurylang.org> wrote:
> On Thu, Sep 11, 2014 at 5:26 PM, Peter Wang <novalazy at gmail.com> wrote:
> > Hi,
> >
> > When a (standard) library predicate is deprecated, the user faces a
> > choice: update code now and break compatibility with older versions of
> > the library, or face breakage in the future. We try to give a lot of
> > time in which to make that choice. In the meantime the compiler keeps
> > nagging, and it's hard to know when to make the break anyway.
>
> The nagging can be stopped with --no-warn-obsolete. But this isn't
> really about the warnings; I think what you're asking for is the
> ability to target different versions of the same library.
Yes, that's it.
> Here's another approach that I think provides an interesting solution.
> Namely, a top level construct of the following abstract form:
>
> if
> declarations
> then
> items
> else if
> declarations
> then
> items
> ...
> else
> items
> end if
>
> These can be nested. The meaning is that we check if there are visible
> items matching the declarations in the conditions. If so, the clauses
> in the first matching then branch are included in the module,
> otherwise the clauses in the else branch are included. Other
> declarations are local to the branch they appear in. In any case, all
> sections are fully statically checked. The then branch is checked with
> the condition's declarations included, replacing any that were already
> visible, while the else branch is checked without them. Predicates or
> functions declared outside this construct can have clauses defined
> inside it; if so, the clauses must be defined in both branches.
>
> Example (choosing the first concrete syntax that comes to mind):
>
> :- import_module set.
> :- pred portable_singleton_set(T::in, set(T)::out) is det.
> :- if.
> :- pred singleton_set(T::in, set(T)::out) is det.
> :- then.
> portable_singleton_set(X, Set) :- singleton_set(X, Set).
> :- else_if.
> :- pred singleton_set(set(T)::out, T::in) is det.
> :- then
> portable_singleton_set(X, Set) :- singleton_set(Set, X).
> :- else.
> % If neither of those work it will be a compile time error: no
> clauses for
> % portable_singleton_set/2, with the `:- else.' as the
> location of the error.
> :- end_if.
>
> This is much more verbose than Peter's suggestion, but aside from the
> better checking it's also much more flexible because you can target
> different libraries, not just different versions of the same library.
> For example, if there is a module called fastlib that only some
> developers have in their path, you might write:
>
> :- pred algorithm(int::in, int::out) is det,
> :- if.
> :- import_module fastlib. % This can fail.
> :- pred fastlib.algorithm(int::in, int::out) is det.
> :- then.
> algorithm(X, Y) :- fastlib.algorithm(X, Y).
> :- else.
> algorithm(X, Y) :- slow_algorithm(X, Y).
> :- end_if.
>
> Note that, even though fastlib is imported, we still have to declare
> the predicates from it that are used. This enables the then branch to
> be checked even if the import fails, and also allows a check that
> fastlib itself is the right version.
I like it.
Is it fair to think of each if-then branch declaring something like an
anonymous nested sub-module, with forwarding of predicates and types
from the parent module to the sub-module?
Peter
More information about the developers
mailing list