Backward-compatible role annotations

Dominique Devriese dominique.devriese at
Mon Mar 31 18:12:59 UTC 2014


Right, but I was thinking about the debate between
"nominal/non-parametric-by-default" or
"representational/parametric-by-default" for parameters of data types
that aren't forced to nominal from inspecting the datatype
implementation.  As I understand it, representational-by-default
(currently used) may leave libraries that don't add role annotations
open for abuse, but won't unnecessarily break library users' code and
nominal-by-default prevents all abuse but may unnecessarily break code
that uses libraries that have not added proper role annotations.

What I was wondering about is if the dilemma could be solved by
choosing nominal-by-default in the long term for the role inference
(so that library writers cannot accidentally leave abstraction holes
open by forgetting to add role annotations) and use them in the
long-term-supported SafeNewtypeDeriving extension, but provide a
deprecated not-quite-as-safe GND extension for helping out users of
libraries that have not yet added role annotations. I would fancy that
this not-quite-as-safe GND could use unsafeCoerce wherever the safe
one would give an error about annotated roles.


2014-03-31 17:05 GMT+02:00 Richard Eisenberg <eir at>:
> 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.
> Richard
> 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