[ghc-steering-committee] #409: Exportable named defaults, Recommendation: Accept

Eric Seidel eric at seidel.io
Tue Aug 3 02:09:54 UTC 2021


Committee,

Mario has updated the proposal following some discussion on GitHub around the question of implicit vs explicit export and import of default rules. The result is

1. *Implicit import*: any and all forms of `import M` also import any defaulting rules exported by M, like type classes.

2. *Explicit export*: defaulting rules must be explicitly exported like named things, mostly. The one exception is that 

    module M (module N) where { import N }

does not re-export any defaulting rules imported from N. Simon PJ argued strongly for this change on GitHub[1].

With that question settled, and with Simon and Richard's assent on GitHub, *I'd like to recommend that we accept the proposal*. However, I still do not see the need for a separate ImportedDefaults extension and would recommend that we enable the import behavior universally.

[1]: https://github.com/ghc-proposals/ghc-proposals/pull/409#issuecomment-882338794

On Mon, Jul 12, 2021, at 04:09, Simon Peyton Jones wrote:
>  
> I have added this as a comment in the GitHub repo, since others may 
> want to express an opinion
>  
> Simon
>  
> *From:* ghc-steering-committee 
> <ghc-steering-committee-bounces at haskell.org> *On Behalf Of *Richard 
> Eisenberg
> *Sent:* 11 July 2021 02:48
> *To:* Eric Seidel <eric at seidel.io>
> *Cc:* ghc-steering-committee at haskell.org
> *Subject:* Re: [ghc-steering-committee] #409: Exportable named 
> defaults, Recommendation: Partial Accept
>  
>  
> 
> 
> > On Jul 9, 2021, at 12:35 AM, Eric Seidel <eric at seidel.io> wrote:
> >  
> > On Thu, Jul 1, 2021, at 13:16, Joachim Breitner wrote:
> > 
> >> a different way to phrase that question might be: Do we want these
> >> defaulting declarations to behave just exactly like named things, or
> >> exactly like typeclass instances, or do we afford a new class with it’s
> >> own exporting/importing behavior. Is that a fair assessment?
> > 
> > Not entirely, I think. 
> > 
> > We currently have two types of import/export behavior:
> > named things, and typeclass instances. The proposal as currently
> > written places defaulting rules somewhere in between: defaulting
> > rules are exported like named things, but imported like class instances.
> > This is new, but not too foreign, as the behavior on both sides exactly
> > matches existing behavior we're familiar with. It's just the combination
> > that's new.
>  
> This doesn't match my understanding of the proposal. It looks to me 
> that, as written in the proposal, exports of a `default` would have to 
> be explicit. That is, a module starting with `module M where ...` would 
> not export any defaults. This fact is a bit implied in the proposal 
> ("This proposal does not modify that behaviour: a `default` declaration 
> by itself does not apply outside its module."), but it's my best 
> understanding. 
>  
> ---
>  
> Simon and I have discussed. We both came to an agreement that imports 
> should have to be explicit.
>  
> GHC currently has two import/export strategies.
>  
> Strategy 1: Always. In the Always strategy, an entity is always 
> exported from a module and always brought into scope from an imported 
> module. The Always strategy is used for type and class instances.
>  
> Strategy 2: Public. In the Public strategy, an entity is exported by 
> default (no export list) or when explicitly included in an export list. 
> It is brought into scope from an importing module by default (no import 
> list) or when explicitly included in an import list. A Public entity 
> may be excluded from scope by a `hiding` clause. All top-level named 
> entities are exported/imported via the Public strategy.
>  
> I propose (with Simon's support)
>  
> Strategy 3: Private. In the Private strategy. an entity is exported 
> only when explicitly included in an export list, and it is brought into 
> scope from an imported module only when explicitly included in the 
> import list. I propose we use Private for `default` declarations (only).
>  
> Reasons:
>  
> * Changing defaulting behavior really can launch the rockets. Suppose T 
> has a Num instance whose fromInteger uses unsafePerformIO to launch the 
> rockets. Then including T in an import list could make a very 
> innocent-looking `x = 5` declaration launch the rockets.
>  
> * GHC currently supports an option -ddump-minimal-imports, which 
> displays import lists describing what symbols must be brought into 
> scope from an imported module. If a `import M` import statement brought 
> defaulting behavior into scope, then going from `import M` to `import M 
> (foo, bar)` might deleteriously change defaulting behavior, thus 
> invalidating the work of -ddump-minimal-imports.
>  
> * The proposal as written does not describe how `module` exports work 
> with named defaults. For example, what happens in `module B (module A) 
> where import A`? Normally, that re-exports all names in scope both as 
> `A.blah` and as `blah`. But, of course, a default isn't named in this 
> way. So is the default exported? By requiring explicit inclusion in the 
> export list, the Private strategy sidesteps this question.
>  
> * This is a more conservative choice. We can always revisit this in the 
> light of experience. However, if defaults were always imported, it 
> would be much more disruptive to make them imported only by request.
>  
> We have rightly identified that using the Private strategy would 
> potentially reduce the usefulness of this idea, especially with 
> alternative Preludes. As far as I know, GHC does not currently 
> officially support having an alternative Prelude. That is, an 
> "alternative Prelude" is really just disabling the import of 
> base.Prelude and then importing some other module. However, we could 
> imagine a compiler flag that specifies another package (or module name) 
> to use as the Prelude... and then we could also specify how it is 
> imported. For example, we could say that the Prelude is imported with
>  
> > import Prelude
> > import Prelude ( default(..) )
>  
> where the second line says to grab all the defaults. I think this would 
> be reasonable, but not necessary in the first version of this current 
> proposal.
>  
> Richard


More information about the ghc-steering-committee mailing list