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
