On 19 July 2013 02:54, Jonathan S. Shapiro <[email protected]> wrote:
> 2nd order generics raise more issues, but they aren't required to have the
> problem we are discussing. You can break instance coherence just fine
> without generics at all, and you can certainly break them when generics get
> into play. The first (multiple implementations of a trait at the same type)
> is generally referred to as the "coherence problem". The second (a generic
> implementation overridden by a specific implementation) is referred to in
> the Haskell world as "overlapping instances".
>
> For a language to work at scale, I feel that both problems need a reasonable
> resolution. Rust may in fact have one, but I'm unable to tell from the
> manual and the wiki entries that I've seen so far.

I think I've often gotten lost in this discussion before, and I'm
fairly confident I'm not the only one, so I wanted to go over some of
these basics again so I don't get lost.

Someone will probably retort that most "languages [that work] at
scale" don't really have the functionality you're talking about.  To
phrase it in popular pseudo-OO terminology:

Module x declares an interface X, and module y declares a class Y.
What restrictions are there on also declaring that Y implements X (or,
the implementation of Y for X)?  In languages like Java or C#, these
must be defined with the class.  From most peoples perspective, these
languages are for writing software at significant scale.  Now, Haskell
is slightly more flexible in this regard, the implementation of Y for
X may be declared with the interface, which is often a useful thing to
do because it means you don't need to wrap built-in types, or use
'services', to make existing types implement the interface.  C# also
has extension methods, although they (well, also) use the static type
resolution rather than virtual.  In C# or Java, the common way to make
an existing type implement an existing interface is via object
composition, which seems very similar cognitively to type aliases.

So, it is important to note that we're not attempting to solve the
expression problem here (am I wrong?).  What we actually want to do is
be able to describe new implementations of existing traits, and then
to be able to call library code that expects some object that
implements that trait.  We don't need to worry about situations in the
library where X is cast to a Y, because the library could never have
been correctly typed if it did so, rather, we need to be able to have
some new instance selected when we perform the cast (say, perhaps
because we're calling a library function, parametrised over a trait
instance).

It would be nice if we could specify the implementation explicitly,
and it would be nice if could be inferred in the common case.  I think
this is all we are talking about.  It is useful to be able to
parametrise modules over the instance selected for certain types too,
but that's a pretty advanced use case which can probably await the
introduction of dependant types.

We can also conflate the idea that that the implementation of the
functions are inline-able into library code, but that's a separate
concern.  Too, how we might partially-evaluate generics against a
certain set of types and compile them; but if we want to do that we
must select an instance anyway, even if the selection is made by our
lexical contour.

--
William Leslie

Notice:
Likely much of this email is, by the nature of copyright, covered
under copyright law.  You absolutely may reproduce any part of it in
accordance with the copyright law of the nation you are reading this
in.  Any attempt to deny you those rights would be illegal without
prior contractual agreement.
_______________________________________________
bitc-dev mailing list
[email protected]
http://www.coyotos.org/mailman/listinfo/bitc-dev

Reply via email to