On Wed, Jul 24, 2013 at 1:24 PM, David Jeske <[email protected]> wrote:
> What I'm suggesting is that once this distinction exists, we acknowledge >> its existence in the type system and define our collision requirements and >> scopes accordingly. We cannot allow non-lexical anti-collision checks to >> manifest at runtime. So if we are going to admit non-lexical anti-collision >> requirements, we have to restrict the scope of those items to some unit >> that is statically compiled and checked. >> > > How can one have an interface in a module without admitting the > possibility of non-lexical collision? Or is this exactly the point you are > making? That we must force compilation units with exported interfaces not > to be capable of asserting implementation selection requirements, so those > selections can be made at a unit which is lexically and statically checked > (and which must not have an interface)? > I think you have it backwards. The problem doesn't arise from having an interface. The problem arises from having an interface in which assumptions have not been documented. Let's start with the assumption that all type class instances (or Trait implementations) are named. One purpose of this is to ensure that every instance has a name that can be referenced at an interface. Now consider a procedure *sort* that accepts a vector and returns a new vector containing the same elements in sorted order. The (unreduced) signature of this procedure is: sort :: Ord 'a, Ord int => 'a[] -> 'a[] *Ord int* gets in here because we are iterating over the array, so we do a comparison on the index type, which is int. We can erase the "Ord int" constraint because int is a primordial type (a minor extension of the "cR or cY" rule), leaving: sort :: Ord 'a => 'a[] -> 'a[] Now suppose we have some type R, and the *exporting* crate has imported an * orphaned* instance of Ord R. And suppose further that we export sortR, a specialization of sort for that type R. In Haskell, we would erase the constraint to get: sortR :: R[] -> R[] what I'm saying is that *because the selected instance is an orphan*, we should instead give this function type as: sortR :: Ord R ~ TheOrphanedOrdRInstance => R[] -> R[] That is: this is a procedure that sorts something of type R[] *provided* the caller agrees with the choice we made about the orphaned instance resolution. We've documented that choice in the interface, and it's up to you whether to use it or not. The caller is free to call the general form of *sort* instead. But if: sort :: Ord 'a => 'a[] -> 'a[] is published at the interface, then we're either going to do run-time code generation or we're going to pass a dictionary pointer at the interface boundary and carry it around internally. > This runs smack into a major common problem in language and runtime > design, which is that we overwhelmingly favor the pattern of > named-impementation-factory when in most cases > conforming-implementation-factory is not only sufficient, but superior. > I haven't heard those two terms before. Would you be kind enough to educate me about them? Jonathan
_______________________________________________ bitc-dev mailing list [email protected] http://www.coyotos.org/mailman/listinfo/bitc-dev
