Backward-compatible role annotations

Richard Eisenberg eir at cis.upenn.edu
Wed Apr 2 14:17:40 UTC 2014


Ah -- I see. Interesting suggestion. As we're not thinking much now about the change to a nominal default (definitely too late for 7.8), I've recorded this idea on the roles wiki page (https://ghc.haskell.org/trac/ghc/wiki/Roles) for easy recovery in the future. I think the idea has merit, but there's no concrete action to take on it, at the moment.

Thanks,
Richard

On Mar 31, 2014, at 2:12 PM, Dominique Devriese <dominique.devriese at cs.kuleuven.be> wrote:

> Richard,
> 
> 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.
> 
> Regards,
> Dominique
> 
> 2014-03-31 17:05 GMT+02:00 Richard Eisenberg <eir at cis.upenn.edu>:
>> 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 cs.kuleuven.be> 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 cis.upenn.edu>:
>>>> I spent some time thinking about what, precisely, can be done here to make
>>>> folks happier. (See the thread beginning here:
>>>> http://www.haskell.org/pipermail/libraries/2014-March/022321.html) 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 github.com/goldfirere/no-role-annots.
>>>> 
>>>> Thanks,
>>>> Richard
>>>> 
>>>> _______________________________________________
>>>> ghc-devs mailing list
>>>> ghc-devs at haskell.org
>>>> http://www.haskell.org/mailman/listinfo/ghc-devs
>>>> 
>>> _______________________________________________
>>> Libraries mailing list
>>> Libraries at haskell.org
>>> http://www.haskell.org/mailman/listinfo/libraries
>> 
> 



More information about the Libraries mailing list