Backward-compatible role annotations

Richard Eisenberg eir at
Mon Mar 31 15:05:23 UTC 2014

Hi Dominique,

When implementing roles, I was indeed worried about the problem you're addressing: that code that previously worked with GND now won't. However, it turns out that few people have really complained about this. IIRC, in all of Hackage, only 3 packages needed to be changed because of this. If there were a larger impact to the GND breakage, I think your suggestion would be a good one.

The problem I'm adressing in this thread is different: that library authors have been given a new, not-backward-compatible way of preventing abuses of their datatypes, and no proposal I have seen really addresses all of the problems here. I'm hoping my no-role-annots package might be helpful, but it doesn't fully resolve the issues.


On Mar 31, 2014, at 2:51 AM, Dominique Devriese <dominique.devriese at> wrote:

> Richard,
> (re-posting because I first used an address that is not subscribed to the lists)
> I've been wondering about the following: it seems like the main
> problem in this situation is that the GeneralizedNewtypeDeriving
> extension changed meaning from "just coerce everything while deriving"
> to "only coerce stuff if it's allowed by the relevant role
> annotations".  Would it not be an alternative solution to split up the
> GND extension into
> * a backwards-compatible one (called GeneralizedNewtypeDeriving for
> backwards compatibility ;)) that ignores role annotations (as before)
> and uses unsafeCoerce whereever necessary
> * a safe one (called e.g. SafeNewtypeDeriving) that respects role annotations
> The first one could then be deprecated and removed in a release or
> two. That might give library maintainers time to move their packages
> to SafeNewtypeDeriving when they have tested that everything works...
> Regards,
> Dominique
> P.S.: The above is based on a limited understanding of the problem, so
> I'm sorry if it misses some aspect of the problem...
> 2014-03-31 2:14 GMT+02:00 Richard Eisenberg <eir at>:
>> I spent some time thinking about what, precisely, can be done here to make
>> folks happier. (See the thread beginning here:
>> And, the
>> answer seemed to all be in the concrete syntax. The only logical alternative
>> (that I could think of) to having roles is to disallow GND, and I don't
>> think anyone is proposing that. And, it is impossible to infer an author's
>> desired roles for a datatype. The heuristics mentioned here all seem far too
>> fragile and hard to predict to become a lasting feature of GHC (in my
>> opinion). What's left? Concrete syntax.
>> So, I have written and uploaded no-role-annots-1.0, a backward-compatible
>> alternative to role annotations -- no CPP required. It's not as principled
>> as proper role annotations, but it should do the job for most users.
>> Here are two examples:
>> 1. Datatypes:
>>> import Language.Haskell.RoleAnnots
>>> data Map k v =
>>>  (Nominal k, Representational v) => MkMap [(k,v)]
>> The constraints (which need be put on only one data constructor, if there
>> are many) will get the built-in role inference mechanism to do what the user
>> requests. In this example, the `Representational v` is actually redundant,
>> but causes no harm. Because these classes have universal instances
>> ("instance Nominal a") and have no methods, they should have no run-time
>> significance. The only downside I can see is that the code above needs
>> -XGADTs or -XExistentialQuantification to work, though it is neither a GADT
>> nor has existentials. (Pattern-matching on such a definition needs no
>> extensions.)
>> 2. Newtypes:
>> Newtype constructors cannot be constrained, unfortunately. So, we have to
>> resort to Template Haskell:
>>> import Language.Haskell.RoleAnnots
>>> roleAnnot [NominalR, RepresentationalR]
>>>  [d| newtype Map k v = MkMap [(k, v)] |]
>> This is clearly worse, but I was able to come up with no other solution that
>> worked for newtypes. Note that, in the example, I used the fact that
>> Template Haskell interprets a bare top-level expression as a Template
>> Haskell splice. We could also wrap that line in $( ... ) to be more explicit
>> about the use of TH. Also problematic here is that the code above requires
>> -XRoleAnnotations in GHC 7.8. To get this extension enabled without using
>> CPP, put it in a condition chunk in your .cabal file, like this:
>>> if impl(ghc >= 7.8)
>>>  default-extensions: RoleAnnotations
>> I hope this is helpful to everyone. Please feel free to post issues/pull
>> requests to my github repo at
>> Thanks,
>> Richard
>> _______________________________________________
>> ghc-devs mailing list
>> ghc-devs at
> _______________________________________________
> Libraries mailing list
> Libraries at

More information about the Libraries mailing list