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

Reply via email to