We need to add role annotations for 7.8

Richard Eisenberg eir at cis.upenn.edu
Thu Mar 27 02:50:21 UTC 2014


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 <cam at uptoisomorphism.net> 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 <eir at cis.upenn.edu> 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 at haskell.org
>> http://www.haskell.org/mailman/listinfo/ghc-devs
>> 
>> 
>> 
>> _______________________________________________
>> Libraries mailing list
>> Libraries at haskell.org
>> http://www.haskell.org/mailman/listinfo/libraries
>> 



More information about the ghc-devs mailing list