We need to add role annotations for 7.8

Hi libraries, Johan, Edward, tl;dr: We really should add role annotations to the libraries that ship with GHC 7.8. In November, I sent this out: http://www.haskell.org/pipermail/libraries/2013-November/021707.html It got several good responses. Some time later, Joachim and I noticed that no action was taken, so we made a bug report, #8718, with a milestone of 7.8.1. I believe we both assumed that would take care of it. However, Simon PJ and I were surprised earlier this week to discover that Map and Set still do not have role annotations. Perhaps the GHC Trac isn't the right place for libraries issues, but posting here didn't quite work, so that seemed like the logical next step. In any case, now that we have the ability to prevent abuses of datatypes like Map and Set through erroneous use of GeneralizedNewtypeDeriving (and the new `coerce`), we should take advantage of this fact for 7.8. See my earlier email for a full explanation. Possibly folks' unfamiliarity with roles are in part to blame for not adding these role annotations. I am happy to help sort out what goes where. But, I need to work with someone with an intimate familiarity with the libraries themselves to help determine what the correct annotations are. For example, Map's first parameter should be nominal (its Ord instance is very relevant) but its second should be representational (there are no particular invariants related to the values of a map). Map is straightforward in this respect; other types probably aren't. Furthermore, I don't have anywhere near a complete list of what even needs attention. (It should be any type abstractly exported from a library.) Can someone help? I've included Johan as the most recent uploader of `containers` and Edward as the head of the core libraries committee. Thanks! Richard

If you send a pull request for containers I'll merge it and make a release.
It needs to be backwards compatible with the last 3 major GHC releases. I
think we need to bump the minor version number so people can reliable write
dependency bounds to depend on the role being there (as that might be the
difference between code compiling or not).
Here's a guess which params should be representational:
Map k v -- k: nominal, v: represententional
Set a -- k: nominal
IntMap v -- v: represententional
Sequence a -- a: represententional
Tree a -- a: represententional
On Thu, Mar 13, 2014 at 7:41 PM, Richard Eisenberg
Hi libraries, Johan, Edward,
tl;dr: We really should add role annotations to the libraries that ship with GHC 7.8.
In November, I sent this out: http://www.haskell.org/pipermail/libraries/2013-November/021707.html It got several good responses. Some time later, Joachim and I noticed that no action was taken, so we made a bug report, #8718, with a milestone of 7.8.1. I believe we both assumed that would take care of it. However, Simon PJ and I were surprised earlier this week to discover that Map and Set still do not have role annotations. Perhaps the GHC Trac isn't the right place for libraries issues, but posting here didn't quite work, so that seemed like the logical next step.
In any case, now that we have the ability to prevent abuses of datatypes like Map and Set through erroneous use of GeneralizedNewtypeDeriving (and the new `coerce`), we should take advantage of this fact for 7.8. See my earlier email for a full explanation.
Possibly folks' unfamiliarity with roles are in part to blame for not adding these role annotations. I am happy to help sort out what goes where. But, I need to work with someone with an intimate familiarity with the libraries themselves to help determine what the correct annotations are. For example, Map's first parameter should be nominal (its Ord instance is very relevant) but its second should be representational (there are no particular invariants related to the values of a map). Map is straightforward in this respect; other types probably aren't. Furthermore, I don't have anywhere near a complete list of what even needs attention. (It should be any type abstractly exported from a library.)
Can someone help? I've included Johan as the most recent uploader of `containers` and Edward as the head of the core libraries committee.
Thanks! Richard

That looks correct to me. Analogously for HashMap in unordered-containers
of course.
On Thu, Mar 13, 2014 at 2:49 PM, Johan Tibell
If you send a pull request for containers I'll merge it and make a release. It needs to be backwards compatible with the last 3 major GHC releases. I think we need to bump the minor version number so people can reliable write dependency bounds to depend on the role being there (as that might be the difference between code compiling or not).
Here's a guess which params should be representational:
Map k v -- k: nominal, v: represententional Set a -- k: nominal IntMap v -- v: represententional Sequence a -- a: represententional Tree a -- a: represententional
On Thu, Mar 13, 2014 at 7:41 PM, Richard Eisenberg
wrote: Hi libraries, Johan, Edward,
tl;dr: We really should add role annotations to the libraries that ship with GHC 7.8.
In November, I sent this out: http://www.haskell.org/pipermail/libraries/2013-November/021707.html It got several good responses. Some time later, Joachim and I noticed that no action was taken, so we made a bug report, #8718, with a milestone of 7.8.1. I believe we both assumed that would take care of it. However, Simon PJ and I were surprised earlier this week to discover that Map and Set still do not have role annotations. Perhaps the GHC Trac isn't the right place for libraries issues, but posting here didn't quite work, so that seemed like the logical next step.
In any case, now that we have the ability to prevent abuses of datatypes like Map and Set through erroneous use of GeneralizedNewtypeDeriving (and the new `coerce`), we should take advantage of this fact for 7.8. See my earlier email for a full explanation.
Possibly folks' unfamiliarity with roles are in part to blame for not adding these role annotations. I am happy to help sort out what goes where. But, I need to work with someone with an intimate familiarity with the libraries themselves to help determine what the correct annotations are. For example, Map's first parameter should be nominal (its Ord instance is very relevant) but its second should be representational (there are no particular invariants related to the values of a map). Map is straightforward in this respect; other types probably aren't. Furthermore, I don't have anywhere near a complete list of what even needs attention. (It should be any type abstractly exported from a library.)
Can someone help? I've included Johan as the most recent uploader of `containers` and Edward as the head of the core libraries committee.
Thanks! Richard

We were talking about this just this second in IRC. We also need to
double-check vector as well.
(After that we can also fix
https://ghc.haskell.org/trac/ghc/ticket/8767, which I mentioned on IRC
earlier.)
On Thu, Mar 13, 2014 at 1:50 PM, Edward Kmett
That looks correct to me. Analogously for HashMap in unordered-containers of course.
On Thu, Mar 13, 2014 at 2:49 PM, Johan Tibell
wrote: If you send a pull request for containers I'll merge it and make a release. It needs to be backwards compatible with the last 3 major GHC releases. I think we need to bump the minor version number so people can reliable write dependency bounds to depend on the role being there (as that might be the difference between code compiling or not).
Here's a guess which params should be representational:
Map k v -- k: nominal, v: represententional Set a -- k: nominal IntMap v -- v: represententional Sequence a -- a: represententional Tree a -- a: represententional
On Thu, Mar 13, 2014 at 7:41 PM, Richard Eisenberg
wrote: Hi libraries, Johan, Edward,
tl;dr: We really should add role annotations to the libraries that ship with GHC 7.8.
In November, I sent this out: http://www.haskell.org/pipermail/libraries/2013-November/021707.html It got several good responses. Some time later, Joachim and I noticed that no action was taken, so we made a bug report, #8718, with a milestone of 7.8.1. I believe we both assumed that would take care of it. However, Simon PJ and I were surprised earlier this week to discover that Map and Set still do not have role annotations. Perhaps the GHC Trac isn't the right place for libraries issues, but posting here didn't quite work, so that seemed like the logical next step.
In any case, now that we have the ability to prevent abuses of datatypes like Map and Set through erroneous use of GeneralizedNewtypeDeriving (and the new `coerce`), we should take advantage of this fact for 7.8. See my earlier email for a full explanation.
Possibly folks' unfamiliarity with roles are in part to blame for not adding these role annotations. I am happy to help sort out what goes where. But, I need to work with someone with an intimate familiarity with the libraries themselves to help determine what the correct annotations are. For example, Map's first parameter should be nominal (its Ord instance is very relevant) but its second should be representational (there are no particular invariants related to the values of a map). Map is straightforward in this respect; other types probably aren't. Furthermore, I don't have anywhere near a complete list of what even needs attention. (It should be any type abstractly exported from a library.)
Can someone help? I've included Johan as the most recent uploader of `containers` and Edward as the head of the core libraries committee.
Thanks! Richard
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Regards, Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/

This is not shipped with GHC. Johan, as the maintainer of unordered-containers, would you be able to use my patch to be able to do this on your end?
Thanks,
Richard
On Mar 13, 2014, at 2:50 PM, Edward Kmett
That looks correct to me. Analogously for HashMap in unordered-containers of course.
On Thu, Mar 13, 2014 at 2:49 PM, Johan Tibell
wrote: If you send a pull request for containers I'll merge it and make a release. It needs to be backwards compatible with the last 3 major GHC releases. I think we need to bump the minor version number so people can reliable write dependency bounds to depend on the role being there (as that might be the difference between code compiling or not). Here's a guess which params should be representational:
Map k v -- k: nominal, v: represententional Set a -- k: nominal IntMap v -- v: represententional Sequence a -- a: represententional Tree a -- a: represententional
On Thu, Mar 13, 2014 at 7:41 PM, Richard Eisenberg
wrote: Hi libraries, Johan, Edward, tl;dr: We really should add role annotations to the libraries that ship with GHC 7.8.
In November, I sent this out: http://www.haskell.org/pipermail/libraries/2013-November/021707.html It got several good responses. Some time later, Joachim and I noticed that no action was taken, so we made a bug report, #8718, with a milestone of 7.8.1. I believe we both assumed that would take care of it. However, Simon PJ and I were surprised earlier this week to discover that Map and Set still do not have role annotations. Perhaps the GHC Trac isn't the right place for libraries issues, but posting here didn't quite work, so that seemed like the logical next step.
In any case, now that we have the ability to prevent abuses of datatypes like Map and Set through erroneous use of GeneralizedNewtypeDeriving (and the new `coerce`), we should take advantage of this fact for 7.8. See my earlier email for a full explanation.
Possibly folks' unfamiliarity with roles are in part to blame for not adding these role annotations. I am happy to help sort out what goes where. But, I need to work with someone with an intimate familiarity with the libraries themselves to help determine what the correct annotations are. For example, Map's first parameter should be nominal (its Ord instance is very relevant) but its second should be representational (there are no particular invariants related to the values of a map). Map is straightforward in this respect; other types probably aren't. Furthermore, I don't have anywhere near a complete list of what even needs attention. (It should be any type abstractly exported from a library.)
Can someone help? I've included Johan as the most recent uploader of `containers` and Edward as the head of the core libraries committee.
Thanks! Richard

I get around to it next time I make a release of unordered-containers.
Filed https://github.com/tibbe/unordered-containers/issues/73 so I don't
forget.
On Thu, Mar 13, 2014 at 9:12 PM, Richard Eisenberg
This is not shipped with GHC. Johan, as the maintainer of unordered-containers, would you be able to use my patch to be able to do this on your end?
Thanks, Richard
On Mar 13, 2014, at 2:50 PM, Edward Kmett
wrote: That looks correct to me. Analogously for HashMap in unordered-containers of course.
On Thu, Mar 13, 2014 at 2:49 PM, Johan Tibell
wrote: If you send a pull request for containers I'll merge it and make a release. It needs to be backwards compatible with the last 3 major GHC releases. I think we need to bump the minor version number so people can reliable write dependency bounds to depend on the role being there (as that might be the difference between code compiling or not).
Here's a guess which params should be representational:
Map k v -- k: nominal, v: represententional Set a -- k: nominal IntMap v -- v: represententional Sequence a -- a: represententional Tree a -- a: represententional
On Thu, Mar 13, 2014 at 7:41 PM, Richard Eisenberg
wrote: Hi libraries, Johan, Edward,
tl;dr: We really should add role annotations to the libraries that ship with GHC 7.8.
In November, I sent this out: http://www.haskell.org/pipermail/libraries/2013-November/021707.html It got several good responses. Some time later, Joachim and I noticed that no action was taken, so we made a bug report, #8718, with a milestone of 7.8.1. I believe we both assumed that would take care of it. However, Simon PJ and I were surprised earlier this week to discover that Map and Set still do not have role annotations. Perhaps the GHC Trac isn't the right place for libraries issues, but posting here didn't quite work, so that seemed like the logical next step.
In any case, now that we have the ability to prevent abuses of datatypes like Map and Set through erroneous use of GeneralizedNewtypeDeriving (and the new `coerce`), we should take advantage of this fact for 7.8. See my earlier email for a full explanation.
Possibly folks' unfamiliarity with roles are in part to blame for not adding these role annotations. I am happy to help sort out what goes where. But, I need to work with someone with an intimate familiarity with the libraries themselves to help determine what the correct annotations are. For example, Map's first parameter should be nominal (its Ord instance is very relevant) but its second should be representational (there are no particular invariants related to the values of a map). Map is straightforward in this respect; other types probably aren't. Furthermore, I don't have anywhere near a complete list of what even needs attention. (It should be any type abstractly exported from a library.)
Can someone help? I've included Johan as the most recent uploader of `containers` and Edward as the head of the core libraries committee.
Thanks! Richard

it'd just need some CPP to maintain compat right?
We need it for vector and friends too right?
On Thu, Mar 13, 2014 at 2:49 PM, Johan Tibell
If you send a pull request for containers I'll merge it and make a release. It needs to be backwards compatible with the last 3 major GHC releases. I think we need to bump the minor version number so people can reliable write dependency bounds to depend on the role being there (as that might be the difference between code compiling or not).
Here's a guess which params should be representational:
Map k v -- k: nominal, v: represententional Set a -- k: nominal IntMap v -- v: represententional Sequence a -- a: represententional Tree a -- a: represententional
On Thu, Mar 13, 2014 at 7:41 PM, Richard Eisenberg
wrote: Hi libraries, Johan, Edward,
tl;dr: We really should add role annotations to the libraries that ship with GHC 7.8.
In November, I sent this out: http://www.haskell.org/pipermail/libraries/2013-November/021707.html It got several good responses. Some time later, Joachim and I noticed that no action was taken, so we made a bug report, #8718, with a milestone of 7.8.1. I believe we both assumed that would take care of it. However, Simon PJ and I were surprised earlier this week to discover that Map and Set still do not have role annotations. Perhaps the GHC Trac isn't the right place for libraries issues, but posting here didn't quite work, so that seemed like the logical next step.
In any case, now that we have the ability to prevent abuses of datatypes like Map and Set through erroneous use of GeneralizedNewtypeDeriving (and the new `coerce`), we should take advantage of this fact for 7.8. See my earlier email for a full explanation.
Possibly folks' unfamiliarity with roles are in part to blame for not adding these role annotations. I am happy to help sort out what goes where. But, I need to work with someone with an intimate familiarity with the libraries themselves to help determine what the correct annotations are. For example, Map's first parameter should be nominal (its Ord instance is very relevant) but its second should be representational (there are no particular invariants related to the values of a map). Map is straightforward in this respect; other types probably aren't. Furthermore, I don't have anywhere near a complete list of what even needs attention. (It should be any type abstractly exported from a library.)
Can someone help? I've included Johan as the most recent uploader of `containers` and Edward as the head of the core libraries committee.
Thanks! Richard
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Yep. The role annotation should be CPP guarded. On Thu, Mar 13, 2014 at 2:51 PM, Carter Schonwald < carter.schonwald@gmail.com> wrote:
it'd just need some CPP to maintain compat right? We need it for vector and friends too right?
On Thu, Mar 13, 2014 at 2:49 PM, Johan Tibell
wrote: If you send a pull request for containers I'll merge it and make a release. It needs to be backwards compatible with the last 3 major GHC releases. I think we need to bump the minor version number so people can reliable write dependency bounds to depend on the role being there (as that might be the difference between code compiling or not).
Here's a guess which params should be representational:
Map k v -- k: nominal, v: represententional Set a -- k: nominal IntMap v -- v: represententional Sequence a -- a: represententional Tree a -- a: represententional
On Thu, Mar 13, 2014 at 7:41 PM, Richard Eisenberg
wrote: Hi libraries, Johan, Edward,
tl;dr: We really should add role annotations to the libraries that ship with GHC 7.8.
In November, I sent this out: http://www.haskell.org/pipermail/libraries/2013-November/021707.html It got several good responses. Some time later, Joachim and I noticed that no action was taken, so we made a bug report, #8718, with a milestone of 7.8.1. I believe we both assumed that would take care of it. However, Simon PJ and I were surprised earlier this week to discover that Map and Set still do not have role annotations. Perhaps the GHC Trac isn't the right place for libraries issues, but posting here didn't quite work, so that seemed like the logical next step.
In any case, now that we have the ability to prevent abuses of datatypes like Map and Set through erroneous use of GeneralizedNewtypeDeriving (and the new `coerce`), we should take advantage of this fact for 7.8. See my earlier email for a full explanation.
Possibly folks' unfamiliarity with roles are in part to blame for not adding these role annotations. I am happy to help sort out what goes where. But, I need to work with someone with an intimate familiarity with the libraries themselves to help determine what the correct annotations are. For example, Map's first parameter should be nominal (its Ord instance is very relevant) but its second should be representational (there are no particular invariants related to the values of a map). Map is straightforward in this respect; other types probably aren't. Furthermore, I don't have anywhere near a complete list of what even needs attention. (It should be any type abstractly exported from a library.)
Can someone help? I've included Johan as the most recent uploader of `containers` and Edward as the head of the core libraries committee.
Thanks! Richard
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Note with vector, Data.Vector.Vector is has a representational arg, but all
the other vector types have nominal args.
On Thu, Mar 13, 2014 at 2:52 PM, Edward Kmett
Yep.
The role annotation should be CPP guarded.
On Thu, Mar 13, 2014 at 2:51 PM, Carter Schonwald < carter.schonwald@gmail.com> wrote:
it'd just need some CPP to maintain compat right? We need it for vector and friends too right?
On Thu, Mar 13, 2014 at 2:49 PM, Johan Tibell
wrote: If you send a pull request for containers I'll merge it and make a release. It needs to be backwards compatible with the last 3 major GHC releases. I think we need to bump the minor version number so people can reliable write dependency bounds to depend on the role being there (as that might be the difference between code compiling or not).
Here's a guess which params should be representational:
Map k v -- k: nominal, v: represententional Set a -- k: nominal IntMap v -- v: represententional Sequence a -- a: represententional Tree a -- a: represententional
On Thu, Mar 13, 2014 at 7:41 PM, Richard Eisenberg
wrote: Hi libraries, Johan, Edward,
tl;dr: We really should add role annotations to the libraries that ship with GHC 7.8.
In November, I sent this out: http://www.haskell.org/pipermail/libraries/2013-November/021707.html It got several good responses. Some time later, Joachim and I noticed that no action was taken, so we made a bug report, #8718, with a milestone of 7.8.1. I believe we both assumed that would take care of it. However, Simon PJ and I were surprised earlier this week to discover that Map and Set still do not have role annotations. Perhaps the GHC Trac isn't the right place for libraries issues, but posting here didn't quite work, so that seemed like the logical next step.
In any case, now that we have the ability to prevent abuses of datatypes like Map and Set through erroneous use of GeneralizedNewtypeDeriving (and the new `coerce`), we should take advantage of this fact for 7.8. See my earlier email for a full explanation.
Possibly folks' unfamiliarity with roles are in part to blame for not adding these role annotations. I am happy to help sort out what goes where. But, I need to work with someone with an intimate familiarity with the libraries themselves to help determine what the correct annotations are. For example, Map's first parameter should be nominal (its Ord instance is very relevant) but its second should be representational (there are no particular invariants related to the values of a map). Map is straightforward in this respect; other types probably aren't. Furthermore, I don't have anywhere near a complete list of what even needs attention. (It should be any type abstractly exported from a library.)
Can someone help? I've included Johan as the most recent uploader of `containers` and Edward as the head of the core libraries committee.
Thanks! Richard
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Interestingly I guess the s in `ST s` and `MVector s a` is nominal despite
being used as a deliberate phantom. =)
On Thu, Mar 13, 2014 at 2:53 PM, Edward Kmett
Note with vector, Data.Vector.Vector is has a representational arg, but all the other vector types have nominal args.
On Thu, Mar 13, 2014 at 2:52 PM, Edward Kmett
wrote: Yep.
The role annotation should be CPP guarded.
On Thu, Mar 13, 2014 at 2:51 PM, Carter Schonwald < carter.schonwald@gmail.com> wrote:
it'd just need some CPP to maintain compat right? We need it for vector and friends too right?
On Thu, Mar 13, 2014 at 2:49 PM, Johan Tibell
wrote: If you send a pull request for containers I'll merge it and make a release. It needs to be backwards compatible with the last 3 major GHC releases. I think we need to bump the minor version number so people can reliable write dependency bounds to depend on the role being there (as that might be the difference between code compiling or not).
Here's a guess which params should be representational:
Map k v -- k: nominal, v: represententional Set a -- k: nominal IntMap v -- v: represententional Sequence a -- a: represententional Tree a -- a: represententional
On Thu, Mar 13, 2014 at 7:41 PM, Richard Eisenberg
wrote: Hi libraries, Johan, Edward,
tl;dr: We really should add role annotations to the libraries that ship with GHC 7.8.
In November, I sent this out: http://www.haskell.org/pipermail/libraries/2013-November/021707.html It got several good responses. Some time later, Joachim and I noticed that no action was taken, so we made a bug report, #8718, with a milestone of 7.8.1. I believe we both assumed that would take care of it. However, Simon PJ and I were surprised earlier this week to discover that Map and Set still do not have role annotations. Perhaps the GHC Trac isn't the right place for libraries issues, but posting here didn't quite work, so that seemed like the logical next step.
In any case, now that we have the ability to prevent abuses of datatypes like Map and Set through erroneous use of GeneralizedNewtypeDeriving (and the new `coerce`), we should take advantage of this fact for 7.8. See my earlier email for a full explanation.
Possibly folks' unfamiliarity with roles are in part to blame for not adding these role annotations. I am happy to help sort out what goes where. But, I need to work with someone with an intimate familiarity with the libraries themselves to help determine what the correct annotations are. For example, Map's first parameter should be nominal (its Ord instance is very relevant) but its second should be representational (there are no particular invariants related to the values of a map). Map is straightforward in this respect; other types probably aren't. Furthermore, I don't have anywhere near a complete list of what even needs attention. (It should be any type abstractly exported from a library.)
Can someone help? I've included Johan as the most recent uploader of `containers` and Edward as the head of the core libraries committee.
Thanks! Richard
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

This one we get for free. State#'s parameter is nominal (it's declared within GHC and I made that change when I did all the core role stuff), so that role gets inherited throughout.
Richard
On Mar 13, 2014, at 2:54 PM, Edward Kmett
Interestingly I guess the s in `ST s` and `MVector s a` is nominal despite being used as a deliberate phantom. =)
On Thu, Mar 13, 2014 at 2:53 PM, Edward Kmett
wrote: Note with vector, Data.Vector.Vector is has a representational arg, but all the other vector types have nominal args. On Thu, Mar 13, 2014 at 2:52 PM, Edward Kmett
wrote: Yep. The role annotation should be CPP guarded.
On Thu, Mar 13, 2014 at 2:51 PM, Carter Schonwald
wrote: it'd just need some CPP to maintain compat right? We need it for vector and friends too right? On Thu, Mar 13, 2014 at 2:49 PM, Johan Tibell
wrote: If you send a pull request for containers I'll merge it and make a release. It needs to be backwards compatible with the last 3 major GHC releases. I think we need to bump the minor version number so people can reliable write dependency bounds to depend on the role being there (as that might be the difference between code compiling or not). Here's a guess which params should be representational:
Map k v -- k: nominal, v: represententional Set a -- k: nominal IntMap v -- v: represententional Sequence a -- a: represententional Tree a -- a: represententional
On Thu, Mar 13, 2014 at 7:41 PM, Richard Eisenberg
wrote: Hi libraries, Johan, Edward, tl;dr: We really should add role annotations to the libraries that ship with GHC 7.8.
In November, I sent this out: http://www.haskell.org/pipermail/libraries/2013-November/021707.html It got several good responses. Some time later, Joachim and I noticed that no action was taken, so we made a bug report, #8718, with a milestone of 7.8.1. I believe we both assumed that would take care of it. However, Simon PJ and I were surprised earlier this week to discover that Map and Set still do not have role annotations. Perhaps the GHC Trac isn't the right place for libraries issues, but posting here didn't quite work, so that seemed like the logical next step.
In any case, now that we have the ability to prevent abuses of datatypes like Map and Set through erroneous use of GeneralizedNewtypeDeriving (and the new `coerce`), we should take advantage of this fact for 7.8. See my earlier email for a full explanation.
Possibly folks' unfamiliarity with roles are in part to blame for not adding these role annotations. I am happy to help sort out what goes where. But, I need to work with someone with an intimate familiarity with the libraries themselves to help determine what the correct annotations are. For example, Map's first parameter should be nominal (its Ord instance is very relevant) but its second should be representational (there are no particular invariants related to the values of a map). Map is straightforward in this respect; other types probably aren't. Furthermore, I don't have anywhere near a complete list of what even needs attention. (It should be any type abstractly exported from a library.)
Can someone help? I've included Johan as the most recent uploader of `containers` and Edward as the head of the core libraries committee.
Thanks! Richard
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

I don't know my way around `vector` at all -- not even sure where datatypes are declared. If you can tell me what "the other vector types" are, I suppose I can make the patch.
Thanks,
Richard
On Mar 13, 2014, at 2:53 PM, Edward Kmett
Note with vector, Data.Vector.Vector is has a representational arg, but all the other vector types have nominal args.
On Thu, Mar 13, 2014 at 2:52 PM, Edward Kmett
wrote: Yep. The role annotation should be CPP guarded.
On Thu, Mar 13, 2014 at 2:51 PM, Carter Schonwald
wrote: it'd just need some CPP to maintain compat right? We need it for vector and friends too right? On Thu, Mar 13, 2014 at 2:49 PM, Johan Tibell
wrote: If you send a pull request for containers I'll merge it and make a release. It needs to be backwards compatible with the last 3 major GHC releases. I think we need to bump the minor version number so people can reliable write dependency bounds to depend on the role being there (as that might be the difference between code compiling or not). Here's a guess which params should be representational:
Map k v -- k: nominal, v: represententional Set a -- k: nominal IntMap v -- v: represententional Sequence a -- a: represententional Tree a -- a: represententional
On Thu, Mar 13, 2014 at 7:41 PM, Richard Eisenberg
wrote: Hi libraries, Johan, Edward, tl;dr: We really should add role annotations to the libraries that ship with GHC 7.8.
In November, I sent this out: http://www.haskell.org/pipermail/libraries/2013-November/021707.html It got several good responses. Some time later, Joachim and I noticed that no action was taken, so we made a bug report, #8718, with a milestone of 7.8.1. I believe we both assumed that would take care of it. However, Simon PJ and I were surprised earlier this week to discover that Map and Set still do not have role annotations. Perhaps the GHC Trac isn't the right place for libraries issues, but posting here didn't quite work, so that seemed like the logical next step.
In any case, now that we have the ability to prevent abuses of datatypes like Map and Set through erroneous use of GeneralizedNewtypeDeriving (and the new `coerce`), we should take advantage of this fact for 7.8. See my earlier email for a full explanation.
Possibly folks' unfamiliarity with roles are in part to blame for not adding these role annotations. I am happy to help sort out what goes where. But, I need to work with someone with an intimate familiarity with the libraries themselves to help determine what the correct annotations are. For example, Map's first parameter should be nominal (its Ord instance is very relevant) but its second should be representational (there are no particular invariants related to the values of a map). Map is straightforward in this respect; other types probably aren't. Furthermore, I don't have anywhere near a complete list of what even needs attention. (It should be any type abstractly exported from a library.)
Can someone help? I've included Johan as the most recent uploader of `containers` and Edward as the head of the core libraries committee.
Thanks! Richard
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Patch attached. I only needed Map and Set -- the others are inferred. I guess this was simpler than I thought. :)
Richard
On Mar 13, 2014, at 2:49 PM, Johan Tibell
If you send a pull request for containers I'll merge it and make a release. It needs to be backwards compatible with the last 3 major GHC releases. I think we need to bump the minor version number so people can reliable write dependency bounds to depend on the role being there (as that might be the difference between code compiling or not).
Here's a guess which params should be representational:
Map k v -- k: nominal, v: represententional Set a -- k: nominal IntMap v -- v: represententional Sequence a -- a: represententional Tree a -- a: represententional
On Thu, Mar 13, 2014 at 7:41 PM, Richard Eisenberg
wrote: Hi libraries, Johan, Edward, tl;dr: We really should add role annotations to the libraries that ship with GHC 7.8.
In November, I sent this out: http://www.haskell.org/pipermail/libraries/2013-November/021707.html It got several good responses. Some time later, Joachim and I noticed that no action was taken, so we made a bug report, #8718, with a milestone of 7.8.1. I believe we both assumed that would take care of it. However, Simon PJ and I were surprised earlier this week to discover that Map and Set still do not have role annotations. Perhaps the GHC Trac isn't the right place for libraries issues, but posting here didn't quite work, so that seemed like the logical next step.
In any case, now that we have the ability to prevent abuses of datatypes like Map and Set through erroneous use of GeneralizedNewtypeDeriving (and the new `coerce`), we should take advantage of this fact for 7.8. See my earlier email for a full explanation.
Possibly folks' unfamiliarity with roles are in part to blame for not adding these role annotations. I am happy to help sort out what goes where. But, I need to work with someone with an intimate familiarity with the libraries themselves to help determine what the correct annotations are. For example, Map's first parameter should be nominal (its Ord instance is very relevant) but its second should be representational (there are no particular invariants related to the values of a map). Map is straightforward in this respect; other types probably aren't. Furthermore, I don't have anywhere near a complete list of what even needs attention. (It should be any type abstractly exported from a library.)
Can someone help? I've included Johan as the most recent uploader of `containers` and Edward as the head of the core libraries committee.
Thanks! Richard

Applied. Do you need a containers release ASAP so it can ship with 7.8?
On Thu, Mar 13, 2014 at 9:11 PM, Richard Eisenberg
Patch attached. I only needed Map and Set -- the others are inferred. I guess this was simpler than I thought. :)
Richard
On Mar 13, 2014, at 2:49 PM, Johan Tibell
wrote: If you send a pull request for containers I'll merge it and make a release. It needs to be backwards compatible with the last 3 major GHC releases. I think we need to bump the minor version number so people can reliable write dependency bounds to depend on the role being there (as that might be the difference between code compiling or not).
Here's a guess which params should be representational:
Map k v -- k: nominal, v: represententional Set a -- k: nominal IntMap v -- v: represententional Sequence a -- a: represententional Tree a -- a: represententional
On Thu, Mar 13, 2014 at 7:41 PM, Richard Eisenberg
wrote: Hi libraries, Johan, Edward,
tl;dr: We really should add role annotations to the libraries that ship with GHC 7.8.
In November, I sent this out: http://www.haskell.org/pipermail/libraries/2013-November/021707.html It got several good responses. Some time later, Joachim and I noticed that no action was taken, so we made a bug report, #8718, with a milestone of 7.8.1. I believe we both assumed that would take care of it. However, Simon PJ and I were surprised earlier this week to discover that Map and Set still do not have role annotations. Perhaps the GHC Trac isn't the right place for libraries issues, but posting here didn't quite work, so that seemed like the logical next step.
In any case, now that we have the ability to prevent abuses of datatypes like Map and Set through erroneous use of GeneralizedNewtypeDeriving (and the new `coerce`), we should take advantage of this fact for 7.8. See my earlier email for a full explanation.
Possibly folks' unfamiliarity with roles are in part to blame for not adding these role annotations. I am happy to help sort out what goes where. But, I need to work with someone with an intimate familiarity with the libraries themselves to help determine what the correct annotations are. For example, Map's first parameter should be nominal (its Ord instance is very relevant) but its second should be representational (there are no particular invariants related to the values of a map). Map is straightforward in this respect; other types probably aren't. Furthermore, I don't have anywhere near a complete list of what even needs attention. (It should be any type abstractly exported from a library.)
Can someone help? I've included Johan as the most recent uploader of `containers` and Edward as the head of the core libraries committee.
Thanks! Richard

That would be ideal if you don't mind, so we can go ahead and merge it
and get that out of the way (vector etc can come soon after, but we
don't ship that in the GHC distributions, so it's less of a problem).
On Thu, Mar 13, 2014 at 3:22 PM, Johan Tibell
Applied. Do you need a containers release ASAP so it can ship with 7.8?
On Thu, Mar 13, 2014 at 9:11 PM, Richard Eisenberg
wrote: Patch attached. I only needed Map and Set -- the others are inferred. I guess this was simpler than I thought. :)
Richard
On Mar 13, 2014, at 2:49 PM, Johan Tibell
wrote: If you send a pull request for containers I'll merge it and make a release. It needs to be backwards compatible with the last 3 major GHC releases. I think we need to bump the minor version number so people can reliable write dependency bounds to depend on the role being there (as that might be the difference between code compiling or not).
Here's a guess which params should be representational:
Map k v -- k: nominal, v: represententional Set a -- k: nominal IntMap v -- v: represententional Sequence a -- a: represententional Tree a -- a: represententional
On Thu, Mar 13, 2014 at 7:41 PM, Richard Eisenberg
wrote: Hi libraries, Johan, Edward,
tl;dr: We really should add role annotations to the libraries that ship with GHC 7.8.
In November, I sent this out: http://www.haskell.org/pipermail/libraries/2013-November/021707.html It got several good responses. Some time later, Joachim and I noticed that no action was taken, so we made a bug report, #8718, with a milestone of 7.8.1. I believe we both assumed that would take care of it. However, Simon PJ and I were surprised earlier this week to discover that Map and Set still do not have role annotations. Perhaps the GHC Trac isn't the right place for libraries issues, but posting here didn't quite work, so that seemed like the logical next step.
In any case, now that we have the ability to prevent abuses of datatypes like Map and Set through erroneous use of GeneralizedNewtypeDeriving (and the new `coerce`), we should take advantage of this fact for 7.8. See my earlier email for a full explanation.
Possibly folks' unfamiliarity with roles are in part to blame for not adding these role annotations. I am happy to help sort out what goes where. But, I need to work with someone with an intimate familiarity with the libraries themselves to help determine what the correct annotations are. For example, Map's first parameter should be nominal (its Ord instance is very relevant) but its second should be representational (there are no particular invariants related to the values of a map). Map is straightforward in this respect; other types probably aren't. Furthermore, I don't have anywhere near a complete list of what even needs attention. (It should be any type abstractly exported from a library.)
Can someone help? I've included Johan as the most recent uploader of `containers` and Edward as the head of the core libraries committee.
Thanks! Richard
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Regards, Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/

Tagged and released containers-0.5.5.0.
On Thu, Mar 13, 2014 at 9:26 PM, Austin Seipp
That would be ideal if you don't mind, so we can go ahead and merge it and get that out of the way (vector etc can come soon after, but we don't ship that in the GHC distributions, so it's less of a problem).
Applied. Do you need a containers release ASAP so it can ship with 7.8?
On Thu, Mar 13, 2014 at 9:11 PM, Richard Eisenberg
wrote: Patch attached. I only needed Map and Set -- the others are inferred. I guess this was simpler than I thought. :)
Richard
On Mar 13, 2014, at 2:49 PM, Johan Tibell
wrote:
If you send a pull request for containers I'll merge it and make a release. It needs to be backwards compatible with the last 3 major GHC releases. I think we need to bump the minor version number so people can reliable write dependency bounds to depend on the role being there (as
might be the difference between code compiling or not).
Here's a guess which params should be representational:
Map k v -- k: nominal, v: represententional Set a -- k: nominal IntMap v -- v: represententional Sequence a -- a: represententional Tree a -- a: represententional
On Thu, Mar 13, 2014 at 7:41 PM, Richard Eisenberg
wrote: Hi libraries, Johan, Edward,
tl;dr: We really should add role annotations to the libraries that ship with GHC 7.8.
In November, I sent this out: http://www.haskell.org/pipermail/libraries/2013-November/021707.html It got several good responses. Some time later, Joachim and I noticed that no action was taken, so we made a bug report, #8718, with a
milestone
of 7.8.1. I believe we both assumed that would take care of it. However, Simon PJ and I were surprised earlier this week to discover that Map and Set still do not have role annotations. Perhaps the GHC Trac isn't the right place for libraries issues, but posting here didn't quite work, so that seemed like the logical next step.
In any case, now that we have the ability to prevent abuses of datatypes like Map and Set through erroneous use of GeneralizedNewtypeDeriving (and the new `coerce`), we should take advantage of this fact for 7.8. See my earlier email for a full explanation.
Possibly folks' unfamiliarity with roles are in part to blame for not adding these role annotations. I am happy to help sort out what goes where. But, I need to work with someone with an intimate familiarity with the libraries themselves to help determine what the correct annotations are. For example, Map's first parameter should be nominal (its Ord instance is very relevant) but its second should be representational (there are no
invariants related to the values of a map). Map is straightforward in
On Thu, Mar 13, 2014 at 3:22 PM, Johan Tibell
wrote: that particular this respect; other types probably aren't. Furthermore, I don't have anywhere near a complete list of what even needs attention. (It should be any type abstractly exported from a library.)
Can someone help? I've included Johan as the most recent uploader of `containers` and Edward as the head of the core libraries committee.
Thanks! Richard
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Regards,
Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/

Well, I'm satisfied now -- again, that was all much easier than I anticipated. Thanks, all! On Mar 13, 2014, at 4:46 PM, Johan Tibell wrote:
Tagged and released containers-0.5.5.0.
On Thu, Mar 13, 2014 at 9:26 PM, Austin Seipp
wrote: That would be ideal if you don't mind, so we can go ahead and merge it and get that out of the way (vector etc can come soon after, but we don't ship that in the GHC distributions, so it's less of a problem). On Thu, Mar 13, 2014 at 3:22 PM, Johan Tibell
wrote: Applied. Do you need a containers release ASAP so it can ship with 7.8?
On Thu, Mar 13, 2014 at 9:11 PM, Richard Eisenberg
wrote: Patch attached. I only needed Map and Set -- the others are inferred. I guess this was simpler than I thought. :)
Richard
On Mar 13, 2014, at 2:49 PM, Johan Tibell
wrote: If you send a pull request for containers I'll merge it and make a release. It needs to be backwards compatible with the last 3 major GHC releases. I think we need to bump the minor version number so people can reliable write dependency bounds to depend on the role being there (as that might be the difference between code compiling or not).
Here's a guess which params should be representational:
Map k v -- k: nominal, v: represententional Set a -- k: nominal IntMap v -- v: represententional Sequence a -- a: represententional Tree a -- a: represententional
On Thu, Mar 13, 2014 at 7:41 PM, Richard Eisenberg
wrote: Hi libraries, Johan, Edward,
tl;dr: We really should add role annotations to the libraries that ship with GHC 7.8.
In November, I sent this out: http://www.haskell.org/pipermail/libraries/2013-November/021707.html It got several good responses. Some time later, Joachim and I noticed that no action was taken, so we made a bug report, #8718, with a milestone of 7.8.1. I believe we both assumed that would take care of it. However, Simon PJ and I were surprised earlier this week to discover that Map and Set still do not have role annotations. Perhaps the GHC Trac isn't the right place for libraries issues, but posting here didn't quite work, so that seemed like the logical next step.
In any case, now that we have the ability to prevent abuses of datatypes like Map and Set through erroneous use of GeneralizedNewtypeDeriving (and the new `coerce`), we should take advantage of this fact for 7.8. See my earlier email for a full explanation.
Possibly folks' unfamiliarity with roles are in part to blame for not adding these role annotations. I am happy to help sort out what goes where. But, I need to work with someone with an intimate familiarity with the libraries themselves to help determine what the correct annotations are. For example, Map's first parameter should be nominal (its Ord instance is very relevant) but its second should be representational (there are no particular invariants related to the values of a map). Map is straightforward in this respect; other types probably aren't. Furthermore, I don't have anywhere near a complete list of what even needs attention. (It should be any type abstractly exported from a library.)
Can someone help? I've included Johan as the most recent uploader of `containers` and Edward as the head of the core libraries committee.
Thanks! Richard
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Regards,
Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/

Hi there. Please forgive my ignorance w.r.t. roles, but why aren't all of these representational?
Map k v -- k: nominal, v: represententional Set a -- k: nominal
AFAIK both Map and Set are "normal" datatypes. Not GADTs, no type families involved. Why would anything need to be "nominal" then? Thanks in advance for explaining. Cheers, Andres -- Andres Löh, Haskell Consultant Well-Typed LLP, http://www.well-typed.com

[Sorry for the self-reply.] Oh, perhaps I actually understand this:
Please forgive my ignorance w.r.t. roles, but why aren't all of these representational?
Map k v -- k: nominal, v: represententional Set a -- k: nominal
AFAIK both Map and Set are "normal" datatypes. Not GADTs, no type families involved. Why would anything need to be "nominal" then?
Is this because the integrity of these types relies on the Ord instance being sane, and a newtype could have a different Ord instance defined? Cheers, Andres

That's right. If you had another instance of Ord for a newtype with
compare = flip compare, and were allowed to coerce the keys, you can
break it.
On Thu, Mar 13, 2014 at 5:00 PM, Andres Löh
[Sorry for the self-reply.]
Oh, perhaps I actually understand this:
Please forgive my ignorance w.r.t. roles, but why aren't all of these representational?
Map k v -- k: nominal, v: represententional Set a -- k: nominal
AFAIK both Map and Set are "normal" datatypes. Not GADTs, no type families involved. Why would anything need to be "nominal" then?
Is this because the integrity of these types relies on the Ord instance being sane, and a newtype could have a different Ord instance defined?
Cheers, Andres _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Regards, Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/

*cough* I hate to be the bearer of bad news, but something went wrong
it seems in HEAD:
$ git describe
ghc-7.9-start-188-g337bac3
$ grep "^version\:" libraries/containers/containers.cabal
version: 0.5.5.0
$ ./inplace/bin/ghc-stage2 --interactive -XSafe
GHCi, version 7.9.20140313: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> import Data.Coerce
Prelude Data.Coerce> import Data.Map
Prelude Data.Coerce Data.Map> import Data.Set
Prelude Data.Coerce Data.Map Data.Set> newtype Age = MkAge Int deriving Show
Prelude Data.Coerce Data.Map Data.Set> let _ = coerce :: Map Int Int
-> Map Int Age
Prelude Data.Coerce Data.Map Data.Set> let _ = coerce :: Map Int Int
-> Map Age Int
<interactive>:7:9:
Could not coerce from ‘Map Int Int’ to ‘Map Age Int’
because the constructors of ‘Map’ are not imported
as required in SafeHaskell mode
because the first type argument of ‘Map’ has role Nominal,
but the arguments ‘Int’ and ‘Age’ differ
arising from a use of ‘coerce’
In the expression: coerce :: Map Int Int -> Map Age Int
In a pattern binding: _ = coerce :: Map Int Int -> Map Age Int
Prelude Data.Coerce Data.Map Data.Set> let _ = coerce :: Set Int -> Set Age
Prelude Data.Coerce Data.Map Data.Set> :i Set
data Set a
= containers-0.5.5.0:Data.Set.Base.Bin {-# UNPACK #-}
!containers-0.5.5.0:Data.Set.Base.Size
!a
!(Set a)
!(Set a)
| containers-0.5.5.0:Data.Set.Base.Tip
-- Defined in ‘containers-0.5.5.0:Data.Set.Base’
instance Eq a => Eq (Set a)
-- Defined in ‘containers-0.5.5.0:Data.Set.Base’
instance Ord a => Ord (Set a)
-- Defined in ‘containers-0.5.5.0:Data.Set.Base’
instance (Read a, Ord a) => Read (Set a)
-- Defined in ‘containers-0.5.5.0:Data.Set.Base’
instance Show a => Show (Set a)
-- Defined in ‘containers-0.5.5.0:Data.Set.Base’
Prelude Data.Coerce Data.Map Data.Set> :i Map
type role Map nominal representational
data Map k a
= containers-0.5.5.0:Data.Map.Base.Bin {-# UNPACK #-}
!containers-0.5.5.0:Data.Map.Base.Size
!k
a
!(Map k a)
!(Map k a)
| containers-0.5.5.0:Data.Map.Base.Tip
-- Defined in ‘containers-0.5.5.0:Data.Map.Base’
instance (Eq k, Eq a) => Eq (Map k a)
-- Defined in ‘containers-0.5.5.0:Data.Map.Base’
instance Functor (Map k)
-- Defined in ‘containers-0.5.5.0:Data.Map.Base’
instance (Ord k, Ord v) => Ord (Map k v)
-- Defined in ‘containers-0.5.5.0:Data.Map.Base’
instance (Ord k, Read k, Read e) => Read (Map k e)
-- Defined in ‘containers-0.5.5.0:Data.Map.Base’
instance (Show k, Show a) => Show (Map k a)
-- Defined in ‘containers-0.5.5.0:Data.Map.Base’
Prelude Data.Coerce Data.Map Data.Set>
--------------------------------------------------------------
As you can see, Map has the proper nominal representation (:i only
shows it when it's other than strictly representational), but Set, for
some reason, does not.
I'll look into this. We should also certainly add tests to containers
(under tests-ghc/) to make sure this doesn't slip by again.
On Thu, Mar 13, 2014 at 5:03 PM, Austin Seipp
That's right. If you had another instance of Ord for a newtype with compare = flip compare, and were allowed to coerce the keys, you can break it.
On Thu, Mar 13, 2014 at 5:00 PM, Andres Löh
wrote: [Sorry for the self-reply.]
Oh, perhaps I actually understand this:
Please forgive my ignorance w.r.t. roles, but why aren't all of these representational?
Map k v -- k: nominal, v: represententional Set a -- k: nominal
AFAIK both Map and Set are "normal" datatypes. Not GADTs, no type families involved. Why would anything need to be "nominal" then?
Is this because the integrity of these types relies on the Ord instance being sane, and a newtype could have a different Ord instance defined?
Cheers, Andres _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Regards,
Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/
-- Regards, Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/

Here's the bug:
https://github.com/ghc/packages-containers/blob/ghc-head/Data/Set/Base.hs#L2...
Note it should be __GLASGOW_HASKELL__ with two underscores at the end.
That's why the annotation was missed for Set only.
Richard, would you mind fixing this? Or anyone, really. We should also
use the above example I showed as a test case and put it in the
containers repository so GHC can pick it up.
Johan, you'll also have to do another release. :( Sorry.
On Fri, Mar 14, 2014 at 3:54 AM, Austin Seipp
*cough* I hate to be the bearer of bad news, but something went wrong it seems in HEAD:
$ git describe ghc-7.9-start-188-g337bac3 $ grep "^version\:" libraries/containers/containers.cabal version: 0.5.5.0 $ ./inplace/bin/ghc-stage2 --interactive -XSafe GHCi, version 7.9.20140313: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Prelude> import Data.Coerce Prelude Data.Coerce> import Data.Map Prelude Data.Coerce Data.Map> import Data.Set Prelude Data.Coerce Data.Map Data.Set> newtype Age = MkAge Int deriving Show Prelude Data.Coerce Data.Map Data.Set> let _ = coerce :: Map Int Int -> Map Int Age Prelude Data.Coerce Data.Map Data.Set> let _ = coerce :: Map Int Int -> Map Age Int
<interactive>:7:9: Could not coerce from ‘Map Int Int’ to ‘Map Age Int’ because the constructors of ‘Map’ are not imported as required in SafeHaskell mode because the first type argument of ‘Map’ has role Nominal, but the arguments ‘Int’ and ‘Age’ differ arising from a use of ‘coerce’ In the expression: coerce :: Map Int Int -> Map Age Int In a pattern binding: _ = coerce :: Map Int Int -> Map Age Int Prelude Data.Coerce Data.Map Data.Set> let _ = coerce :: Set Int -> Set Age Prelude Data.Coerce Data.Map Data.Set> :i Set data Set a = containers-0.5.5.0:Data.Set.Base.Bin {-# UNPACK #-} !containers-0.5.5.0:Data.Set.Base.Size !a !(Set a) !(Set a) | containers-0.5.5.0:Data.Set.Base.Tip -- Defined in ‘containers-0.5.5.0:Data.Set.Base’ instance Eq a => Eq (Set a) -- Defined in ‘containers-0.5.5.0:Data.Set.Base’ instance Ord a => Ord (Set a) -- Defined in ‘containers-0.5.5.0:Data.Set.Base’ instance (Read a, Ord a) => Read (Set a) -- Defined in ‘containers-0.5.5.0:Data.Set.Base’ instance Show a => Show (Set a) -- Defined in ‘containers-0.5.5.0:Data.Set.Base’ Prelude Data.Coerce Data.Map Data.Set> :i Map type role Map nominal representational data Map k a = containers-0.5.5.0:Data.Map.Base.Bin {-# UNPACK #-} !containers-0.5.5.0:Data.Map.Base.Size !k a !(Map k a) !(Map k a) | containers-0.5.5.0:Data.Map.Base.Tip -- Defined in ‘containers-0.5.5.0:Data.Map.Base’ instance (Eq k, Eq a) => Eq (Map k a) -- Defined in ‘containers-0.5.5.0:Data.Map.Base’ instance Functor (Map k) -- Defined in ‘containers-0.5.5.0:Data.Map.Base’ instance (Ord k, Ord v) => Ord (Map k v) -- Defined in ‘containers-0.5.5.0:Data.Map.Base’ instance (Ord k, Read k, Read e) => Read (Map k e) -- Defined in ‘containers-0.5.5.0:Data.Map.Base’ instance (Show k, Show a) => Show (Map k a) -- Defined in ‘containers-0.5.5.0:Data.Map.Base’ Prelude Data.Coerce Data.Map Data.Set>
--------------------------------------------------------------
As you can see, Map has the proper nominal representation (:i only shows it when it's other than strictly representational), but Set, for some reason, does not.
I'll look into this. We should also certainly add tests to containers (under tests-ghc/) to make sure this doesn't slip by again.
On Thu, Mar 13, 2014 at 5:03 PM, Austin Seipp
wrote: That's right. If you had another instance of Ord for a newtype with compare = flip compare, and were allowed to coerce the keys, you can break it.
On Thu, Mar 13, 2014 at 5:00 PM, Andres Löh
wrote: [Sorry for the self-reply.]
Oh, perhaps I actually understand this:
Please forgive my ignorance w.r.t. roles, but why aren't all of these representational?
Map k v -- k: nominal, v: represententional Set a -- k: nominal
AFAIK both Map and Set are "normal" datatypes. Not GADTs, no type families involved. Why would anything need to be "nominal" then?
Is this because the integrity of these types relies on the Ord instance being sane, and a newtype could have a different Ord instance defined?
Cheers, Andres _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Regards,
Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/
-- Regards,
Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/
-- Regards, Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/

*sigh* I'll also note that, for some reason, the testsuite does not
automatically pick up the containers library's tests-ghc directory as
a path to look for tests. So that needs to be fixed too (hopefully it
hasn't bitrotted). Ugh...
At the very least we *should* have a test, but maybe just stuff it in
GHC's testsuite instead for now.
On Fri, Mar 14, 2014 at 3:58 AM, Austin Seipp
Here's the bug:
https://github.com/ghc/packages-containers/blob/ghc-head/Data/Set/Base.hs#L2...
Note it should be __GLASGOW_HASKELL__ with two underscores at the end. That's why the annotation was missed for Set only.
Richard, would you mind fixing this? Or anyone, really. We should also use the above example I showed as a test case and put it in the containers repository so GHC can pick it up.
Johan, you'll also have to do another release. :( Sorry.
On Fri, Mar 14, 2014 at 3:54 AM, Austin Seipp
wrote: *cough* I hate to be the bearer of bad news, but something went wrong it seems in HEAD:
$ git describe ghc-7.9-start-188-g337bac3 $ grep "^version\:" libraries/containers/containers.cabal version: 0.5.5.0 $ ./inplace/bin/ghc-stage2 --interactive -XSafe GHCi, version 7.9.20140313: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Prelude> import Data.Coerce Prelude Data.Coerce> import Data.Map Prelude Data.Coerce Data.Map> import Data.Set Prelude Data.Coerce Data.Map Data.Set> newtype Age = MkAge Int deriving Show Prelude Data.Coerce Data.Map Data.Set> let _ = coerce :: Map Int Int -> Map Int Age Prelude Data.Coerce Data.Map Data.Set> let _ = coerce :: Map Int Int -> Map Age Int
<interactive>:7:9: Could not coerce from ‘Map Int Int’ to ‘Map Age Int’ because the constructors of ‘Map’ are not imported as required in SafeHaskell mode because the first type argument of ‘Map’ has role Nominal, but the arguments ‘Int’ and ‘Age’ differ arising from a use of ‘coerce’ In the expression: coerce :: Map Int Int -> Map Age Int In a pattern binding: _ = coerce :: Map Int Int -> Map Age Int Prelude Data.Coerce Data.Map Data.Set> let _ = coerce :: Set Int -> Set Age Prelude Data.Coerce Data.Map Data.Set> :i Set data Set a = containers-0.5.5.0:Data.Set.Base.Bin {-# UNPACK #-} !containers-0.5.5.0:Data.Set.Base.Size !a !(Set a) !(Set a) | containers-0.5.5.0:Data.Set.Base.Tip -- Defined in ‘containers-0.5.5.0:Data.Set.Base’ instance Eq a => Eq (Set a) -- Defined in ‘containers-0.5.5.0:Data.Set.Base’ instance Ord a => Ord (Set a) -- Defined in ‘containers-0.5.5.0:Data.Set.Base’ instance (Read a, Ord a) => Read (Set a) -- Defined in ‘containers-0.5.5.0:Data.Set.Base’ instance Show a => Show (Set a) -- Defined in ‘containers-0.5.5.0:Data.Set.Base’ Prelude Data.Coerce Data.Map Data.Set> :i Map type role Map nominal representational data Map k a = containers-0.5.5.0:Data.Map.Base.Bin {-# UNPACK #-} !containers-0.5.5.0:Data.Map.Base.Size !k a !(Map k a) !(Map k a) | containers-0.5.5.0:Data.Map.Base.Tip -- Defined in ‘containers-0.5.5.0:Data.Map.Base’ instance (Eq k, Eq a) => Eq (Map k a) -- Defined in ‘containers-0.5.5.0:Data.Map.Base’ instance Functor (Map k) -- Defined in ‘containers-0.5.5.0:Data.Map.Base’ instance (Ord k, Ord v) => Ord (Map k v) -- Defined in ‘containers-0.5.5.0:Data.Map.Base’ instance (Ord k, Read k, Read e) => Read (Map k e) -- Defined in ‘containers-0.5.5.0:Data.Map.Base’ instance (Show k, Show a) => Show (Map k a) -- Defined in ‘containers-0.5.5.0:Data.Map.Base’ Prelude Data.Coerce Data.Map Data.Set>
--------------------------------------------------------------
As you can see, Map has the proper nominal representation (:i only shows it when it's other than strictly representational), but Set, for some reason, does not.
I'll look into this. We should also certainly add tests to containers (under tests-ghc/) to make sure this doesn't slip by again.
On Thu, Mar 13, 2014 at 5:03 PM, Austin Seipp
wrote: That's right. If you had another instance of Ord for a newtype with compare = flip compare, and were allowed to coerce the keys, you can break it.
On Thu, Mar 13, 2014 at 5:00 PM, Andres Löh
wrote: [Sorry for the self-reply.]
Oh, perhaps I actually understand this:
Please forgive my ignorance w.r.t. roles, but why aren't all of these representational?
Map k v -- k: nominal, v: represententional Set a -- k: nominal
AFAIK both Map and Set are "normal" datatypes. Not GADTs, no type families involved. Why would anything need to be "nominal" then?
Is this because the integrity of these types relies on the Ord instance being sane, and a newtype could have a different Ord instance defined?
Cheers, Andres _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Regards,
Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/
-- Regards,
Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/
-- Regards,
Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/
-- Regards, Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/

I've released and tagged a new containers version that fixes the typo.
I'm quite worried about this change though. I thought the default role for
data type was nominal, as that's the safe default. If the default is
representational, every package author will need to be aware of this
feature and update their packages. That's quite a high cost.
On Fri, Mar 14, 2014 at 10:00 AM, Austin Seipp
*sigh* I'll also note that, for some reason, the testsuite does not automatically pick up the containers library's tests-ghc directory as a path to look for tests. So that needs to be fixed too (hopefully it hasn't bitrotted). Ugh...
At the very least we *should* have a test, but maybe just stuff it in GHC's testsuite instead for now.
On Fri, Mar 14, 2014 at 3:58 AM, Austin Seipp
wrote: Here's the bug:
https://github.com/ghc/packages-containers/blob/ghc-head/Data/Set/Base.hs#L2...
Note it should be __GLASGOW_HASKELL__ with two underscores at the end. That's why the annotation was missed for Set only.
Richard, would you mind fixing this? Or anyone, really. We should also use the above example I showed as a test case and put it in the containers repository so GHC can pick it up.
Johan, you'll also have to do another release. :( Sorry.
On Fri, Mar 14, 2014 at 3:54 AM, Austin Seipp
wrote:
*cough* I hate to be the bearer of bad news, but something went wrong it seems in HEAD:
$ git describe ghc-7.9-start-188-g337bac3 $ grep "^version\:" libraries/containers/containers.cabal version: 0.5.5.0 $ ./inplace/bin/ghc-stage2 --interactive -XSafe GHCi, version 7.9.20140313: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Prelude> import Data.Coerce Prelude Data.Coerce> import Data.Map Prelude Data.Coerce Data.Map> import Data.Set Prelude Data.Coerce Data.Map Data.Set> newtype Age = MkAge Int deriving Show Prelude Data.Coerce Data.Map Data.Set> let _ = coerce :: Map Int Int -> Map Int Age Prelude Data.Coerce Data.Map Data.Set> let _ = coerce :: Map Int Int -> Map Age Int
<interactive>:7:9: Could not coerce from 'Map Int Int' to 'Map Age Int' because the constructors of 'Map' are not imported as required in SafeHaskell mode because the first type argument of 'Map' has role Nominal, but the arguments 'Int' and 'Age' differ arising from a use of 'coerce' In the expression: coerce :: Map Int Int -> Map Age Int In a pattern binding: _ = coerce :: Map Int Int -> Map Age Int Prelude Data.Coerce Data.Map Data.Set> let _ = coerce :: Set Int -> Set Age Prelude Data.Coerce Data.Map Data.Set> :i Set data Set a = containers-0.5.5.0:Data.Set.Base.Bin {-# UNPACK #-} !containers-0.5.5.0:Data.Set.Base.Size !a !(Set a) !(Set a) | containers-0.5.5.0:Data.Set.Base.Tip -- Defined in 'containers-0.5.5.0:Data.Set.Base' instance Eq a => Eq (Set a) -- Defined in 'containers-0.5.5.0:Data.Set.Base' instance Ord a => Ord (Set a) -- Defined in 'containers-0.5.5.0:Data.Set.Base' instance (Read a, Ord a) => Read (Set a) -- Defined in 'containers-0.5.5.0:Data.Set.Base' instance Show a => Show (Set a) -- Defined in 'containers-0.5.5.0:Data.Set.Base' Prelude Data.Coerce Data.Map Data.Set> :i Map type role Map nominal representational data Map k a = containers-0.5.5.0:Data.Map.Base.Bin {-# UNPACK #-} !containers-0.5.5.0:Data.Map.Base.Size !k a !(Map k a) !(Map k a) | containers-0.5.5.0:Data.Map.Base.Tip -- Defined in 'containers-0.5.5.0:Data.Map.Base' instance (Eq k, Eq a) => Eq (Map k a) -- Defined in 'containers-0.5.5.0:Data.Map.Base' instance Functor (Map k) -- Defined in 'containers-0.5.5.0:Data.Map.Base' instance (Ord k, Ord v) => Ord (Map k v) -- Defined in 'containers-0.5.5.0:Data.Map.Base' instance (Ord k, Read k, Read e) => Read (Map k e) -- Defined in 'containers-0.5.5.0:Data.Map.Base' instance (Show k, Show a) => Show (Map k a) -- Defined in 'containers-0.5.5.0:Data.Map.Base' Prelude Data.Coerce Data.Map Data.Set>
--------------------------------------------------------------
As you can see, Map has the proper nominal representation (:i only shows it when it's other than strictly representational), but Set, for some reason, does not.
I'll look into this. We should also certainly add tests to containers (under tests-ghc/) to make sure this doesn't slip by again.
On Thu, Mar 13, 2014 at 5:03 PM, Austin Seipp
wrote: That's right. If you had another instance of Ord for a newtype with compare = flip compare, and were allowed to coerce the keys, you can break it.
On Thu, Mar 13, 2014 at 5:00 PM, Andres Löh
wrote: [Sorry for the self-reply.]
Oh, perhaps I actually understand this:
Please forgive my ignorance w.r.t. roles, but why aren't all of these representational?
> Map k v -- k: nominal, v: represententional > Set a -- k: nominal
AFAIK both Map and Set are "normal" datatypes. Not GADTs, no type families involved. Why would anything need to be "nominal" then?
Is this because the integrity of these types relies on the Ord instance being sane, and a newtype could have a different Ord instance defined?
Cheers, Andres _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Regards,
Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/
-- Regards,
Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/
-- Regards,
Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/
-- Regards,
Austin Seipp, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/ _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Fri, Mar 14, 2014 at 5:36 AM, Johan Tibell
I'm quite worried about this change though. I thought the default role for data type was nominal, as that's the safe default. If the default is representational, every package author will need to be aware of this feature and update their packages. That's quite a high cost.
Nominal default breaks everything that uses newtype deriving and doesn't have role annotations, doesn't it? Representational default means things behave in 7.8 as they did in earlier GHCs. -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

On Fri, Mar 14, 2014 at 2:00 PM, Brandon Allbery
On Fri, Mar 14, 2014 at 5:36 AM, Johan Tibell
wrote: I'm quite worried about this change though. I thought the default role for data type was nominal, as that's the safe default. If the default is representational, every package author will need to be aware of this feature and update their packages. That's quite a high cost.
Nominal default breaks everything that uses newtype deriving and doesn't have role annotations, doesn't it? Representational default means things behave in 7.8 as they did in earlier GHCs.
True, but shouldn't coerce be called unsafeCoerce then as it is, in fact, unsafe from a correctness perspective?

On Fri, Mar 14, 2014 at 9:12 AM, Johan Tibell
On Fri, Mar 14, 2014 at 2:00 PM, Brandon Allbery
wrote: On Fri, Mar 14, 2014 at 5:36 AM, Johan Tibell
wrote: I'm quite worried about this change though. I thought the default role for data type was nominal, as that's the safe default. If the default is representational, every package author will need to be aware of this feature and update their packages. That's quite a high cost.
Nominal default breaks everything that uses newtype deriving and doesn't have role annotations, doesn't it? Representational default means things behave in 7.8 as they did in earlier GHCs.
True, but shouldn't coerce be called unsafeCoerce then as it is, in fact, unsafe from a correctness perspective?
My expectation would be that 7.8 keeps the old behavior while enabling the new, and possibly issues a warning when newtype deriving is used with no role annotations; this gives us a release cycle to get role annotations in place before making the new safe behavior default. -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

My expectation matches Brandon's, that making roles default to nominal would break lots of code and therefore have a higher cost than defaulting to representational (well, phantom actually, but that's a rarer case).
As for issuing a warning, I've thought about this some, but I don't know the right place to detect and issue it. Do we want to warn about any parameterized datatype definition without a role annotation? (That's a lot of them!) Do we want to warn only about abstractly-exported datatypes without role annotations? (But, what about types exported concretely from an internal, hidden module and then re-exported abstractly?) Do we want to warn at use sites? (But then the warning is more about the library than the use site.) It's all quite thorny, and several of us have thought about this all for a while with no strong conclusion.
So, the best thing we came up with is this: Libraries that wish to export abstract data types must do two things:
1. Manage export lists carefully.
2. Use role annotations.
A better question might be how to get the word out about the above.
Whether or not `coerce` is "unsafe from a correctness perspective" depends on your definition of correctness:
- If you care only about type safety, then `coerce` is most certainly safe.
- If you believe that a type's roles are what its author intended, then `coerce` is most certainly safe.
- If you believe that authors may omit critical role annotations and are worried about breaking abstraction, then `coerce` is not safe.
There has been some thought about making `coerce`'s behavior different with -XSafe than without. See, for example, tickets #8745 (https://ghc.haskell.org/trac/ghc/ticket/8745) and #8827 (https://ghc.haskell.org/trac/ghc/ticket/8827). In the end, we decided to remove this, instead believing authors' role annotations (or lack thereof).
Note that 7.8 does not actually give users a new way to break abstractions -- GeneralizedNewtypeDeriving has been around for a while. What 7.8 provides is a way to break abstractions more easily (`coerce`) and a way to prevent this from happening (role annotations).
Richard
On Mar 14, 2014, at 9:22 AM, Brandon Allbery
On Fri, Mar 14, 2014 at 9:12 AM, Johan Tibell
wrote: On Fri, Mar 14, 2014 at 2:00 PM, Brandon Allbery wrote: On Fri, Mar 14, 2014 at 5:36 AM, Johan Tibell wrote: I'm quite worried about this change though. I thought the default role for data type was nominal, as that's the safe default. If the default is representational, every package author will need to be aware of this feature and update their packages. That's quite a high cost. Nominal default breaks everything that uses newtype deriving and doesn't have role annotations, doesn't it? Representational default means things behave in 7.8 as they did in earlier GHCs.
True, but shouldn't coerce be called unsafeCoerce then as it is, in fact, unsafe from a correctness perspective?
My expectation would be that 7.8 keeps the old behavior while enabling the new, and possibly issues a warning when newtype deriving is used with no role annotations; this gives us a release cycle to get role annotations in place before making the new safe behavior default.
-- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

So is the goal that all library authors will add role annotations in the
future? If that doesn't happen, what does that mean for users of coerce?
Will they just have to be careful in what they coerce and make sure that if
their library internally uses coerce that library is only used with types
that have correct role annotations?
On Fri, Mar 14, 2014 at 3:22 PM, Richard Eisenberg
My expectation matches Brandon's, that making roles default to nominal would break lots of code and therefore have a higher cost than defaulting to representational (well, phantom actually, but that's a rarer case).
As for issuing a warning, I've thought about this some, but I don't know the right place to detect and issue it. Do we want to warn about any parameterized datatype definition without a role annotation? (That's a lot of them!) Do we want to warn only about abstractly-exported datatypes without role annotations? (But, what about types exported concretely from an internal, hidden module and then re-exported abstractly?) Do we want to warn at use sites? (But then the warning is more about the library than the use site.) It's all quite thorny, and several of us have thought about this all for a while with no strong conclusion.
So, the best thing we came up with is this: Libraries that wish to export abstract data types must do two things: 1. Manage export lists carefully. 2. Use role annotations.
A better question might be how to get the word out about the above.
Whether or not `coerce` is "unsafe from a correctness perspective" depends on your definition of correctness: - If you care only about type safety, then `coerce` is most certainly safe. - If you believe that a type's roles are what its author intended, then `coerce` is most certainly safe. - If you believe that authors may omit critical role annotations and are worried about breaking abstraction, then `coerce` is not safe.
There has been some thought about making `coerce`'s behavior different with -XSafe than without. See, for example, tickets #8745 ( https://ghc.haskell.org/trac/ghc/ticket/8745) and #8827 ( https://ghc.haskell.org/trac/ghc/ticket/8827). In the end, we decided to remove this, instead believing authors' role annotations (or lack thereof).
Note that 7.8 does not actually give users a new way to break abstractions -- GeneralizedNewtypeDeriving has been around for a while. What 7.8 provides is a way to break abstractions more easily (`coerce`) and a way to prevent this from happening (role annotations).
Richard
On Mar 14, 2014, at 9:22 AM, Brandon Allbery
wrote: On Fri, Mar 14, 2014 at 9:12 AM, Johan Tibell
wrote: On Fri, Mar 14, 2014 at 2:00 PM, Brandon Allbery
wrote: On Fri, Mar 14, 2014 at 5:36 AM, Johan Tibell
wrote: I'm quite worried about this change though. I thought the default role for data type was nominal, as that's the safe default. If the default is representational, every package author will need to be aware of this feature and update their packages. That's quite a high cost.
Nominal default breaks everything that uses newtype deriving and doesn't have role annotations, doesn't it? Representational default means things behave in 7.8 as they did in earlier GHCs.
True, but shouldn't coerce be called unsafeCoerce then as it is, in fact, unsafe from a correctness perspective?
My expectation would be that 7.8 keeps the old behavior while enabling the new, and possibly issues a warning when newtype deriving is used with no role annotations; this gives us a release cycle to get role annotations in place before making the new safe behavior default.
-- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

While I see where your discomfort is coming from, this same argument could be said about GeneralizedNewtypeDeriving. I suppose the answer is "yes" -- the goal is for library authors to add role annotations in the future. There is no way to infer what roles are appropriate to preserve the right level of abstraction. Note that this goal would stand regardless of the decision around default roles. Until then, we will have to use `coerce` carefully. After all, `coerce` is only an optimization -- it isn't meant to provide a feature that is otherwise impossible to implement.
Richard
On Mar 14, 2014, at 10:26 AM, Johan Tibell
So is the goal that all library authors will add role annotations in the future? If that doesn't happen, what does that mean for users of coerce? Will they just have to be careful in what they coerce and make sure that if their library internally uses coerce that library is only used with types that have correct role annotations?
On Fri, Mar 14, 2014 at 3:22 PM, Richard Eisenberg
wrote: My expectation matches Brandon's, that making roles default to nominal would break lots of code and therefore have a higher cost than defaulting to representational (well, phantom actually, but that's a rarer case). As for issuing a warning, I've thought about this some, but I don't know the right place to detect and issue it. Do we want to warn about any parameterized datatype definition without a role annotation? (That's a lot of them!) Do we want to warn only about abstractly-exported datatypes without role annotations? (But, what about types exported concretely from an internal, hidden module and then re-exported abstractly?) Do we want to warn at use sites? (But then the warning is more about the library than the use site.) It's all quite thorny, and several of us have thought about this all for a while with no strong conclusion.
So, the best thing we came up with is this: Libraries that wish to export abstract data types must do two things: 1. Manage export lists carefully. 2. Use role annotations.
A better question might be how to get the word out about the above.
Whether or not `coerce` is "unsafe from a correctness perspective" depends on your definition of correctness: - If you care only about type safety, then `coerce` is most certainly safe. - If you believe that a type's roles are what its author intended, then `coerce` is most certainly safe. - If you believe that authors may omit critical role annotations and are worried about breaking abstraction, then `coerce` is not safe.
There has been some thought about making `coerce`'s behavior different with -XSafe than without. See, for example, tickets #8745 (https://ghc.haskell.org/trac/ghc/ticket/8745) and #8827 (https://ghc.haskell.org/trac/ghc/ticket/8827). In the end, we decided to remove this, instead believing authors' role annotations (or lack thereof).
Note that 7.8 does not actually give users a new way to break abstractions -- GeneralizedNewtypeDeriving has been around for a while. What 7.8 provides is a way to break abstractions more easily (`coerce`) and a way to prevent this from happening (role annotations).
Richard
On Mar 14, 2014, at 9:22 AM, Brandon Allbery
wrote: On Fri, Mar 14, 2014 at 9:12 AM, Johan Tibell
wrote: On Fri, Mar 14, 2014 at 2:00 PM, Brandon Allbery wrote: On Fri, Mar 14, 2014 at 5:36 AM, Johan Tibell wrote: I'm quite worried about this change though. I thought the default role for data type was nominal, as that's the safe default. If the default is representational, every package author will need to be aware of this feature and update their packages. That's quite a high cost. Nominal default breaks everything that uses newtype deriving and doesn't have role annotations, doesn't it? Representational default means things behave in 7.8 as they did in earlier GHCs.
True, but shouldn't coerce be called unsafeCoerce then as it is, in fact, unsafe from a correctness perspective?
My expectation would be that 7.8 keeps the old behavior while enabling the new, and possibly issues a warning when newtype deriving is used with no role annotations; this gives us a release cycle to get role annotations in place before making the new safe behavior default.
-- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Hi Richard,
On 14 March 2014 15:22, Richard Eisenberg
There has been some thought about making `coerce`'s behavior different with -XSafe than without. See, for example, tickets #8745 (https://ghc.haskell.org/trac/ghc/ticket/8745) and #8827 (https://ghc.haskell.org/trac/ghc/ticket/8827). In the end, we decided to remove this, instead believing authors' role annotations (or lack thereof).
Interesting, it looks like the paper hasn't yet been updated to reflect this.
Note that 7.8 does not actually give users a new way to break abstractions -- GeneralizedNewtypeDeriving has been around for a while. What 7.8 provides is a way to break abstractions more easily (`coerce`) and a way to prevent this from happening (role annotations).
Isn't this false in the case of -XSafe? In 7.8 one will be able to coerce 'Map Int a' to 'Map Age a' (provided that there is no role annotation for Map), which didn't work previously because SafeHaskell prohibited GND.

On Mar 14, 2014, at 11:41 AM, Mikhail Glushenkov
Hi Richard,
On 14 March 2014 15:22, Richard Eisenberg
wrote: There has been some thought about making `coerce`'s behavior different with -XSafe than without. See, for example, tickets #8745 (https://ghc.haskell.org/trac/ghc/ticket/8745) and #8827 (https://ghc.haskell.org/trac/ghc/ticket/8827). In the end, we decided to remove this, instead believing authors' role annotations (or lack thereof).
Interesting, it looks like the paper hasn't yet been updated to reflect this.
That's correct. This is a late-breaking design decision.
Note that 7.8 does not actually give users a new way to break abstractions -- GeneralizedNewtypeDeriving has been around for a while. What 7.8 provides is a way to break abstractions more easily (`coerce`) and a way to prevent this from happening (role annotations).
Isn't this false in the case of -XSafe? In 7.8 one will be able to coerce 'Map Int a' to 'Map Age a' (provided that there is no role annotation for Map), which didn't work previously because SafeHaskell prohibited GND.
This is an even thornier corner of a thorny design decision. As one can discover from various public sources, I have advocated for adding extra checks under -XSafe, essentially closing this hole, as described in the paper and in those tickets. However, due to trouble *inferring* safe mode with the extra checks, and the fact that there was no clear design goal to attend to, we decided to drop the checks, with Simon PJ consistently advocating against the checks. There's nothing insurmountable here, just more engineering overhead. Is it worth it? The real trouble with making this decision is that we have no real guidance. We've tried contacting David Terei (the originator of Safe Haskell) several times to no avail. If you are an actual consumer of Safe Haskell and would like to share your opinion on this front, I do encourage you to make a ticket, essentially requesting a resurrection of the extra Safe checks. Richard

Hi Richard,
On 14 March 2014 17:25, Richard Eisenberg
This is an even thornier corner of a thorny design decision. As one can discover from various public sources, I have advocated for adding extra checks under -XSafe, essentially closing this hole, as described in the paper and in those tickets. However, due to trouble *inferring* safe mode with the extra checks, and the fact that there was no clear design goal to attend to, we decided to drop the checks, with Simon PJ consistently advocating against the checks. There's nothing insurmountable here, just more engineering overhead. Is it worth it?
I think that you were right. IIUC, omitting these checks essentially makes the MinList example from the Safe Haskell paper legal (provided that there are no role annotations), which was the reason for prohibiting GND in Safe Haskell code. I agree with Brandon that it'd be nice to have some kind of warning.
The real trouble with making this decision is that we have no real guidance. We've tried contacting David Terei (the originator of Safe Haskell) several times to no avail. If you are an actual consumer of Safe Haskell and would like to share your opinion on this front, I do encourage you to make a ticket, essentially requesting a resurrection of the extra Safe checks.
Yes, it would be nice if David Terei or David Mazières (CC:ed) could comment.

Speaking from the vantage point of platform.... This pair of comments
(emphasis mine) have my alarm index on high:
On Fri, Mar 14, 2014 at 2:36 AM, Johan Tibell
I'm quite worried about this change though. I thought the default rolefor data type was nominal, as that's the safe default. *If the default is representational, every package author will need to be aware of this feature and update their packages.* That's quite a high cost.
On Fri, Mar 14, 2014 at 6:00 AM, Brandon Allbery
*Nominal default breaks everything that uses newtype deriving and doesn't have role annotations, doesn't it?* Representational default means things behave in 7.8 as they did in earlier GHCs.
Am I reading these pair of statements correctly? It seems to imply to me
that *every* parameterized type that uses a type constraint on a parameter
*must* be reviewed and possibly annotated to work correctly, one way or the
other!
Seems so:
On Fri, Mar 14, 2014 at 7:22 AM, Richard Eisenberg
So, the best thing we came up with is this: Libraries that wish to export abstract data types must do two things: 1. Manage export lists carefully. *2. Use role annotations.*
This is huge order, and one that will produce significant strain on the ecosystem. For one, this will set back Haskell Platform months: We have 250k lines of Haskell by 30+ authors that will need to be reviewed and updated. And all of this is so that data types can be coerced more safely? While I'm all for safely, the number of places where coercion is that important seems very small... and this addition to the language and burden on the libraries very high. If this feature cannot be added safely without reviewing 1/4 million lines of library code (not to mention all of hackage)... Then I think it isn't ready and shouldn't be released in 7.8. - Mark

2014-03-24 15:14 GMT+01:00 Mark Lentczner
Speaking from the vantage point of platform.... This pair of comments (emphasis mine) have my alarm index on high:
On Fri, Mar 14, 2014 at 2:36 AM, Johan Tibell
wrote: [...] So, the best thing we came up with is this: Libraries that wish to export abstract data types must do two things: 1. Manage export lists carefully. 2. Use role annotations.
This is huge order, and one that will produce significant strain on the ecosystem. For one, this will set back Haskell Platform months: We have 250k lines of Haskell by 30+ authors that will need to be reviewed and updated. [...]
Hmmm, I didn't follow role annotations at all so far, because I assumed it was of no concern to me as a library author *unless* I use some shiny new machinery in my library. Did I misunderstand that? How can I find out if I have to do something? What happens if I don't do something? What about Haskell systems which are not GHC? Do I have to #ifdef around those annotations? :-P I'm a bit clueless, and I'm guess I'm not alone... :-/ If this new feature really implies that massive amount of library code review, we should discuss first if it's really worth the trouble. The GHC release and the HP are already late... Cheers, S.

On Mon, Mar 24, 2014 at 10:14 AM, Mark Lentczner
On Fri, Mar 14, 2014 at 2:36 AM, Johan Tibell
wrote: I'm quite worried about this change though. I thought the default rolefor data type was nominal, as that's the safe default. *If the default is representational, every package author will need to be aware of this feature and update their packages.* That's quite a high cost.
On Fri, Mar 14, 2014 at 6:00 AM, Brandon Allbery
wrote: *Nominal default breaks everything that uses newtype deriving and doesn't
have role annotations, doesn't it?* Representational default means things behave in 7.8 as they did in earlier GHCs.
Am I reading these pair of statements correctly? It seems to imply to me that *every* parameterized type that uses a type constraint on a parameter *must* be reviewed and possibly annotated to work correctly, one way or the other!
No; if the default is representational, everything works as it did in earlier versions, potential bugs/unsafety and all. If the default is immediately switched to nominal, *then* every affected type must be reviewed immediately. My counter-proposal was to have 7.8 default to representational to give library maintainers a release cycle to add the necessary annotations, then switch the default to nominal in 7.10 to get the additional safety. -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

On Mon, Mar 24, 2014 at 10:28 AM, Brandon Allbery
On Mon, Mar 24, 2014 at 10:14 AM, Mark Lentczner
wrote:
On Fri, Mar 14, 2014 at 2:36 AM, Johan Tibell
wrote: I'm quite worried about this change though. I thought the default rolefor data type was nominal, as that's the safe default. *If the default is representational, every package author will need to be aware of this feature and update their packages.* That's quite a high cost.
On Fri, Mar 14, 2014 at 6:00 AM, Brandon Allbery
wrote: *Nominal default breaks everything that uses newtype deriving and doesn't
have role annotations, doesn't it?* Representational default means things behave in 7.8 as they did in earlier GHCs.
Am I reading these pair of statements correctly? It seems to imply to me that *every* parameterized type that uses a type constraint on a parameter *must* be reviewed and possibly annotated to work correctly, one way or the other!
No; if the default is representational, everything works as it did in earlier versions, potential bugs/unsafety and all. If the default is immediately switched to nominal, *then* every affected type must be reviewed immediately. My counter-proposal was to have 7.8 default to representational to give library maintainers a release cycle to add the necessary annotations, then switch the default to nominal in 7.10 to get the additional safety.
By the way, since I suspected (and was subsequently proved out) that appropriate warnings are difficult, perhaps there should be some mechanism to specify to ghc 7.8 whether a compile should default to representational or nominal so that authors have a way to test their code / look for problems. -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

On Mon, Mar 24, 2014 at 7:28 AM, Brandon Allbery
No; if the default is representational, everything works as it did in earlier versions, potential bugs/unsafety and all. If the default is immediately switched to nominal, *then* every affected type must be reviewed immediately.
Now I'm confused about the current state of the default.... But it doesn't matter either way: The Platform is expected to work cohesively with the GHC release, and either of these defaults spells a huge amount of work for the Platform.
My counter-proposal was to have 7.8 default to representational to give library maintainers a release cycle to add the necessary annotations, then switch the default to nominal in 7.10 to get the additional safety.
This is unworkable. How much conditional code do you want library writers
to have to have? Library writers strive to have code which works with n
prior releases where n is commonly 3. Having code that works with 7.6, 7.8,
and 7.10 would be a nighmare!
On Mon, Mar 24, 2014 at 7:32 AM, Brandon Allbery
perhaps there should be some mechanism to specify to ghc 7.8 whether a compile should default to representational or nominal so that authors have a way to test their code / look for problems.
Also unworkable... now we need a conditional flag for the state of the default so the code can be written to work with either based on a GHC flag? And how is that supposed to work with already compiled dependencies (sandboxed or not)? Is cabal now to take this flag into account? the Package manager signatures too? The major problem with this feature is that it is massively global in scope. This is extremely rare for GHC extensions (Safe comes to mind)... and with good reason: It is very very expensive. The motivating case here, a compiler checked safe zero-cost coerce, seems way out of proportion to the cost: Careful review of every library abstract type, and addition of *three+* lines of source (remember, this must be CPP guarded, so you have to add CPP extension on to every file, too).

On Mon, Mar 24, 2014 at 10:44 AM, Mark Lentczner
On Mon, Mar 24, 2014 at 7:28 AM, Brandon Allbery
wrote: My counter-proposal was to have 7.8 default to representational to give library maintainers a release cycle to add the necessary annotations, then switch the default to nominal in 7.10 to get the additional safety.
This is unworkable. How much conditional code do you want library writers to have to have? Library writers strive to have code which works with n prior releases where n is commonly 3. Having code that works with 7.6, 7.8, and 7.10 would be a nighmare!
No? Immediately switching to nominal requires those annotations immediately. No immediate change is needed if we keep the current default; if you have problems with conditional code, you will have them no matter what with roles --- the only question is when. Also see SPJ's response.
On Mon, Mar 24, 2014 at 7:32 AM, Brandon Allbery
wrote: perhaps there should be some mechanism to specify to ghc 7.8 whether a
compile should default to representational or nominal so that authors have a way to test their code / look for problems.
Also unworkable... now we need a conditional flag for the state of the default so the code can
be written to work with either based on a GHC flag? And how is that
supposed to work with
Nope; in fact, code containing this flag should be rejected by hackage the same way some other options are rejected. It exists ONLY to help library authors with the transition, and should never be used with released code, only for maintainer debugging/testing. It would be nice if it could be forced to only work in sandboxes, but that would require a rather unhealthy level of ghc / cabal-install interaction. I expect such testing will end up requiring hsenv. There's just no good way of handling this whole role annotations thing; it's a massive sledgehammer. -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

On Mon, Mar 24, 2014 at 10:57 AM, Brandon Allbery
No? Immediately switching to nominal requires those annotations immediately. No immediate change is needed if we keep the current default; if you have problems with conditional code, you will have them no matter what with roles --- the only question is when. Also see SPJ's response.
I don't think this is true. If nominal-by-default is not on the road map, then most people never have to do anything. If I can generalize about myself at least, most data types that are defined do not have (additional, role-enforceable) invariants. They are mainly simple combinations of other types in ways that allow me to structure my code well. So the vast majority of types defined by people like me should have representational parameters, unless one of the constituent types is a Set or Map or what have you, in which case nominal can be inferred, assuming Set and Map are appropriately annotated. Nominal-by-default would require annotations for every minor definition like this in order to correctly specify the type. By contrast, representational-by-default imposes some work/diligence on authors of data structures with invariants, which tend (in my experience) to be the minority of definitions, and typically come as libraries. I feel a little bad suggesting 'unsafety' as the default, but the safe default imposes a significant, perpetual cost on everyone using the language in return for defense against occasional oversights by library authors. That doesn't seem like a good trade off. -- Dan

Apols if I'm overstating the case, but let me try to clear things up. Roles are not in place to provide a "safe" cheap coerce. Roles are in place to _prevent_ an unsoundness with newtype deriving in the presence of type families. They also happen to _allow_ a cheaper coerce. The unsoundness is fixed by roles, with or without specific role annotations, because the necessary roles for type-safety (preventing segfault) are inferred/enforced regardless. With or without roles, in the past, it has been possible to circumvent certain mechanisms of abstraction by using newtype deriving. Explicit roles now _allow_ library writers to, for the first time, to enforce these abstraction mechanisms more strongly than in the past. We also happen to have a new "coerce" that will not segfault, and _if_ role annotations are correct, will respect representation-hiding. If libraries do _not_ get updated with roles, the "worst" that can happen is that their abstractions are precisely as deliberately circumventable as in the past, although there is now an "easy" function provided that makes this circumvention more straightforward. So I feel it is "better" to enforce representation-hiding through proper usage of roles. However, it is also no great sin to _not_ enforce it for some span of time, since all that doing so prevents is a rather (at the moment) esoteric mechanism for developers to shoot themselves in the foot -- a mechanism that in a slightly different form has existed all along. -g On 3/24/14, 10:44 AM, Mark Lentczner wrote:
The major problem with this feature is that it is massively global in scope. This is extremely rare for GHC extensions (Safe comes to mind)... and with good reason: It is very very expensive. The motivating case here, a compiler checked safe zero-cost coerce, seems way out of proportion to the cost: Careful review of every library abstract type, and addition of *three+* lines of source (remember, this must be CPP guarded, so you have to add CPP extension on to every file, too).

When Brandon says “potential bugs/unsafety and all” he means GeneralisedNewtypeDeriving (GND). That already exists, and already allows you to do bad things (Trac #1496 among others).
See the thread on https://ghc.haskell.org/trac/ghc/ticket/8827, starting especially at comment 17 for more discussion and some insightful comments. As Edward (on the ticket) and Brandon (here) point out, going to “nominal by default” will be very safe but it’ll break many Haskell packages which use GND.
This is really a library/user question, not a GHC one. We can implement whatever default you want. But GHC 7.8 is about to be released and this debate has been going on for some weeks, at high intensity on ghc-devs, plus Richard specifically advertised it to the libraries list back in Novemberhttp://www.haskell.org/pipermail/libraries/2013-November/021707.html, and again a couple of weeks agohttp://www.haskell.org/pipermail/libraries/2014-March/022321.html.
I think the status quo is not unreasonable. One question you might want to debate is whether, as Brandon suggests, you want to move to “nominal by default” in due course.
Simon
From: Libraries [mailto:libraries-bounces@haskell.org] On Behalf Of Brandon Allbery
Sent: 24 March 2014 14:28
To: Mark Lentczner
Cc: GHC Development Mailing List; libraries@haskell.org Libraries
Subject: Re: We need to add role annotations for 7.8
On Mon, Mar 24, 2014 at 10:14 AM, Mark Lentczner

Thanks for the pointers, Simon. I appologize for coming to this quite so late... I didn't realize the global impact of this feature.
From a "meaning" perspective, I'm agnostic on the default. From a "engineering" perspective, I want a default that "does a good enough, reasonably safe thing" if programmers ignore the feature.
The later is subtle as there are different vantage points for different developers. In the Platform, we have many libraries that we are encouraging both end-programmers, and other library authors to make use of and depend on extensively. This means those libraries have to work for both programmers that are ignoring the feature, and those that use it. In that later case, there is the even more subtle distinction of those that use the feature for their own code, and those that use it in libraries they make available. The later case is issue: It seems a real mess if a library author who wanted to use the new feature, had to circumvent a HP library because it didn't annotate. Similar thought experiment: What would be the downside if containers didn't annotate? Would that just make the feature unusable because everything uses containers? To put it more directly: with the satus-quo default of representations, what is the down side if a library, a widely used library, doesn't bother to annotate? What would be the loss if containers didn't annotate? (I know it did, this is the thought experiment... because I've got 30+ libraries in HP that are in this boat.)

Again, sorry for the 11:59 meddling.... The syntax of role annotations is very heavy weight, and requires lots of CPP where there wasn't need before. Two thoughts: 1) Couldn't we do something like use "cue" type constraints? For example, assuming the default is representational, and that phantom can just be inferred, all we need is a way to indicate nominal: data (Nominal k) => Map k v = ... This could then probably be easily made to compile in other compilers with some null library implementation of Nominal 2) An alternative to the above. We generally frown on constraints in a data / newtype declaration, but perhaps this is exactly the case for them, whereby we can now do away with the type role syntax: We can infer nominal if there are *any* constraints on a type parameter, *representational* if there are none, and *phantom *if there are no mentions in the right hand side: data (Eq k) => Map k v = ... This seems even nicer and just works with all compilers... but perhaps I'm missing something. (Yes, I imagine there are type constraints that shouldn't force nominal, but perhaps not worth worrying about?) Mind you, this all just about syntax... the issue of what is the implication for libraries of the default being representational is still at hand.

It was suggested on reddit and seemed to be thought a good idea that it
would be better for the syntax to be a comment like {-# INLINE -#}, etc.
That allows backward compatibility with older versions without CPP, and
also doesn't use up syntax.
I think the problem is that we are on the doorstep of a release now and the
existing syntax has already been under use.
On Mon, Mar 24, 2014 at 8:36 AM, Mark Lentczner
Again, sorry for the 11:59 meddling....
The syntax of role annotations is very heavy weight, and requires lots of CPP where there wasn't need before. Two thoughts:
1) Couldn't we do something like use "cue" type constraints? For example, assuming the default is representational, and that phantom can just be inferred, all we need is a way to indicate nominal:
data (Nominal k) => Map k v = ...
This could then probably be easily made to compile in other compilers with some null library implementation of Nominal
2) An alternative to the above. We generally frown on constraints in a data / newtype declaration, but perhaps this is exactly the case for them, whereby we can now do away with the type role syntax: We can infer nominal if there are *any* constraints on a type parameter, *representational* if there are none, and *phantom *if there are no mentions in the right hand side:
data (Eq k) => Map k v = ...
This seems even nicer and just works with all compilers... but perhaps I'm missing something. (Yes, I imagine there are type constraints that shouldn't force nominal, but perhaps not worth worrying about?)
Mind you, this all just about syntax... the issue of what is the implication for libraries of the default being representational is still at hand.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

This puts the constraint on the wrong thing.
I did argue for a pragma-like syntax for the annotations when they were
first proposed, as the need for library authors to hide these behind CPP
pragmas bothers me a great deal, but I think for better or worse that
syntax decision is largely behind us.
A type-class driven approach does have some promise, but that said, it
can't look like what you've written.
What you've written:
data Nominal k => Map k a
is saying something about the argument k, not about if you can turn
Map kinto Map
k', which is actually about Map, k is just along for the ride.
Really what we're talking about is that the next argument is
representational as applied. Also, the right 'open world' version would be
to talk about it as classes would be:
class Representational t where
rep :: Coercion a b -> Coercion (t a) (t b)
class Representational t => Phantom t where
phantom :: Coercion (t a) (t b)
With "Nominal" simply being the absence of either of those instances.
data Map k a
would need
instance Representational (Map k)
since the 'a' can be coerced as it has a representational role.
instance Representational (->)
instance Representational ((->) a)
But there are actually still open issues I don't know how to solve, even
with this approach.
-Edward
On Mon, Mar 24, 2014 at 11:36 AM, Mark Lentczner
Again, sorry for the 11:59 meddling....
The syntax of role annotations is very heavy weight, and requires lots of CPP where there wasn't need before. Two thoughts:
1) Couldn't we do something like use "cue" type constraints? For example, assuming the default is representational, and that phantom can just be inferred, all we need is a way to indicate nominal:
data (Nominal k) => Map k v = ...
This could then probably be easily made to compile in other compilers with some null library implementation of Nominal
2) An alternative to the above. We generally frown on constraints in a data / newtype declaration, but perhaps this is exactly the case for them, whereby we can now do away with the type role syntax: We can infer nominal if there are *any* constraints on a type parameter, *representational* if there are none, and *phantom *if there are no mentions in the right hand side:
data (Eq k) => Map k v = ...
This seems even nicer and just works with all compilers... but perhaps I'm missing something. (Yes, I imagine there are type constraints that shouldn't force nominal, but perhaps not worth worrying about?)
Mind you, this all just about syntax... the issue of what is the implication for libraries of the default being representational is still at hand.
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs

Mark,
We're currently planning to retain the existing behavior of
GeneralizedNewtypeDeriving with regards to Safe Haskell. That is, Safe
Haskell and GND still won't mix in 7.8 due to these same security concerns.
I think a key observation with regards to GeneralizedNewtypeDeriving is
with representational roles as default the new roles machinery with the
representational default lets you write nothing you couldn't write before.
No new security vulnerabilities are introduced. They were there all along!
We're also disabling the Safe flag on Data.Coerce. In that light, `coerce`
then can be viewed as a more friendly but still evil version of
unsafeCoerce. It lets you write nothing you couldn't write before with
`unsafeCoerce`. I view it as merely an occasional situational improvement
over the existing unsafeCoerce in that it at least enforces
representational equality.
Making the default role annotation nominal comes at a very very real cost.
Namely, *all* of generalized newtype deriving anywhere breaks, and everyone
forever will have to put annotations in to fix it.
The 'backwards' representational default puts the burden on a small
minority of library authors.
I'm not a huge fan of the representational machinery, in that it hoists us
upon this dilemma, but given the choice between everyone paying in
perpetuity and a small minority of skilled library authors adding a handful
of annotations that for the most part have already been added, and which
expose them to no more risk than they'd had before if they forget, I'm
definitely in favor of the current solution.
-Edward
On Mon, Mar 24, 2014 at 11:26 AM, Mark Lentczner
Thanks for the pointers, Simon. I appologize for coming to this quite so late... I didn't realize the global impact of this feature.
From a "meaning" perspective, I'm agnostic on the default. From a "engineering" perspective, I want a default that "does a good enough, reasonably safe thing" if programmers ignore the feature.
The later is subtle as there are different vantage points for different developers. In the Platform, we have many libraries that we are encouraging both end-programmers, and other library authors to make use of and depend on extensively. This means those libraries have to work for both programmers that are ignoring the feature, and those that use it. In that later case, there is the even more subtle distinction of those that use the feature for their own code, and those that use it in libraries they make available.
The later case is issue: It seems a real mess if a library author who wanted to use the new feature, had to circumvent a HP library because it didn't annotate. Similar thought experiment: What would be the downside if containers didn't annotate? Would that just make the feature unusable because everything uses containers?
To put it more directly: with the satus-quo default of representations, what is the down side if a library, a widely used library, doesn't bother to annotate? What would be the loss if containers didn't annotate? (I know it did, this is the thought experiment... because I've got 30+ libraries in HP that are in this boat.)
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

In that light, `coerce` then can be viewed as a more friendly but still evil version of unsafeCoerce
Coerce embodies one rather compelling improvement: it is type-sound. unsafeCoerce can cause arbitrary seg-faults etc. ‘coerce’ cannot. Call me an old-fashioned “well-typed programs don’t go wrong” man, but I think that’s a big plus. Much more than “an occasional situation improvement”.
Granted, “type-sound” doesn’t guarantee “correct”, but then it never did.
The role machinery doesn’t exactly hoist us on a dilemma – it merely exposes the dilemma that was there all the time.
Simon
From: Edward Kmett [mailto:ekmett@gmail.com]
Sent: 24 March 2014 19:11
To: Mark Lentczner
Cc: Simon Peyton Jones; libraries@haskell.org Libraries; ghc-devs@haskell.org
Subject: Re: We need to add role annotations for 7.8
Mark,
We're currently planning to retain the existing behavior of GeneralizedNewtypeDeriving with regards to Safe Haskell. That is, Safe Haskell and GND still won't mix in 7.8 due to these same security concerns.
I think a key observation with regards to GeneralizedNewtypeDeriving is with representational roles as default the new roles machinery with the representational default lets you write nothing you couldn't write before. No new security vulnerabilities are introduced. They were there all along!
We're also disabling the Safe flag on Data.Coerce. In that light, `coerce` then can be viewed as a more friendly but still evil version of unsafeCoerce. It lets you write nothing you couldn't write before with `unsafeCoerce`. I view it as merely an occasional situational improvement over the existing unsafeCoerce in that it at least enforces representational equality.
Making the default role annotation nominal comes at a very very real cost. Namely, all of generalized newtype deriving anywhere breaks, and everyone forever will have to put annotations in to fix it.
The 'backwards' representational default puts the burden on a small minority of library authors.
I'm not a huge fan of the representational machinery, in that it hoists us upon this dilemma, but given the choice between everyone paying in perpetuity and a small minority of skilled library authors adding a handful of annotations that for the most part have already been added, and which expose them to no more risk than they'd had before if they forget, I'm definitely in favor of the current solution.
-Edward
On Mon, Mar 24, 2014 at 11:26 AM, Mark Lentczner

Fair enough. I did try to convey that in the following sentence about how it at least enforces representational equality, but I can see how my statement might be taken as understating the importance of that property. Sent from my iPhone
On Mar 24, 2014, at 6:57 PM, Simon Peyton Jones
wrote: In that light, `coerce` then can be viewed as a more friendly but still evil version of unsafeCoerce
Coerce embodies one rather compelling improvement: it is type-sound. unsafeCoerce can cause arbitrary seg-faults etc. ‘coerce’ cannot. Call me an old-fashioned “well-typed programs don’t go wrong” man, but I think that’s a big plus. Much more than “an occasional situation improvement”.
Granted, “type-sound” doesn’t guarantee “correct”, but then it never did.
The role machinery doesn’t exactly hoist us on a dilemma – it merely exposes the dilemma that was there all the time.
Simon
From: Edward Kmett [mailto:ekmett@gmail.com] Sent: 24 March 2014 19:11 To: Mark Lentczner Cc: Simon Peyton Jones; libraries@haskell.org Libraries; ghc-devs@haskell.org Subject: Re: We need to add role annotations for 7.8
Mark,
We're currently planning to retain the existing behavior of GeneralizedNewtypeDeriving with regards to Safe Haskell. That is, Safe Haskell and GND still won't mix in 7.8 due to these same security concerns.
I think a key observation with regards to GeneralizedNewtypeDeriving is with representational roles as default the new roles machinery with the representational default lets you write nothing you couldn't write before. No new security vulnerabilities are introduced. They were there all along!
We're also disabling the Safe flag on Data.Coerce. In that light, `coerce` then can be viewed as a more friendly but still evil version of unsafeCoerce. It lets you write nothing you couldn't write before with `unsafeCoerce`. I view it as merely an occasional situational improvement over the existing unsafeCoerce in that it at least enforces representational equality.
Making the default role annotation nominal comes at a very very real cost. Namely, all of generalized newtype deriving anywhere breaks, and everyone forever will have to put annotations in to fix it.
The 'backwards' representational default puts the burden on a small minority of library authors.
I'm not a huge fan of the representational machinery, in that it hoists us upon this dilemma, but given the choice between everyone paying in perpetuity and a small minority of skilled library authors adding a handful of annotations that for the most part have already been added, and which expose them to no more risk than they'd had before if they forget, I'm definitely in favor of the current solution.
-Edward
On Mon, Mar 24, 2014 at 11:26 AM, Mark Lentczner
wrote: Thanks for the pointers, Simon. I appologize for coming to this quite so late... I didn't realize the global impact of this feature.
From a "meaning" perspective, I'm agnostic on the default.
From a "engineering" perspective, I want a default that "does a good enough, reasonably safe thing" if programmers ignore the feature.
The later is subtle as there are different vantage points for different developers. In the Platform, we have many libraries that we are encouraging both end-programmers, and other library authors to make use of and depend on extensively. This means those libraries have to work for both programmers that are ignoring the feature, and those that use it. In that later case, there is the even more subtle distinction of those that use the feature for their own code, and those that use it in libraries they make available.
The later case is issue: It seems a real mess if a library author who wanted to use the new feature, had to circumvent a HP library because it didn't annotate. Similar thought experiment: What would be the downside if containers didn't annotate? Would that just make the feature unusable because everything uses containers?
To put it more directly: with the satus-quo default of representations, what is the down side if a library, a widely used library, doesn't bother to annotate? What would be the loss if containers didn't annotate? (I know it did, this is the thought experiment... because I've got 30+ libraries in HP that are in this boat.)
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

I have a few responses to various themes in this thread, but nothing terribly unexpected: - The introduction of roles is the end of the story that began with the discovery of bug #1496. The alternative would be to do away with GND. `coerce` is just a convenient application of roles, not the reason they were introduced. - The concrete syntax for role ascriptions was debated in public, in bug #8185. There is further discussion of the design choice in the appendix of the extended version of our recent draft paper on the subject: www.cis.upenn.edu/~eir/papers/2014/coercible/coercible-ext.pdf I'm afraid it's too late now to make changes. I don't love what we ended up with, but I believe it's the best syntax that was proposed. - I agree with Simon that `coerce` is quite a bit safer than `unsafeCoerce`. Under the assumption that all libraries are written correctly (that is, with proper role annotations), `coerce` is in fact fully safe. - I surely recognize why and how this causes a Major Pain for Mark, and for other library maintainers. I wish there were an easier solution. However, I will perhaps repeat others in saying that a library that doesn't add role annotations is no more wrong in 7.8 than it was since GND was introduced. The only difference with 7.8 is that, now, there is a way to be right. Richard On Mar 24, 2014, at 9:32 PM, Edward A Kmett wrote:
Fair enough. I did try to convey that in the following sentence about how it at least enforces representational equality, but I can see how my statement might be taken as understating the importance of that property.
Sent from my iPhone
On Mar 24, 2014, at 6:57 PM, Simon Peyton Jones
wrote: In that light, `coerce` then can be viewed as a more friendly but still evil version of unsafeCoerce
Coerce embodies one rather compelling improvement: it is type-sound. unsafeCoerce can cause arbitrary seg-faults etc. ‘coerce’ cannot. Call me an old-fashioned “well-typed programs don’t go wrong” man, but I think that’s a big plus. Much more than “an occasional situation improvement”.
Granted, “type-sound” doesn’t guarantee “correct”, but then it never did.
The role machinery doesn’t exactly hoist us on a dilemma – it merely exposes the dilemma that was there all the time.
Simon
From: Edward Kmett [mailto:ekmett@gmail.com] Sent: 24 March 2014 19:11 To: Mark Lentczner Cc: Simon Peyton Jones; libraries@haskell.org Libraries; ghc-devs@haskell.org Subject: Re: We need to add role annotations for 7.8
Mark,
We're currently planning to retain the existing behavior of GeneralizedNewtypeDeriving with regards to Safe Haskell. That is, Safe Haskell and GND still won't mix in 7.8 due to these same security concerns.
I think a key observation with regards to GeneralizedNewtypeDeriving is with representational roles as default the new roles machinery with the representational default lets you write nothing you couldn't write before. No new security vulnerabilities are introduced. They were there all along!
We're also disabling the Safe flag on Data.Coerce. In that light, `coerce` then can be viewed as a more friendly but still evil version of unsafeCoerce. It lets you write nothing you couldn't write before with `unsafeCoerce`. I view it as merely an occasional situational improvement over the existing unsafeCoerce in that it at least enforces representational equality.
Making the default role annotation nominal comes at a very very real cost. Namely, all of generalized newtype deriving anywhere breaks, and everyone forever will have to put annotations in to fix it.
The 'backwards' representational default puts the burden on a small minority of library authors.
I'm not a huge fan of the representational machinery, in that it hoists us upon this dilemma, but given the choice between everyone paying in perpetuity and a small minority of skilled library authors adding a handful of annotations that for the most part have already been added, and which expose them to no more risk than they'd had before if they forget, I'm definitely in favor of the current solution.
-Edward
On Mon, Mar 24, 2014 at 11:26 AM, Mark Lentczner
wrote: Thanks for the pointers, Simon. I appologize for coming to this quite so late... I didn't realize the global impact of this feature.
From a "meaning" perspective, I'm agnostic on the default.
From a "engineering" perspective, I want a default that "does a good enough, reasonably safe thing" if programmers ignore the feature.
The later is subtle as there are different vantage points for different developers. In the Platform, we have many libraries that we are encouraging both end-programmers, and other library authors to make use of and depend on extensively. This means those libraries have to work for both programmers that are ignoring the feature, and those that use it. In that later case, there is the even more subtle distinction of those that use the feature for their own code, and those that use it in libraries they make available.
The later case is issue: It seems a real mess if a library author who wanted to use the new feature, had to circumvent a HP library because it didn't annotate. Similar thought experiment: What would be the downside if containers didn't annotate? Would that just make the feature unusable because everything uses containers?
To put it more directly: with the satus-quo default of representations, what is the down side if a library, a widely used library, doesn't bother to annotate? What would be the loss if containers didn't annotate? (I know it did, this is the thought experiment... because I've got 30+ libraries in HP that are in this boat.)
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 As someone completely oblivious on this development in Haskell until now, but researching myself in the same direction (on the distinction of computational, irrelevant, and parametric arguments in Agda), I am allowing myself some comments on the process, and the syntax discussion given in the paper http://www.cis.upenn.edu/~eir/papers/2014/coercible/coercible-ext.pdf 1. The alternative of using a pragma as syntax is dismissed with the argument: "We felt that, in several years, we would regret this decision. Backwards-compatibility would no longer be an issue, and we would be stuck with a pragma syntax for a core language feature." I strongly disagree. One can introduce a pragma syntax first, for smooth backward compatibility, and after the feature has passed the test of time, still introduce a proper, "first-class" syntax. If role annotations become standard, introduction of a proper syntax instead of ugly pragmas will be received with applause, unlike now, where you burden ugly CPP-ifs onto the library developers. You could do for now with a pragma-like declaration {-# TYPEROLE identifier role ... role #-} or {-# TYPE_ROLE identifier role ... role #-} instead of the declaration type role identifier role ... role 2. The chosen role names mean nothing to me. It feels a bit like the term "delegate" used in C# instead of just speaking of a higher-order function. Looking at the semantics, I find the following translation nominal = computational That is, the choice of type expression has a computational effect (like a different implementation of Ord). representational = parametric The choice of type expression is parametric, i.e., does not lead to other choices, but is purely propagated through. Further, "representational" is a bit long for a keyword. 'nominal' invokes the exact opposite association for me than it means. In nominal calculi (Pitts et al), everything is *parametric* in the choice of names. For introducing a non-backwards compatible language feature, this process feels rushed, imho. You might wanna pull the break before the release. Cheers, Andreas On 25.03.2014 04:26, Richard Eisenberg wrote:
I have a few responses to various themes in this thread, but nothing terribly unexpected:
- The introduction of roles is the end of the story that began with the discovery of bug #1496. The alternative would be to do away with GND. `coerce` is just a convenient application of roles, not the reason they were introduced.
- The concrete syntax for role ascriptions was debated in public, in bug #8185. There is further discussion of the design choice in the appendix of the extended version of our recent draft paper on the subject: www.cis.upenn.edu/~eir/papers/2014/coercible/coercible-ext.pdf http://www.cis.upenn.edu/~eir/papers/2014/coercible/coercible-ext.pdf
I'm afraid it's too late now to make changes. I don't love what we
ended up with, but I believe it's the best syntax that was proposed.
- I agree with Simon that `coerce` is quite a bit safer than `unsafeCoerce`. Under the assumption that all libraries are written correctly (that is, with proper role annotations), `coerce` is in fact fully safe.
- I surely recognize why and how this causes a Major Pain for Mark, and for other library maintainers. I wish there were an easier solution. However, I will perhaps repeat others in saying that a library that doesn't add role annotations is no more wrong in 7.8 than it was since GND was introduced. The only difference with 7.8 is that, now, there is a way to be right.
Richard
On Mar 24, 2014, at 9:32 PM, Edward A Kmett wrote:
Fair enough. I did try to convey that in the following sentence about how it at least enforces representational equality, but I can see how my statement might be taken as understating the importance of that property.
Sent from my iPhone
On Mar 24, 2014, at 6:57 PM, Simon Peyton Jones
mailto:simonpj@microsoft.com> wrote: In that light, `coerce` then can be viewed as a more friendly but still evil version of unsafeCoerce
Coerce embodies one rather compelling improvement: *it is type-sound.* unsafeCoerce can cause arbitrary seg-faults etc. ‘coerce’ cannot. Call me an old-fashioned “well-typed programs don’t go wrong” man, but I think that’s a big plus. Much more than “an occasional situation improvement”.
Granted, “type-sound” doesn’t guarantee “correct”, but then it never did.
The role machinery doesn’t exactly hoist us on a dilemma – it merely exposes the dilemma that was there all the time.
Simon
*From:*Edward Kmett [mailto:ekmett@gmail.com] *Sent:* 24 March 2014 19:11 *To:* Mark Lentczner *Cc:* Simon Peyton Jones; libraries@haskell.org mailto:libraries@haskell.org Libraries; ghc-devs@haskell.org mailto:ghc-devs@haskell.org *Subject:* Re: We need to add role annotations for 7.8
Mark,
We're currently planning to retain the existing behavior of GeneralizedNewtypeDeriving with regards to Safe Haskell. That is, Safe Haskell and GND still won't mix in 7.8 due to these same security concerns.
I think a key observation with regards to GeneralizedNewtypeDeriving is with representational roles as default the new roles machinery with the representational default lets you write nothing you couldn't write before. No new security vulnerabilities are introduced. They were there all along!
We're also disabling the Safe flag on Data.Coerce. In that light, `coerce` then can be viewed as a more friendly but still evil version of unsafeCoerce. It lets you write nothing you couldn't write before with `unsafeCoerce`. I view it as merely an occasional situational improvement over the existing unsafeCoerce in that it at least enforces representational equality.
Making the default role annotation nominal comes at a very very real cost. Namely, *all* of generalized newtype deriving anywhere breaks, and everyone forever will have to put annotations in to fix it.
The 'backwards' representational default puts the burden on a small minority of library authors.
I'm not a huge fan of the representational machinery, in that it hoists us upon this dilemma, but given the choice between everyone paying in perpetuity and a small minority of skilled library authors adding a handful of annotations that for the most part have already been added, and which expose them to no more risk than they'd had before if they forget, I'm definitely in favor of the current solution.
-Edward
On Mon, Mar 24, 2014 at 11:26 AM, Mark Lentczner
mailto:mark.lentczner@gmail.com> wrote: Thanks for the pointers, Simon. I appologize for coming to this quite so late... I didn't realize the global impact of this feature.
From a "meaning" perspective, I'm agnostic on the default.
From a "engineering" perspective, I want a default that "does a good enough, reasonably safe thing" if programmers ignore the feature.
The later is subtle as there are different vantage points for different developers. In the Platform, we have many libraries that we are encouraging both end-programmers, and other library authors to make use of and depend on extensively. This means those libraries have to work for both programmers that are ignoring the feature, and those that use it. In that later case, there is the even more subtle distinction of those that use the feature for their own code, and those that use it in libraries they make available.
The later case is issue: It seems a real mess if a library author who wanted to use the new feature, had to circumvent a HP library because it didn't annotate. Similar thought experiment: What would be the downside if containers didn't annotate? Would that just make the feature unusable because everything uses containers?
To put it more directly: with the satus-quo default of representations, what is the down side if a library, a widely used library, doesn't bother to annotate? What would be the loss if containers didn't annotate? (I know it did, this is the thought experiment... because I've got 30+ libraries in HP that are in this boat.)
_______________________________________________ Libraries mailing list Libraries@haskell.org mailto:Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org mailto:Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
- -- Andreas Abel <>< Du bist der geliebte Mensch. Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden andreas.abel@gu.se http://www2.tcs.ifi.lmu.de/~abel/ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iEYEARECAAYFAlMxPkkACgkQPMHaDxpUpLNc6QCeLSqyQE/huMc0cBMIL4oJbLQ1 pOgAn3cW4YmP2hrQoMwMtRcmJ6t6jML3 =DnVb -----END PGP SIGNATURE-----

On 2014-03-25 at 09:28:57 +0100, Andreas Abel wrote: [...]
You might wanna pull the break before the release.
Fwiw, reverting the new syntax at this point also has an effect on already officially released libraries such as http://hackage.haskell.org/package/containers-0.5.5.1 which started using the new non-pragma annotation[1]; so this would require new hackage uploads (and maybe hackage-deprecations)... just saying... [1]: http://hdiff.luite.com/cgit/containers/commit?id=0.5.5.0

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 25.03.2014 10:56, Herbert Valerio Riedel wrote:
On 2014-03-25 at 09:28:57 +0100, Andreas Abel wrote:
You might wanna pull the break before the release.
Fwiw, reverting the new syntax at this point also has an effect on already officially released libraries such as http://hackage.haskell.org/package/containers-0.5.5.1 which started using the new non-pragma annotation[1]; so this would require new hackage uploads (and maybe hackage-deprecations)... just saying...
[1]: http://hdiff.luite.com/cgit/containers/commit?id=0.5.5.0
Probably it is too late to row back. Even a pragma syntax {-# TYPE_ROLE id role ... role #-} generates a warning on older ghcs: file:1:1: Warning: Unrecognised pragma So that is not a fully smooth alternative to a new syntax---it also has an effect on old instances of the compiler. Though it is only a warning, which can be ignored like a deprecation warning. - -- Andreas Abel <>< Du bist der geliebte Mensch. Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden andreas.abel@gu.se http://www2.tcs.ifi.lmu.de/~abel/ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iEYEARECAAYFAlMxZd8ACgkQPMHaDxpUpLNoQQCg2JWsVkskUfGS4WiSE9zycXrH rqMAnjJ5lg2UgFaYRiWmu9y6SqUs2e2E =jT79 -----END PGP SIGNATURE-----

Thank you to everyone who has been helping me understand this issue in greater depth. *tl;dr: As long as we don't expect any libraries beyond to core to annotate, I'm cool. This presumes that the extra safety isn't, in practice, dependent on transitive adoption by libraries. It also implies that representational is the only possible default, and that there can be no migration from it.* My approach to thinking about this is guided by thinking about supporting an eco-system with 1000s of libraries (hackage), a few dozen of which are heavily promoted (the platform), and a small set that are closely tied to the compiler (the core). The availability, speed of release, motivation, and even skill of the the developers varies widely over that range. I also think about the various "stances" of different developers: - *End developer*: makes use of libraries, but just builds apps - *Internal developer*: makes libraries for internal use in a project - *Casual library writer*: makes libraries, primarily for their own needs, but distributed on hackage - *Popular library writer:* actively maintains libraries which are widely used - *Core library writer: *maintainer of a core package that stays in lock step with the compiler Then, I think about, for each of these, what is the effect on a new feature on them, their existing code, and future code? Does it affect them only if they are using the feature? If they aren't using the feature? For library writers, how does the feature affect clients? If a client wants to use a feature, under what conditions does the library need to do something? This last issue of the "transitivity" the feature is often the biggest concern. *Given that... onto type roles:* The default of *representational* is the only option, because a default of *nominal* would require far too many developers to have to update their code. I don't believe that we can ever migrate to *nominal* as default. The feature implies that any abstract data type that uses a type parameter in certain ways needs annotate to get the full safety afforded now afforded. However, without annotation, the data type is still no worse off than it was before (there is added safety, but not perhaps relevant to the stand point of the library writer). Further, this (pre-existing) non-safety isn't likely a huge concern. Making sure the docs take the tone that most developers need to nothing, and when developers need to be concerned seems like an important way to ensure the right outcome. A key question here is transitivity: Is it possible for module A to not annotate a type, and then have module B by a different author use the type in A in another abstract type, that *is* annotated, and get the benefit. Seems the answer is "partially". If the answer were "no", then use of the feature would be dependent on transitive adoption, and that is where the big burden on developers comes from. The degree to which we believe this "partially" is important: If we are willing to believe that the only library writers we care about doing this are those in the core, then fine. In this case we shouldn't feel compelled to suggest to library writers that they annotate, ever. I'm good with this. If the team here thinks otherwise, that we need to start a campaign to get every library writer to eventually annotate, then I have deep objections. I read the paper, and understand how the authors felt the syntax options were all less than perfect, and choose what they did. But that choice, perhaps unwittingly, the implication that it forces -XCPP on all libraries except perhaps some of the core. This is because they all need to support previous compilers. So, a one line annotation has turned into an ugly beast, and perhaps added -XCPP where there was none, which is really unfortunate. (I, like many, consider it a defeat when one has to resort to -XCPP.) It seems to me that the paper didn't really consider less-perfect, heuristic solutions. It might have had significantly less impact on library writers were some heuristic (no constructors exported? has any type constraint on the parameter? etc..) might have allowed most data types to go without annotation at the cost of a few (where *nominal* was incorrectly inferred) requiring immediate action. In this situation, a non-language feature (pragma or other device) might have been more palatable. Finally, on the choice of terms, *nominal*, *representational*, and *phantom* all seem like clear, self-explanatory choices to me. - Mark

The degree to which we believe this "partially" is important: If we are willing to believe that the only library writers we care about doing this are those in the core, then fine. In this case we shouldn't feel compelled to suggest to library writers that they annotate, ever. I'm good with this. If the team here thinks otherwise, that we need to start a campaign to get every library writer to eventually annotate, then I have deep objections. The situation today is that · A client of a library can use GND to do bad things to the library (e.g. change the “key” type of (Map key value)). · Role annotations allow the library author to prevent that happening. Would you say that means that we are “compelled to suggest to library writers that they annotate”? I would have thought that it would indeed be good to suggest to them that a new opportunity exists for them to make their library more robust to clients. They are free to do nothing, or to take advantage of the suggestion. It’s an upside-only situation. Looking further ahead, when you say that “there can be no migration from representational-by-default”, do you have data to support that? Notably, any client not using GND could not observe a change. So simply seeing how many library modules use GND would be an upper bound on how many libraries would fail to compile you were to ask us to change the default. Is that 1% of Hackage modules? 10%? 0.1%? I don’t know. The awkward bit is that if a client is using GND, which fails after a change to nominal-by-default, the fix is to change the library, not the client, and I can see that is awkward. Simon From: Libraries [mailto:libraries-bounces@haskell.org] On Behalf Of Mark Lentczner Sent: 25 March 2014 15:10 To: libraries@haskell.org Libraries; ghc-devs@haskell.org Subject: Re: We need to add role annotations for 7.8 Thank you to everyone who has been helping me understand this issue in greater depth. tl;dr: As long as we don't expect any libraries beyond to core to annotate, I'm cool. This presumes that the extra safety isn't, in practice, dependent on transitive adoption by libraries. It also implies that representational is the only possible default, and that there can be no migration from it. My approach to thinking about this is guided by thinking about supporting an eco-system with 1000s of libraries (hackage), a few dozen of which are heavily promoted (the platform), and a small set that are closely tied to the compiler (the core). The availability, speed of release, motivation, and even skill of the the developers varies widely over that range. I also think about the various "stances" of different developers: * End developer: makes use of libraries, but just builds apps * Internal developer: makes libraries for internal use in a project * Casual library writer: makes libraries, primarily for their own needs, but distributed on hackage * Popular library writer: actively maintains libraries which are widely used * Core library writer: maintainer of a core package that stays in lock step with the compiler Then, I think about, for each of these, what is the effect on a new feature on them, their existing code, and future code? Does it affect them only if they are using the feature? If they aren't using the feature? For library writers, how does the feature affect clients? If a client wants to use a feature, under what conditions does the library need to do something? This last issue of the "transitivity" the feature is often the biggest concern. Given that... onto type roles: The default of representational is the only option, because a default of nominal would require far too many developers to have to update their code. I don't believe that we can ever migrate to nominal as default. The feature implies that any abstract data type that uses a type parameter in certain ways needs annotate to get the full safety afforded now afforded. However, without annotation, the data type is still no worse off than it was before (there is added safety, but not perhaps relevant to the stand point of the library writer). Further, this (pre-existing) non-safety isn't likely a huge concern. Making sure the docs take the tone that most developers need to nothing, and when developers need to be concerned seems like an important way to ensure the right outcome. A key question here is transitivity: Is it possible for module A to not annotate a type, and then have module B by a different author use the type in A in another abstract type, that is annotated, and get the benefit. Seems the answer is "partially". If the answer were "no", then use of the feature would be dependent on transitive adoption, and that is where the big burden on developers comes from. The degree to which we believe this "partially" is important: If we are willing to believe that the only library writers we care about doing this are those in the core, then fine. In this case we shouldn't feel compelled to suggest to library writers that they annotate, ever. I'm good with this. If the team here thinks otherwise, that we need to start a campaign to get every library writer to eventually annotate, then I have deep objections. I read the paper, and understand how the authors felt the syntax options were all less than perfect, and choose what they did. But that choice, perhaps unwittingly, the implication that it forces -XCPP on all libraries except perhaps some of the core. This is because they all need to support previous compilers. So, a one line annotation has turned into an ugly beast, and perhaps added -XCPP where there was none, which is really unfortunate. (I, like many, consider it a defeat when one has to resort to -XCPP.) It seems to me that the paper didn't really consider less-perfect, heuristic solutions. It might have had significantly less impact on library writers were some heuristic (no constructors exported? has any type constraint on the parameter? etc..) might have allowed most data types to go without annotation at the cost of a few (where nominal was incorrectly inferred) requiring immediate action. In this situation, a non-language feature (pragma or other device) might have been more palatable. Finally, on the choice of terms, nominal, representational, and phantom all seem like clear, self-explanatory choices to me. - Mark

*Apologies*
On Tue, Mar 25, 2014 at 8:47 AM, Simon Peyton Jones
The situation today is that · A client of a library can use GND to do bad things to the library (e.g. change the “key” type of (Map key value)). · Role annotations allow the library author to prevent that happening. Would you say that means that we are “compelled to suggest to library writers that they annotate”?
Well... I don't think we should. The reason is that this situation is very sad for it puts the burden upon the library writer, for potential abuse of an extension to Haskell she might not even be aware of! She writes a perfectly safe, reasonable abstracted type, and bam, now has to worry about a very hard to understand situation involving the interaction to two separate Haskell extensions. And furthermore, adding that protection requires yet a third (CPP), and makes the "protection" often as long as the abstract type itself. Looking further ahead, when you say that “there can be no migration from
representational-by-default”, do you have data to support that? Notably, any client not using GND could not observe a change. So simply seeing how many library modules use GND would be an upper bound on how many libraries would fail to compile you were to ask us to change the default. Is that 1% of Hackage modules? 10%? 0.1%? I don’t know.
You are wrong that use of GND is the upper bound: The burden is on the type
author, not the GND user. And so, while only a small percent of Hackage
uses GND (though I note that more and more literature promotes GND (very
handy in Shake, for example)...) in order to keep them from breaking, a
potentially much larger percentage of Hackage has to get fixed.
What's more, the ability to remedy the situation is in the wrong place: If
the default changes, and my GND library breaks, all my users are broken,
and worse, I can't do anything about it until I compel the libraries I
depend on to annotate.
This is why we can't ever change the default.
On Tue, Mar 25, 2014 at 4:23 PM, Richard Eisenberg
The problem is, in the actual datatype definition, the constraints tend not to appear? Should we look around for other functions with constraints?
Right - we've been advocating removing them for years, and only placing the
constraints on the functions that need them, since they really present no
constraint on the data type itself. Of course, the presence of GND and
roles means that they now *would be* saying something about the type - as
they are indicating that the integrity of the type requires the constraint.
So yes, a shift to using this as the marker for nominal would require a
change in developer habit. But so does annotation.
I agree that other heuristics are pretty fragile: names of modules,
presence of constraints in functions, and even status of constructor export
are all a) far too removed from the code site in question, and b) things
that are much more fluid during development. I would be against any of
these.
On Wed, Mar 26, 2014 at 8:46 PM, Edward Kmett
Personally, looking at it 10 years on, having a nominal default would look pretty terrible to me. I'd be stuck annotating everything I write. Nothing easy could just be easy.
Agree whole-heartedly.
Worth reiterating: Easy things should not need annotation.
On Wed, Mar 26, 2014 at 11:44 PM, Ganesh Sittampalam
I think that in theory the basic principle should be that by default you can only write a GND if you could have written it by hand in the same scope - i.e. you can only do it if you have access to the relevant methods and datatype constructors etc
This is much closer to the approach I wish had been taken: The burden is on the correct party. The client of the lib, wishing to use it in a new way, unbeknownst to the library author. I don't know enough about the type theory, but could we have disallowed GND in the presence of type families anywhere in the class being derived?

The first line was supposed to say: *Apologies for the delayed and multi-message response.*

Am 28.03.2014 17:17, schrieb Mark Lentczner:
/Apologies/ On Tue, Mar 25, 2014 at 8:47 AM, Simon Peyton Jones
mailto:simonpj@microsoft.com> wrote: The situation today is that · A client of a library can use GND to do bad things to the library (e.g. change the “key” type of (Map key value)). · Role annotations allow the library author to prevent that happening. Would you say that means that we are “compelled to suggest to library writers that they annotate”?
Well... I don't think we should.
The reason is that this situation is very sad for it puts the burden upon the library writer, for potential abuse of an extension to Haskell she might not even be aware of! She writes a perfectly safe, reasonable abstracted type, and bam, now has to worry about a very hard to understand situation involving the interaction to two separate Haskell extensions. And furthermore, adding that protection requires yet a third (CPP), and makes the "protection" often as long as the abstract type itself.
Well put! Before GHC-7.8 release candidates appeared I already thought about removing all GeneralizedNewtypeDerivings from my packages in order to earn the Safe-Haskell seal. Now GHC-7.8 refuses to derive some of the instances that former GHC versions automatically derived. As far as I understand I can use role annotation to let the generation of even more Newtype instances fail, but I cannot persuade GHC to generate more instance using role annoations, right? That is, I have to write these instances manually in any case. That is, up to now, GeneralizedNewtypeDeriving was Unsafe and it seems it becomes Safe with the new role inference. Is this right? However, it is still possible to generate instances that I could not generate manually, as demonstrated in the Data.Map example. Would it solve the problem to respect type roles only if Safe Haskell is enabled and ignore them otherwise? Then all existing code could be compiled unchanged but you can make use of the increased safety of roles by enabling Safe Haskell.

I think a few clarifications might help: - Roles, as originally conceived, were not an attempt to make Unsafe code Safe. Instead, they make unsafe things safe. Before roles, it was quite possible to write Haskell code that would cause a seg fault at runtime. Now, this is (short of unsafeCoerce & friends) impossible, as far as we know. This is independent of any concern with Safe Haskell. That is why certain code that used to work with GND can no longer do so, and why there is no easy fix -- the old code is unsafe, not just Unsafe. - Role annotations are never necessary to ensure type safety. To reiterate: all Haskell code, with or without type annotations, is now safe from the interaction between GND and TypeFamilies. - The whole debate here is about *abstraction* -- whether or not a user outside of a library can fiddle with that library's expected invariants. - Edward and Mark have said that with a default of a nominal role "Nothing easy could just be easy." Yet, we accept the need for deriving Eq and Show without question. I think, if we ignore its current alienness, a role annotation is on a similar order -- a role annotation (in a world with a nominal default) would be granting new capabilities to users of a type, just like adding instances of classes. - If you could use GND only where the constructors are available, then some valid current use of GND would break, I believe. It would mean that GND would be unable to coerce a (Map String Int) to a (Map String Age), because the constructor of Set is (rightly) not exported. This would have a direct runtime significance for some users -- their code would run slower. Richard On Mar 28, 2014, at 12:17 PM, Mark Lentczner wrote:
Apologies On Tue, Mar 25, 2014 at 8:47 AM, Simon Peyton Jones
wrote: The situation today is that · A client of a library can use GND to do bad things to the library (e.g. change the “key” type of (Map key value)). · Role annotations allow the library author to prevent that happening. Would you say that means that we are “compelled to suggest to library writers that they annotate”? Well... I don't think we should.
The reason is that this situation is very sad for it puts the burden upon the library writer, for potential abuse of an extension to Haskell she might not even be aware of! She writes a perfectly safe, reasonable abstracted type, and bam, now has to worry about a very hard to understand situation involving the interaction to two separate Haskell extensions. And furthermore, adding that protection requires yet a third (CPP), and makes the "protection" often as long as the abstract type itself.
Looking further ahead, when you say that “there can be no migration from representational-by-default”, do you have data to support that? Notably, any client not using GND could not observe a change. So simply seeing how many library modules use GND would be an upper bound on how many libraries would fail to compile you were to ask us to change the default. Is that 1% of Hackage modules? 10%? 0.1%? I don’t know.
You are wrong that use of GND is the upper bound: The burden is on the type author, not the GND user. And so, while only a small percent of Hackage uses GND (though I note that more and more literature promotes GND (very handy in Shake, for example)...) in order to keep them from breaking, a potentially much larger percentage of Hackage has to get fixed.
What's more, the ability to remedy the situation is in the wrong place: If the default changes, and my GND library breaks, all my users are broken, and worse, I can't do anything about it until I compel the libraries I depend on to annotate.
This is why we can't ever change the default.
On Tue, Mar 25, 2014 at 4:23 PM, Richard Eisenberg
wrote: The problem is, in the actual datatype definition, the constraints tend not to appear? Should we look around for other functions with constraints? Right - we've been advocating removing them for years, and only placing the constraints on the functions that need them, since they really present no constraint on the data type itself. Of course, the presence of GND and roles means that they now would be saying something about the type - as they are indicating that the integrity of the type requires the constraint. So yes, a shift to using this as the marker for nominal would require a change in developer habit. But so does annotation.
I agree that other heuristics are pretty fragile: names of modules, presence of constraints in functions, and even status of constructor export are all a) far too removed from the code site in question, and b) things that are much more fluid during development. I would be against any of these.
On Wed, Mar 26, 2014 at 8:46 PM, Edward Kmett
wrote: Personally, looking at it 10 years on, having a nominal default would look pretty terrible to me. I'd be stuck annotating everything I write. Nothing easy could just be easy. Agree whole-heartedly. Worth reiterating: Easy things should not need annotation.
On Wed, Mar 26, 2014 at 11:44 PM, Ganesh Sittampalam
wrote: I think that in theory the basic principle should be that by default you can only write a GND if you could have written it by hand in the same scope - i.e. you can only do it if you have access to the relevant methods and datatype constructors etc This is much closer to the approach I wish had been taken: The burden is on the correct party. The client of the lib, wishing to use it in a new way, unbeknownst to the library author. I don't know enough about the type theory, but could we have disallowed GND in the presence of type families anywhere in the class being derived?
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Fri, Mar 28, 2014 at 3:56 PM, Richard Eisenberg
- Edward and Mark have said that with a default of a nominal role "Nothing easy could just be easy." Yet, we accept the need for deriving Eq and Show without question. I think, if we ignore its current alienness, a role annotation is on a similar order -- a role annotation (in a world with a nominal default) would be granting new capabilities to users of a type, just like adding instances of classes.
Well, "deriving (Eq, Show)" is a bit less wordy than "type role Foo representational representational". Although I guess you could just do "type role Foo _ _ _". On the other hand, telling people to add "type role Map nominal _" where it matters is analogous to telling them to have an explicit export list when they want to hide a type's constructors.
- If you could use GND only where the constructors are available, then some valid current use of GND would break, I believe. It would mean that GND would be unable to coerce a (Map String Int) to a (Map String Age), because the constructor of Set is (rightly) not exported. This would have a direct runtime significance for some users -- their code would run slower.
One might attempt a compromise:
- types with explicit annotations always have the specified roles
- types with no explicit annotations but visible constructors have the
inferred roles
- types with no explicit annotations and no visible constructors have
nominal roles
--
Dave Menendez

On Fri, Mar 28, 2014 at 4:27 PM, David Menendez
Well, "deriving (Eq, Show)" is a bit less wordy than "type role Foo representational representational". Although I guess you could just do "type role Foo _ _ _".
You forgot some stuff. #ifdef __GLASGOW_HASKELL__ #if __GLASGOW_HASKELL__ >= 708 && __GLASGOW_HASKELL__ < ??? type role Foo representational nominal representational #elif __GLASGOW_HASKELL >= ??? -- insert whatever the future solution is to actually -- handle higher-order types; it will, without question, -- be different from the above role annotation. #endif #endif data Foo f x y = Foo (f x) y deriving (Eq, Ord, Show, Read) Please add that to every type definition in your code. :) -- Dan

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

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
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@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs

Am 31.03.2014 08:51, schrieb Dominique Devriese:
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
That's very similar to what I proposed with respect to SafeHaskell, i.e. GeneralizedNewtypeDeriving in an Unsafe module means backwards-compatible old GeneralizedNewtypeDeriving and GeneralizedNewtypeDeriving in a Safe module means SafeNewtypeDeriving.
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...
I think their main concern is not on the side of the user who wants to use GeneralizedNewtypeDeriving, but on the side of the library writer who has to take GeneralizedNewtypeDeriving into account, although it is an extension and his code would be perfectly safe without GeneralizedNewtypeDeriving. The first one is a problem only in the transition from GHC-7.6 to GHC-7.8, but the latter one is a permanent problem. But then again, the backward-compatible role annotations proposal seems to address yet another problem.

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
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
: 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@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

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
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
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
: 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@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

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
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
: 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
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
: 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@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Hi Mark, I appreciate your analysis in terms of classes of users -- I think that is helpful for framing the discussion. About transitivity: I think we're in the clear here. Let's say package A exports types missing role annotations. If package B imports package A and wants to have the full safety afforded by roles, that is no problem whatsoever. Package B has annotations on its types (which may use package A's types) that may restrict certain parameters to be nominal, as appropriate. If package A had role annotations, it's quite possible that package B could omit some annotations (as role inference propagates nominal roles), but there is no problem inherent in this. (Indeed, if package A adds annotations in the future, package B would have redundant, but harmless, annotations.) So, I disagree with Mark's "partially" below -- I think we're fully OK in this regard. About heuristics: we briefly considered some, though there's no documentation of this anywhere. Specifically, we thought about giving nominal roles to parameters used in class constraints. The problem is, in the actual datatype definition, the constraints tend not to appear? Should we look around for other functions with constraints? That seems likely to be more confusing than helpful. Furthermore, I strongly don't like the idea of using heuristics to infer a feature such as this -- it can cause strange behavior and is hard to specify. Richard On Mar 25, 2014, at 11:09 AM, Mark Lentczner wrote:
Thank you to everyone who has been helping me understand this issue in greater depth.
tl;dr: As long as we don't expect any libraries beyond to core to annotate, I'm cool. This presumes that the extra safety isn't, in practice, dependent on transitive adoption by libraries. It also implies that representational is the only possible default, and that there can be no migration from it.
My approach to thinking about this is guided by thinking about supporting an eco-system with 1000s of libraries (hackage), a few dozen of which are heavily promoted (the platform), and a small set that are closely tied to the compiler (the core). The availability, speed of release, motivation, and even skill of the the developers varies widely over that range.
I also think about the various "stances" of different developers: End developer: makes use of libraries, but just builds apps Internal developer: makes libraries for internal use in a project Casual library writer: makes libraries, primarily for their own needs, but distributed on hackage Popular library writer: actively maintains libraries which are widely used Core library writer: maintainer of a core package that stays in lock step with the compiler Then, I think about, for each of these, what is the effect on a new feature on them, their existing code, and future code? Does it affect them only if they are using the feature? If they aren't using the feature? For library writers, how does the feature affect clients? If a client wants to use a feature, under what conditions does the library need to do something? This last issue of the "transitivity" the feature is often the biggest concern.
Given that... onto type roles:
The default of representational is the only option, because a default of nominal would require far too many developers to have to update their code. I don't believe that we can ever migrate to nominal as default.
The feature implies that any abstract data type that uses a type parameter in certain ways needs annotate to get the full safety afforded now afforded. However, without annotation, the data type is still no worse off than it was before (there is added safety, but not perhaps relevant to the stand point of the library writer). Further, this (pre-existing) non-safety isn't likely a huge concern. Making sure the docs take the tone that most developers need to nothing, and when developers need to be concerned seems like an important way to ensure the right outcome.
A key question here is transitivity: Is it possible for module A to not annotate a type, and then have module B by a different author use the type in A in another abstract type, that is annotated, and get the benefit. Seems the answer is "partially". If the answer were "no", then use of the feature would be dependent on transitive adoption, and that is where the big burden on developers comes from.
The degree to which we believe this "partially" is important: If we are willing to believe that the only library writers we care about doing this are those in the core, then fine. In this case we shouldn't feel compelled to suggest to library writers that they annotate, ever. I'm good with this. If the team here thinks otherwise, that we need to start a campaign to get every library writer to eventually annotate, then I have deep objections.
I read the paper, and understand how the authors felt the syntax options were all less than perfect, and choose what they did. But that choice, perhaps unwittingly, the implication that it forces -XCPP on all libraries except perhaps some of the core. This is because they all need to support previous compilers. So, a one line annotation has turned into an ugly beast, and perhaps added -XCPP where there was none, which is really unfortunate. (I, like many, consider it a defeat when one has to resort to -XCPP.)
It seems to me that the paper didn't really consider less-perfect, heuristic solutions. It might have had significantly less impact on library writers were some heuristic (no constructors exported? has any type constraint on the parameter? etc..) might have allowed most data types to go without annotation at the cost of a few (where nominal was incorrectly inferred) requiring immediate action. In this situation, a non-language feature (pragma or other device) might have been more palatable.
Finally, on the choice of terms, nominal, representational, and phantom all seem like clear, self-explanatory choices to me.
- Mark
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs

Were any rules considered along the lines of "Representational by
default if all the type's constructors are exported by a module not
named 'Internal', nominal by default otherwise"? Better would probably
include "exported by a module the package exposes" but that's
disgustingly non-local if it's even possible at all. The module name
thing is hacky to the extreme but at least it's a simple rule rather
than some obscure and opaque heuristics.
Anyway, the goal of something like that would be not so much "figure
out what it should be", since that's impossible, but more "default to
nominal if and only if there's clear indication the user is already
thinking about restricting how the type is used".
Not that I'm really even suggesting such a rule, just wondering if it
was discussed.
- C.
On Tue, Mar 25, 2014 at 7:23 PM, Richard Eisenberg
Hi Mark,
I appreciate your analysis in terms of classes of users -- I think that is helpful for framing the discussion.
About transitivity: I think we're in the clear here. Let's say package A exports types missing role annotations. If package B imports package A and wants to have the full safety afforded by roles, that is no problem whatsoever. Package B has annotations on its types (which may use package A's types) that may restrict certain parameters to be nominal, as appropriate. If package A had role annotations, it's quite possible that package B could omit some annotations (as role inference propagates nominal roles), but there is no problem inherent in this. (Indeed, if package A adds annotations in the future, package B would have redundant, but harmless, annotations.) So, I disagree with Mark's "partially" below -- I think we're fully OK in this regard.
About heuristics: we briefly considered some, though there's no documentation of this anywhere. Specifically, we thought about giving nominal roles to parameters used in class constraints. The problem is, in the actual datatype definition, the constraints tend not to appear? Should we look around for other functions with constraints? That seems likely to be more confusing than helpful. Furthermore, I strongly don't like the idea of using heuristics to infer a feature such as this -- it can cause strange behavior and is hard to specify.
Richard
On Mar 25, 2014, at 11:09 AM, Mark Lentczner wrote:
Thank you to everyone who has been helping me understand this issue in greater depth.
tl;dr: As long as we don't expect any libraries beyond to core to annotate, I'm cool. This presumes that the extra safety isn't, in practice, dependent on transitive adoption by libraries. It also implies that representational is the only possible default, and that there can be no migration from it.
My approach to thinking about this is guided by thinking about supporting an eco-system with 1000s of libraries (hackage), a few dozen of which are heavily promoted (the platform), and a small set that are closely tied to the compiler (the core). The availability, speed of release, motivation, and even skill of the the developers varies widely over that range.
I also think about the various "stances" of different developers:
End developer: makes use of libraries, but just builds apps Internal developer: makes libraries for internal use in a project Casual library writer: makes libraries, primarily for their own needs, but distributed on hackage Popular library writer: actively maintains libraries which are widely used Core library writer: maintainer of a core package that stays in lock step with the compiler
Then, I think about, for each of these, what is the effect on a new feature on them, their existing code, and future code? Does it affect them only if they are using the feature? If they aren't using the feature? For library writers, how does the feature affect clients? If a client wants to use a feature, under what conditions does the library need to do something? This last issue of the "transitivity" the feature is often the biggest concern.
Given that... onto type roles:
The default of representational is the only option, because a default of nominal would require far too many developers to have to update their code. I don't believe that we can ever migrate to nominal as default.
The feature implies that any abstract data type that uses a type parameter in certain ways needs annotate to get the full safety afforded now afforded. However, without annotation, the data type is still no worse off than it was before (there is added safety, but not perhaps relevant to the stand point of the library writer). Further, this (pre-existing) non-safety isn't likely a huge concern. Making sure the docs take the tone that most developers need to nothing, and when developers need to be concerned seems like an important way to ensure the right outcome.
A key question here is transitivity: Is it possible for module A to not annotate a type, and then have module B by a different author use the type in A in another abstract type, that is annotated, and get the benefit. Seems the answer is "partially". If the answer were "no", then use of the feature would be dependent on transitive adoption, and that is where the big burden on developers comes from.
The degree to which we believe this "partially" is important: If we are willing to believe that the only library writers we care about doing this are those in the core, then fine. In this case we shouldn't feel compelled to suggest to library writers that they annotate, ever. I'm good with this. If the team here thinks otherwise, that we need to start a campaign to get every library writer to eventually annotate, then I have deep objections.
I read the paper, and understand how the authors felt the syntax options were all less than perfect, and choose what they did. But that choice, perhaps unwittingly, the implication that it forces -XCPP on all libraries except perhaps some of the core. This is because they all need to support previous compilers. So, a one line annotation has turned into an ugly beast, and perhaps added -XCPP where there was none, which is really unfortunate. (I, like many, consider it a defeat when one has to resort to -XCPP.)
It seems to me that the paper didn't really consider less-perfect, heuristic solutions. It might have had significantly less impact on library writers were some heuristic (no constructors exported? has any type constraint on the parameter? etc..) might have allowed most data types to go without annotation at the cost of a few (where nominal was incorrectly inferred) requiring immediate action. In this situation, a non-language feature (pragma or other device) might have been more palatable.
Finally, on the choice of terms, nominal, representational, and phantom all seem like clear, self-explanatory choices to me.
- Mark
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

I think something like that is on the table, at least for a future ghc
release. I'm not sure if it made it into the patches for 7.8.1. But this
was actually suggested on the relevant ticket last week. (I'm Afk otherwise
id dig up the link)
On Wednesday, March 26, 2014, Casey McCann
Were any rules considered along the lines of "Representational by default if all the type's constructors are exported by a module not named 'Internal', nominal by default otherwise"? Better would probably include "exported by a module the package exposes" but that's disgustingly non-local if it's even possible at all. The module name thing is hacky to the extreme but at least it's a simple rule rather than some obscure and opaque heuristics.
Anyway, the goal of something like that would be not so much "figure out what it should be", since that's impossible, but more "default to nominal if and only if there's clear indication the user is already thinking about restricting how the type is used".
Not that I'm really even suggesting such a rule, just wondering if it was discussed.
- C.
Hi Mark,
I appreciate your analysis in terms of classes of users -- I think that is helpful for framing the discussion.
About transitivity: I think we're in the clear here. Let's say package A exports types missing role annotations. If package B imports package A and wants to have the full safety afforded by roles, that is no problem whatsoever. Package B has annotations on its types (which may use package A's types) that may restrict certain parameters to be nominal, as appropriate. If package A had role annotations, it's quite possible that package B could omit some annotations (as role inference propagates nominal roles), but there is no problem inherent in this. (Indeed, if package A adds annotations in the future, package B would have redundant, but harmless, annotations.) So, I disagree with Mark's "partially" below -- I think we're fully OK in this regard.
About heuristics: we briefly considered some, though there's no documentation of this anywhere. Specifically, we thought about giving nominal roles to parameters used in class constraints. The problem is, in the actual datatype definition, the constraints tend not to appear? Should we look around for other functions with constraints? That seems likely to be more confusing than helpful. Furthermore, I strongly don't like the idea of using heuristics to infer a feature such as this -- it can cause strange behavior and is hard to specify.
Richard
On Mar 25, 2014, at 11:09 AM, Mark Lentczner wrote:
Thank you to everyone who has been helping me understand this issue in greater depth.
tl;dr: As long as we don't expect any libraries beyond to core to annotate, I'm cool. This presumes that the extra safety isn't, in practice, dependent on transitive adoption by libraries. It also implies that representational is the only possible default, and that there can be no migration from it.
My approach to thinking about this is guided by thinking about supporting an eco-system with 1000s of libraries (hackage), a few dozen of which are heavily promoted (the platform), and a small set that are closely tied to the compiler (the core). The availability, speed of release, motivation, and even skill of the the developers varies widely over that range.
I also think about the various "stances" of different developers:
End developer: makes use of libraries, but just builds apps Internal developer: makes libraries for internal use in a project Casual library writer: makes libraries, primarily for their own needs, but distributed on hackage Popular library writer: actively maintains libraries which are widely used Core library writer: maintainer of a core package that stays in lock step with the compiler
Then, I think about, for each of these, what is the effect on a new feature on them, their existing code, and future code? Does it affect them only if they are using the feature? If they aren't using the feature? For library writers, how does the feature affect clients? If a client wants to use a feature, under what conditions does the library need to do something? This last issue of the "transitivity" the feature is often the biggest concern.
Given that... onto type roles:
The default of representational is the only option, because a default of nominal would require far too many developers to have to update their code. I don't believe that we can ever migrate to nominal as default.
The feature implies that any abstract data type that uses a type
in certain ways needs annotate to get the full safety afforded now afforded. However, without annotation, the data type is still no worse off than it was before (there is added safety, but not perhaps relevant to the stand
of the library writer). Further, this (pre-existing) non-safety isn't
On Tue, Mar 25, 2014 at 7:23 PM, Richard Eisenberg
wrote: parameter point likely a huge concern. Making sure the docs take the tone that most developers need to nothing, and when developers need to be concerned seems like an important way to ensure the right outcome.
A key question here is transitivity: Is it possible for module A to not annotate a type, and then have module B b>
Libraries mailing list Libraries@haskell.org javascript:; http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org javascript:; http://www.haskell.org/mailman/listinfo/libraries

Not for more than a passing mention. Using the name of the module to control the default makes me unhappy (should choice of name be relevant in the correctness / interpretation of a program?). Other heuristics (presence of constrained functions) seem quite fragile. Of everything said so far, I think the closest suggestion is to use constrained datatypes (like `data Ord a => Set a = ...`), but that mis-appropriates datatype contexts (which are silly) into something new and different, and so I personally don't think it's really viable.
Following Mark's idea of breaking this problem up into more manageable chunks, I would want us to think about two separate (and conflicting, often) users:
1. Users of today's Haskell who have to update their code.
2. Users of Haskell in 10 years.
Would users in group (2) like these heuristics? I doubt it. I think users in group (2) would probably most like a default of nominal with role annotations (in some concrete syntax). But, users in group (1) would hate a nominal default, so we have a compromise.
Richard
On Mar 26, 2014, at 11:40 AM, Casey McCann
Were any rules considered along the lines of "Representational by default if all the type's constructors are exported by a module not named 'Internal', nominal by default otherwise"? Better would probably include "exported by a module the package exposes" but that's disgustingly non-local if it's even possible at all. The module name thing is hacky to the extreme but at least it's a simple rule rather than some obscure and opaque heuristics.
Anyway, the goal of something like that would be not so much "figure out what it should be", since that's impossible, but more "default to nominal if and only if there's clear indication the user is already thinking about restricting how the type is used".
Not that I'm really even suggesting such a rule, just wondering if it was discussed.
- C.
On Tue, Mar 25, 2014 at 7:23 PM, Richard Eisenberg
wrote: Hi Mark,
I appreciate your analysis in terms of classes of users -- I think that is helpful for framing the discussion.
About transitivity: I think we're in the clear here. Let's say package A exports types missing role annotations. If package B imports package A and wants to have the full safety afforded by roles, that is no problem whatsoever. Package B has annotations on its types (which may use package A's types) that may restrict certain parameters to be nominal, as appropriate. If package A had role annotations, it's quite possible that package B could omit some annotations (as role inference propagates nominal roles), but there is no problem inherent in this. (Indeed, if package A adds annotations in the future, package B would have redundant, but harmless, annotations.) So, I disagree with Mark's "partially" below -- I think we're fully OK in this regard.
About heuristics: we briefly considered some, though there's no documentation of this anywhere. Specifically, we thought about giving nominal roles to parameters used in class constraints. The problem is, in the actual datatype definition, the constraints tend not to appear? Should we look around for other functions with constraints? That seems likely to be more confusing than helpful. Furthermore, I strongly don't like the idea of using heuristics to infer a feature such as this -- it can cause strange behavior and is hard to specify.
Richard
On Mar 25, 2014, at 11:09 AM, Mark Lentczner wrote:
Thank you to everyone who has been helping me understand this issue in greater depth.
tl;dr: As long as we don't expect any libraries beyond to core to annotate, I'm cool. This presumes that the extra safety isn't, in practice, dependent on transitive adoption by libraries. It also implies that representational is the only possible default, and that there can be no migration from it.
My approach to thinking about this is guided by thinking about supporting an eco-system with 1000s of libraries (hackage), a few dozen of which are heavily promoted (the platform), and a small set that are closely tied to the compiler (the core). The availability, speed of release, motivation, and even skill of the the developers varies widely over that range.
I also think about the various "stances" of different developers:
End developer: makes use of libraries, but just builds apps Internal developer: makes libraries for internal use in a project Casual library writer: makes libraries, primarily for their own needs, but distributed on hackage Popular library writer: actively maintains libraries which are widely used Core library writer: maintainer of a core package that stays in lock step with the compiler
Then, I think about, for each of these, what is the effect on a new feature on them, their existing code, and future code? Does it affect them only if they are using the feature? If they aren't using the feature? For library writers, how does the feature affect clients? If a client wants to use a feature, under what conditions does the library need to do something? This last issue of the "transitivity" the feature is often the biggest concern.
Given that... onto type roles:
The default of representational is the only option, because a default of nominal would require far too many developers to have to update their code. I don't believe that we can ever migrate to nominal as default.
The feature implies that any abstract data type that uses a type parameter in certain ways needs annotate to get the full safety afforded now afforded. However, without annotation, the data type is still no worse off than it was before (there is added safety, but not perhaps relevant to the stand point of the library writer). Further, this (pre-existing) non-safety isn't likely a huge concern. Making sure the docs take the tone that most developers need to nothing, and when developers need to be concerned seems like an important way to ensure the right outcome.
A key question here is transitivity: Is it possible for module A to not annotate a type, and then have module B by a different author use the type in A in another abstract type, that is annotated, and get the benefit. Seems the answer is "partially". If the answer were "no", then use of the feature would be dependent on transitive adoption, and that is where the big burden on developers comes from.
The degree to which we believe this "partially" is important: If we are willing to believe that the only library writers we care about doing this are those in the core, then fine. In this case we shouldn't feel compelled to suggest to library writers that they annotate, ever. I'm good with this. If the team here thinks otherwise, that we need to start a campaign to get every library writer to eventually annotate, then I have deep objections.
I read the paper, and understand how the authors felt the syntax options were all less than perfect, and choose what they did. But that choice, perhaps unwittingly, the implication that it forces -XCPP on all libraries except perhaps some of the core. This is because they all need to support previous compilers. So, a one line annotation has turned into an ugly beast, and perhaps added -XCPP where there was none, which is really unfortunate. (I, like many, consider it a defeat when one has to resort to -XCPP.)
It seems to me that the paper didn't really consider less-perfect, heuristic solutions. It might have had significantly less impact on library writers were some heuristic (no constructors exported? has any type constraint on the parameter? etc..) might have allowed most data types to go without annotation at the cost of a few (where nominal was incorrectly inferred) requiring immediate action. In this situation, a non-language feature (pragma or other device) might have been more palatable.
Finally, on the choice of terms, nominal, representational, and phantom all seem like clear, self-explanatory choices to me.
- Mark
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Personally, looking at it 10 years on, having a nominal default would look
pretty terrible to me.
I'd be stuck annotating everything I write. Nothing easy could just be
easy.
The 10 years on crowd is a reasonable argument for a "real" type role
syntax, and it was indeed that argument that won me over, but if anything
the 10 year argument goes the other way for me on a nominal vs
representational default.
-Edward
On Wed, Mar 26, 2014 at 10:50 PM, Richard Eisenberg
Not for more than a passing mention. Using the name of the module to control the default makes me unhappy (should choice of name be relevant in the correctness / interpretation of a program?). Other heuristics (presence of constrained functions) seem quite fragile. Of everything said so far, I think the closest suggestion is to use constrained datatypes (like `data Ord a => Set a = ...`), but that mis-appropriates datatype contexts (which are silly) into something new and different, and so I personally don't think it's really viable.
Following Mark's idea of breaking this problem up into more manageable chunks, I would want us to think about two separate (and conflicting, often) users:
1. Users of today's Haskell who have to update their code. 2. Users of Haskell in 10 years.
Would users in group (2) like these heuristics? I doubt it. I think users in group (2) would probably most like a default of nominal with role annotations (in some concrete syntax). But, users in group (1) would hate a nominal default, so we have a compromise.
Richard
On Mar 26, 2014, at 11:40 AM, Casey McCann
wrote: Were any rules considered along the lines of "Representational by default if all the type's constructors are exported by a module not named 'Internal', nominal by default otherwise"? Better would probably include "exported by a module the package exposes" but that's disgustingly non-local if it's even possible at all. The module name thing is hacky to the extreme but at least it's a simple rule rather than some obscure and opaque heuristics.
Anyway, the goal of something like that would be not so much "figure out what it should be", since that's impossible, but more "default to nominal if and only if there's clear indication the user is already thinking about restricting how the type is used".
Not that I'm really even suggesting such a rule, just wondering if it was discussed.
- C.
Hi Mark,
I appreciate your analysis in terms of classes of users -- I think that is helpful for framing the discussion.
About transitivity: I think we're in the clear here. Let's say package A exports types missing role annotations. If package B imports package A and wants to have the full safety afforded by roles, that is no problem whatsoever. Package B has annotations on its types (which may use
A's types) that may restrict certain parameters to be nominal, as appropriate. If package A had role annotations, it's quite possible that package B could omit some annotations (as role inference propagates nominal roles), but there is no problem inherent in this. (Indeed, if package A adds annotations in the future, package B would have redundant, but harmless, annotations.) So, I disagree with Mark's "partially" below -- I think we're fully OK in this regard.
About heuristics: we briefly considered some, though there's no documentation of this anywhere. Specifically, we thought about giving nominal roles to parameters used in class constraints. The problem is, in the actual datatype definition, the constraints tend not to appear? Should we look around for other functions with constraints? That seems likely to be more confusing than helpful. Furthermore, I strongly don't like the idea of using heuristics to infer a feature such as this -- it can cause strange behavior and is hard to specify.
Richard
On Mar 25, 2014, at 11:09 AM, Mark Lentczner wrote:
Thank you to everyone who has been helping me understand this issue in greater depth.
tl;dr: As long as we don't expect any libraries beyond to core to annotate, I'm cool. This presumes that the extra safety isn't, in practice, dependent on transitive adoption by libraries. It also implies that representational is the only possible default, and that there can be no migration from it.
My approach to thinking about this is guided by thinking about supporting an eco-system with 1000s of libraries (hackage), a few dozen of which are heavily promoted (the platform), and a small set that are closely tied to the compiler (the core). The availability, speed of release, motivation, and even skill of the the developers varies widely over that range.
I also think about the various "stances" of different developers:
End developer: makes use of libraries, but just builds apps Internal developer: makes libraries for internal use in a project Casual library writer: makes libraries, primarily for their own needs, but distributed on hackage Popular library writer: actively maintains libraries which are widely used Core library writer: maintainer of a core package that stays in lock step with the compiler
Then, I think about, for each of these, what is the effect on a new feature on them, their existing code, and future code? Does it affect them only if they are using the feature? If they aren't using the feature? For
writers, how does the feature affect clients? If a client wants to use a feature, under what conditions does the library need to do something? This last issue of the "transitivity" the feature is often the biggest concern.
Given that... onto type roles:
The default of representational is the only option, because a default of nominal would require far too many developers to have to update their code. I don't believe that we can ever migrate to nominal as default.
The feature implies that any abstract data type that uses a type
in certain ways needs annotate to get the full safety afforded now afforded. However, without annotation, the data type is still no worse off than it was before (there is added safety, but not perhaps relevant to the stand
of the library writer). Further, this (pre-existing) non-safety isn't
a huge concern. Making sure the docs take the tone that most developers need to nothing, and when developers need to be concerned seems like an important way to ensure the right outcome.
A key question here is transitivity: Is it possible for module A to not annotate a type, and then have module B by a different author use the type in A in another abstract type, that is annotated, and get the benefit. Seems the answer is "partially". If the answer were "no", then use of the feature would be dependent on transitive adoption, and that is where the big burden on developers comes from.
The degree to which we believe this "partially" is important: If we are willing to believe that the only library writers we care about doing
are those in the core, then fine. In this case we shouldn't feel compelled to suggest to library writers that they annotate, ever. I'm good with
If the team here thinks otherwise, that we need to start a campaign to get every library writer to eventually annotate, then I have deep objections.
I read the paper, and understand how the authors felt the syntax options were all less than perfect, and choose what they did. But that choice, perhaps unwittingly, the implication that it forces -XCPP on all
On Tue, Mar 25, 2014 at 7:23 PM, Richard Eisenberg
wrote: package library parameter point likely this this. libraries except perhaps some of the core. This is because they all need to support previous compilers. So, a one line annotation has turned into an ugly beast, and perhaps added -XCPP where there was none, which is really unfortunate. (I, like many, consider it a defeat when one has to resort to -XCPP.)
It seems to me that the paper didn't really consider less-perfect, heuristic solutions. It might have had significantly less impact on library writers were some heuristic (no constructors exported? has any type constraint on the parameter? etc..) might have allowed most data types to go without annotation at the cost of a few (where nominal was incorrectly inferred) requiring immediate action. In this situation, a non-language feature (pragma or other device) might have been more palatable.
Finally, on the choice of terms, nominal, representational, and phantom all seem like clear, self-explanatory choices to me.
- Mark
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs

I think that in theory the basic principle should be that by default you can only write a GND if you could have written it by hand in the same scope - i.e. you can only do it if you have access to the relevant methods and datatype constructors etc. Alternatively the library author might have made an explicit choice to override that default in either direction. I'm not sure how easy it would be to achieve that exact solution in practice, but it might guide the 10-year vision for point (2) below. On 27/03/2014 02:50, Richard Eisenberg wrote:
Not for more than a passing mention. Using the name of the module to control the default makes me unhappy (should choice of name be relevant in the correctness / interpretation of a program?). Other heuristics (presence of constrained functions) seem quite fragile. Of everything said so far, I think the closest suggestion is to use constrained datatypes (like `data Ord a => Set a = ...`), but that mis-appropriates datatype contexts (which are silly) into something new and different, and so I personally don't think it's really viable.
Following Mark's idea of breaking this problem up into more manageable chunks, I would want us to think about two separate (and conflicting, often) users:
1. Users of today's Haskell who have to update their code. 2. Users of Haskell in 10 years.
Would users in group (2) like these heuristics? I doubt it. I think users in group (2) would probably most like a default of nominal with role annotations (in some concrete syntax). But, users in group (1) would hate a nominal default, so we have a compromise.
Richard
On Mar 26, 2014, at 11:40 AM, Casey McCann
wrote: Were any rules considered along the lines of "Representational by default if all the type's constructors are exported by a module not named 'Internal', nominal by default otherwise"? Better would probably include "exported by a module the package exposes" but that's disgustingly non-local if it's even possible at all. The module name thing is hacky to the extreme but at least it's a simple rule rather than some obscure and opaque heuristics.
Anyway, the goal of something like that would be not so much "figure out what it should be", since that's impossible, but more "default to nominal if and only if there's clear indication the user is already thinking about restricting how the type is used".
Not that I'm really even suggesting such a rule, just wondering if it was discussed.
- C.
On Tue, Mar 25, 2014 at 7:23 PM, Richard Eisenberg
wrote: Hi Mark,
I appreciate your analysis in terms of classes of users -- I think that is helpful for framing the discussion.
About transitivity: I think we're in the clear here. Let's say package A exports types missing role annotations. If package B imports package A and wants to have the full safety afforded by roles, that is no problem whatsoever. Package B has annotations on its types (which may use package A's types) that may restrict certain parameters to be nominal, as appropriate. If package A had role annotations, it's quite possible that package B could omit some annotations (as role inference propagates nominal roles), but there is no problem inherent in this. (Indeed, if package A adds annotations in the future, package B would have redundant, but harmless, annotations.) So, I disagree with Mark's "partially" below -- I think we're fully OK in this regard.
About heuristics: we briefly considered some, though there's no documentation of this anywhere. Specifically, we thought about giving nominal roles to parameters used in class constraints. The problem is, in the actual datatype definition, the constraints tend not to appear? Should we look around for other functions with constraints? That seems likely to be more confusing than helpful. Furthermore, I strongly don't like the idea of using heuristics to infer a feature such as this -- it can cause strange behavior and is hard to specify.
Richard
On Mar 25, 2014, at 11:09 AM, Mark Lentczner wrote:
Thank you to everyone who has been helping me understand this issue in greater depth.
tl;dr: As long as we don't expect any libraries beyond to core to annotate, I'm cool. This presumes that the extra safety isn't, in practice, dependent on transitive adoption by libraries. It also implies that representational is the only possible default, and that there can be no migration from it.
My approach to thinking about this is guided by thinking about supporting an eco-system with 1000s of libraries (hackage), a few dozen of which are heavily promoted (the platform), and a small set that are closely tied to the compiler (the core). The availability, speed of release, motivation, and even skill of the the developers varies widely over that range.
I also think about the various "stances" of different developers:
End developer: makes use of libraries, but just builds apps Internal developer: makes libraries for internal use in a project Casual library writer: makes libraries, primarily for their own needs, but distributed on hackage Popular library writer: actively maintains libraries which are widely used Core library writer: maintainer of a core package that stays in lock step with the compiler
Then, I think about, for each of these, what is the effect on a new feature on them, their existing code, and future code? Does it affect them only if they are using the feature? If they aren't using the feature? For library writers, how does the feature affect clients? If a client wants to use a feature, under what conditions does the library need to do something? This last issue of the "transitivity" the feature is often the biggest concern.
Given that... onto type roles:
The default of representational is the only option, because a default of nominal would require far too many developers to have to update their code. I don't believe that we can ever migrate to nominal as default.
The feature implies that any abstract data type that uses a type parameter in certain ways needs annotate to get the full safety afforded now afforded. However, without annotation, the data type is still no worse off than it was before (there is added safety, but not perhaps relevant to the stand point of the library writer). Further, this (pre-existing) non-safety isn't likely a huge concern. Making sure the docs take the tone that most developers need to nothing, and when developers need to be concerned seems like an important way to ensure the right outcome.
A key question here is transitivity: Is it possible for module A to not annotate a type, and then have module B by a different author use the type in A in another abstract type, that is annotated, and get the benefit. Seems the answer is "partially". If the answer were "no", then use of the feature would be dependent on transitive adoption, and that is where the big burden on developers comes from.
The degree to which we believe this "partially" is important: If we are willing to believe that the only library writers we care about doing this are those in the core, then fine. In this case we shouldn't feel compelled to suggest to library writers that they annotate, ever. I'm good with this. If the team here thinks otherwise, that we need to start a campaign to get every library writer to eventually annotate, then I have deep objections.
I read the paper, and understand how the authors felt the syntax options were all less than perfect, and choose what they did. But that choice, perhaps unwittingly, the implication that it forces -XCPP on all libraries except perhaps some of the core. This is because they all need to support previous compilers. So, a one line annotation has turned into an ugly beast, and perhaps added -XCPP where there was none, which is really unfortunate. (I, like many, consider it a defeat when one has to resort to -XCPP.)
It seems to me that the paper didn't really consider less-perfect, heuristic solutions. It might have had significantly less impact on library writers were some heuristic (no constructors exported? has any type constraint on the parameter? etc..) might have allowed most data types to go without annotation at the cost of a few (where nominal was incorrectly inferred) requiring immediate action. In this situation, a non-language feature (pragma or other device) might have been more palatable.
Finally, on the choice of terms, nominal, representational, and phantom all seem like clear, self-explanatory choices to me.
- Mark
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Tue, Mar 25, 2014 at 4:28 AM, Andreas Abel
2. The chosen role names mean nothing to me. It feels a bit like the term "delegate" used in C# instead of just speaking of a higher-order function. Looking at the semantics, I find the following translation
nominal = computational
That is, the choice of type expression has a computational effect (like a different implementation of Ord).
representational = parametric
The choice of type expression is parametric, i.e., does not lead to other choices, but is purely propagated through.
Further, "representational" is a bit long for a keyword. 'nominal' invokes the exact opposite association for me than it means. In nominal calculi (Pitts et al), everything is *parametric* in the choice of names.
Nominal refers to nominal typing, where types are distinguished based on their names. So a type with a nominal argument may do different things based on the name of a type. The opposite of this is typically called "structural." Representational is (for the purposes here, at least) a synonym of that, though. I'd be surprised if this usage of the words wasn't quite a bit more common than knowledge of nominal logic. -- Dan
participants (23)
-
Andreas Abel
-
Andres Löh
-
Austin Seipp
-
Bardur Arantsson
-
Brandon Allbery
-
Carter Schonwald
-
Casey McCann
-
Dan Doel
-
David Menendez
-
Dominique Devriese
-
Edward A Kmett
-
Edward Kmett
-
Ganesh Sittampalam
-
Gershom Bazerman
-
Greg Weber
-
Henning Thielemann
-
Herbert Valerio Riedel
-
Johan Tibell
-
Mark Lentczner
-
Mikhail Glushenkov
-
Richard Eisenberg
-
Simon Peyton Jones
-
Sven Panne