#512: NoFieldSelectors as datatype annotation, Recommendation: reject

Dear Committee, Matt Parsons has proposed #512 "NoFieldSelectors as datatype annotation". Read it here: https://github.com/parsonsmatt/ghc-proposals/blob/matt/field-selectors-scope... Background: An older (accepted and implemented) GHC Proposal #160 "NoFieldSelectors" introduced a language extension flag to control whether top-level field selectors for record data types are generated. That is, when the programmer writes data R = MkR { fld :: Int }, shall we generate a top-level fld :: R -> Int or not? The answer in #160 is to make this controlled by the "FieldSelectors" language extension (enabled by default). Proposal Summary: In the new GHC Proposal #512, Matt argues that the control provided by the language extension introduced in #160 is insufficiently fine-grained, since it applies per-module, not per-definition. Matt has a use case where declarations are generated by Template Haskell and he would like to disable generation of field selectors for the generated declarations. The proposal introduces a new pragma-based annotation to declarations: data {-# NoFieldSelectors #-} R = MkR { fld :: Int } The proposal also introduces constructor-level and field-level annotations: data R = {-# NoFieldSelectors #-} MkR { fld :: Int } data R = MkR { fld :: {-# NoFieldSelectors #-} Int } Recommendation: I recommend rejecting this proposal on multiple grounds. 1. The first reason is the implementation (and maintenance) cost. GHC lacks generic infrastructure for pragmas, so every additional pragma means that we add at least the following: * special support in the parser (and the lexer) * data structures to represent it in the AST, together with TTG extension fields * data structures in the Template Haskell AST and the corresponding conversion logic between TH and GHC ASTs Maybe more, this is off the top of my head. And the proposal introduces not one but three places where a new pragma is allowed. This complexity needs to be justified. 2. The second reason is the existence of a more compelling alternative. I mentioned the lack of generic infrastructure for pragmas, but we do have an accepted proposal for generic annotations: it's #370 "Syntax for Modifiers". If the proposal switched to syntax introduced in #370, it would address the first objection. However, the author is unwilling to do so as long as #370 is not implemented (even though it's an accepted proposal). The author argues that we could switch to the modifiers syntax in the future, but it does not actually address my concern: if we get the pragma syntax, it's going to stay with us forever (that is how things typically work in GHC), and supporting *both* the pragma and modifiers would be worse still. 3. The third reason is ideological. Pragmas are syntactically similar to comments because (ideally) one should be able to ignore them. We use them to define rewrite rules, to mark fields unpacked, or to add cost centre annotations, because it only affects the performance/profiling, not the semantics of the code. But here, a pragma would affect what names are brought into scope, and as such, it shouldn't really be a pragma (syntactically). 4. The fourth reason is that an easy workaround is available. Just move declarations into a separate module with "NoFieldSelectors". I understand that it might be unsatisfactory and inconvenient, but it works and I'm weighing it against the maintenance cost mentioned in (1). To summarize, I'm not thrilled about adding a feature that (1) imposes maintenance costs on GHC, (2) could be done better, (3) uses inappropriate syntax, and (4) has a readily available workaround. I recognize the author's motivation but I believe their use case can be addressed in a more principled way using #370 Modifiers. Let me know what you think. Discussion period: 2 weeks. - Vlad

Hi, Am Mittwoch, dem 30.11.2022 um 14:08 +0300 schrieb Vladislav Zavialov:
4. The fourth reason is that an easy workaround is available. Just move declarations into a separate module with "NoFieldSelectors". I understand that it might be unsatisfactory and inconvenient, but it works and I'm weighing it against the maintenance cost mentioned in (1).
I wonder if there is another work-around: If the motivation is a module full of TH-generated data types, and only some of them should get a FieldSelector, couldn’t TH generate those fieldselectors that are needed simply as plain functions? This makes me wonder: can the effect of NoFieldSelectors be really undone using a plain function definition, or is there something about field selectors that is special? Ah, probably the export/import story… I assume we don’t (yet?) have a way of bundling them with the type constructor so that `import TyCon(..)` gets them as well? I also wonder: Where do we want to steer Haskell here! While not a strict rule, I believe we _do_ want to avoid, if possible, from creating many different dialects in the long run, and (usually) extensions should at least be plausible to become the default eventually. Is that true for NoFieldSelectors? Do we envision that to eventually become the default? If so, pragmas for turning it on selectively don’t seem to be that useful. (Until two days ago I would have been hesitant to imagine Haskell without FieldSelectors on by default. Two days I go for the first time worked on a code base with OverloadedRecordDot, and it felt surprisingly smooth and elegant. Now I could imagine Haskell in the long run weaning away from (automatic) field selector functions, and reaching a future where one uses dot notation (and pattern matching, of course) to get data out of records.) About wanting to use modifier syntax instead: I sympathize with Matt’s hesitancy. Modifier syntax is not only unimplemented, it is also untested, and (to me at least) it is unclear it will live up to the generality it tries to apply to. (For example, we’ll see if using the syntax of types is always the ergonomic syntax for annotation, if some annotation really need bespoke syntax; if having types there, which at least need to be name-resolutioned, may prevent their use in annotations that affect name resolution; etc. – I digress) So if Matt’s proposal was more compelling on other grounds, I may have suggested to allow it in Pragma style. But Vlad makes good arguments about the suggested changes not really pulling their weight, and thus I concur with his recommendation. Cheers, Joachim -- Joachim Breitner mail@joachim-breitner.de http://www.joachim-breitner.de/

On 30/11/2022 16:22, Joachim Breitner wrote:
Am Mittwoch, dem 30.11.2022 um 14:08 +0300 schrieb Vladislav Zavialov:
4. The fourth reason is that an easy workaround is available. Just move declarations into a separate module with "NoFieldSelectors". I understand that it might be unsatisfactory and inconvenient, but it works and I'm weighing it against the maintenance cost mentioned in (1).
I wonder if there is another work-around: If the motivation is a module full of TH-generated data types, and only some of them should get a FieldSelector, couldn’t TH generate those fieldselectors that are needed simply as plain functions?
The motivating use case seems to be this: * End user code defines a datatype Foo (in a module that may or may not have FieldSelectors enabled). * They then (perhaps via TH) define a datatype SqlFoo using the same field names, for which NoFieldSelectors must apply. I guess we could say that the end user must set NoFieldSelectors on the whole module and then write or have TH code generate selectors for Foo. But that feels rather awkward, as does being forced to use separate modules. I think it would be much nicer if the code could say "use NoFieldSelectors for this specific definition". It seems to me that the motivation is relatively compelling at the level of entire datatype declarations. Being able to toggle NoFieldSelectors for individual constructors or fields seems less convincing.
This makes me wonder: can the effect of NoFieldSelectors be really undone using a plain function definition, or is there something about field selectors that is special? Ah, probably the export/import story… I assume we don’t (yet?) have a way of bundling them with the type constructor so that `import TyCon(..)` gets them as well?
Right, we could imagine explicit bundling of selector functions with datatype constructors much as we have for pattern synonyms. That might be nice independently, but seems like it would still be annoying for the motivating use case though: the end user code will suddenly need the export list to explicitly list all the fields in all the datatypes it is exporting.
I also wonder: Where do we want to steer Haskell here! While not a strict rule, I believe we _do_ want to avoid, if possible, from creating many different dialects in the long run, and (usually) extensions should at least be plausible to become the default eventually. Is that true for NoFieldSelectors? Do we envision that to eventually become the default? If so, pragmas for turning it on selectively don’t seem to be that useful.
(Until two days ago I would have been hesitant to imagine Haskell without FieldSelectors on by default. Two days I go for the first time worked on a code base with OverloadedRecordDot, and it felt surprisingly smooth and elegant. Now I could imagine Haskell in the long run weaning away from (automatic) field selector functions, and reaching a future where one uses dot notation (and pattern matching, of course) to get data out of records.)
I think it is too early to judge this. It's not inconceivable that NoFieldSelectors will become preferred in the future, but I think the in-between period will be long enough that wanting to set it on specific datatypes makes sense.
About wanting to use modifier syntax instead: I sympathize with Matt’s hesitancy. Modifier syntax is not only unimplemented, it is also untested, and (to me at least) it is unclear it will live up to the generality it tries to apply to. (For example, we’ll see if using the syntax of types is always the ergonomic syntax for annotation, if some annotation really need bespoke syntax; if having types there, which at least need to be name-resolutioned, may prevent their use in annotations that affect name resolution; etc. – I digress) So if Matt’s proposal was more compelling on other grounds, I may have suggested to allow it in Pragma style.
But Vlad makes good arguments about the suggested changes not really pulling their weight, and thus I concur with his recommendation.
The modifiers situation is very unfortunate. I'm not convinced we should insist on holding future proposals to an unimplemented/untested design. Perhaps there is a reasonable approach that uses neither pragmas nor modifiers? Suggesting half-baked ideas when responding to a proposal is a bit risky, but how about this as an alternative: what if we add a new top-level declaration that enables a language extension for a block of declarations. I'll use "language" as a keyword here, but obviously the exact syntax is up for debate. For example: language NoFieldSelectors where data SqlFoo = SqlFoo... This could also be used to resolve existing violations of the ideological principle Vlad mentions (that pragmas shouldn't affect semantics), such as this one: language OverlappingInstances where instance C [Int] instance C [a] Now we might not want to allow arbitrary language extensions in local "language" blocks, if any may have module-wide effects, but if necessary we could whitelist extensions that are allowed to be toggled locally. Also, this doesn't address the proposal's suggestion of per-constructor or per-field NoFieldSelectors; but I'm less convinced that is needed. This could also solve a similar problem I have experienced, which is that TH declaration splices may need various specific language extensions for the declarations they generate. For example, both `persistent` and `optics` have TH code that reports errors if required extensions are not enabled. As a library author, I'd much rather enable extensions locally so my TH code works in more contexts and doesn't force users to enable otherwise unneeded extensions at the module level. What do you think? Adam -- Adam Gundry, Haskell Consultant Well-Typed LLP, https://www.well-typed.com/ Registered in England & Wales, OC335890 27 Old Gloucester Street, London WC1N 3AX, England

Hi, Am Mittwoch, dem 30.11.2022 um 19:28 +0000 schrieb Adam Gundry:
What do you think?
my initial feeling about `language … where …` is that it is a modifer of sorts, however * with a syntax that may not scale well (hard to target anything but a whole set of declarations) * looks like it could support any kind of language extension, when it probably doesn’t make sense for all of them. so may not gain much over implementing (parts) of the modifier syntax. But thinking outside the box: Isn’t there already a warning flag that GHC implicitly turns off when working on TH-generated files? So could we use the same machinery and allow, _without actual surface syntax_, and only via the TH API, toggle some flags that then should apply or not apply when type-checking the TH output? enableExt :: Extension -> Q () disableExt :: Extension -> Q () But yes, this also has it’s problems. Soon people will ask for this ability to scope over just _some_ of the generated declarations. And, maybe worse, if TH can produce something that doesn’t exist as source, then it’ll cause headaches for those who need to write splices to file for cross-compilation… And the syntax-representable version of this idea is … precisely your langauges … where … idea :-) Or we revive local modules, and use that as a then natural way of scoping language pragmas… Cheers, Joachim -- Joachim Breitner mail@joachim-breitner.de http://www.joachim-breitner.de/

On 30/11/2022 20:37, Joachim Breitner wrote:
Hi,
Am Mittwoch, dem 30.11.2022 um 19:28 +0000 schrieb Adam Gundry:
What do you think?
my initial feeling about `language … where …` is that it is a modifer of sorts, however * with a syntax that may not scale well (hard to target anything but a whole set of declarations) * looks like it could support any kind of language extension, when it probably doesn’t make sense for all of them. so may not gain much over implementing (parts) of the modifier syntax.
Well, I find it hard to imagine really needing to enable an extension for anything smaller than a declaration group. On the other hand, I not infrequently want to enable particular extensions only for a few specific definitions (AllowAmbiguousTypes comes to mind). As I understand it, modifiers need to be type-checked before they have meaning assigned. This presumably means they cannot change the behaviour of the parser, whereas an explicit "language ... where ..." construct could do so. And I don't think modifiers can scope over a declaration group, only a single declaration? I agree that we wouldn't necessarily support *all* language extensions locally, but I think the list for which this fundamentally does not make sense is relatively short (the main ones that come to mind are import-related extensions such as ExplicitNamespaces). Others might be hard to specify/implement (e.g. Safe Haskell seems tricky) but we could simply not support them locally.
...
Or we revive local modules, and use that as a then natural way of scoping language pragmas…
There's clearly a relationship to local modules, but that seems like more complexity than we need for the problem at hand. I don't see why we shouldn't add "language ... where ..." now, then potentially later support local (or top-level!) modules with language Blah where module M where ... After all, {-# LANGUAGE #-} pragmas violate the principle that pragmas shouldn't change semantics. ;-) Cheers, Adam -- Adam Gundry, Haskell Consultant Well-Typed LLP, https://www.well-typed.com/ Registered in England & Wales, OC335890 27 Old Gloucester Street, London WC1N 3AX, England

It seems to me that the only motivation for this proposal is for Template
Haskell generated code. So maybe we can imagine an alternative that is
purely in Template Haskell, without any syntax. Which would avoid the
concerns about parsing pragmas*. Maybe there is room, in this space, for a
generic mechanism, but I don't think that we'd need this: it makes sense to
let the Template Haskell slice decide if a record it defines generates
selectors or not.
That being said, I'm personally ok with the proposal as it stands, I think
it makes sense. But it's likely that a pure Template Haskell solution may
be both more forward compatible and easier to implement (at least, based on
Vlad estimate, who knows this part of the code, I'm inclined to believe
so). As there doesn't seem to be any particular motivation beyond Template
Haskell, I'd be ok if we made this counter-proposal.
I don't think counterargument 4 is something we can oppose: it is
theoretically possible to define the doppelgänger record in a separate
module, but we know it won't happen. Matt Parsons mentions the Esqueleto
library, it is obvious that the library will prefer using a silly name for
record fields rather than ask its users to move definitions to another
module and the library will be right: it is less obnoxious.
All in all, I think that the proposal is quite reasonable, and would open
space in the design of Template-Haskell based libraries.
* For the record, I don't think that we can claim that pragmas can be
ignored semantically. The OVERLAPPING pragma is a counter-example. Maybe
more acutely: the LANGUAGE pragma. So I don't agree with counterargument 3.
On Wed, 30 Nov 2022 at 22:18, Adam Gundry
On 30/11/2022 20:37, Joachim Breitner wrote:
Hi,
Am Mittwoch, dem 30.11.2022 um 19:28 +0000 schrieb Adam Gundry:
What do you think?
my initial feeling about `language … where …` is that it is a modifer of sorts, however * with a syntax that may not scale well (hard to target anything but a whole set of declarations) * looks like it could support any kind of language extension, when it probably doesn’t make sense for all of them. so may not gain much over implementing (parts) of the modifier syntax.
Well, I find it hard to imagine really needing to enable an extension for anything smaller than a declaration group. On the other hand, I not infrequently want to enable particular extensions only for a few specific definitions (AllowAmbiguousTypes comes to mind).
As I understand it, modifiers need to be type-checked before they have meaning assigned. This presumably means they cannot change the behaviour of the parser, whereas an explicit "language ... where ..." construct could do so. And I don't think modifiers can scope over a declaration group, only a single declaration?
I agree that we wouldn't necessarily support *all* language extensions locally, but I think the list for which this fundamentally does not make sense is relatively short (the main ones that come to mind are import-related extensions such as ExplicitNamespaces). Others might be hard to specify/implement (e.g. Safe Haskell seems tricky) but we could simply not support them locally.
...
Or we revive local modules, and use that as a then natural way of scoping language pragmas…
There's clearly a relationship to local modules, but that seems like more complexity than we need for the problem at hand. I don't see why we shouldn't add "language ... where ..." now, then potentially later support local (or top-level!) modules with
language Blah where module M where ...
After all, {-# LANGUAGE #-} pragmas violate the principle that pragmas shouldn't change semantics. ;-)
Cheers,
Adam
-- Adam Gundry, Haskell Consultant Well-Typed LLP, https://www.well-typed.com/
Registered in England & Wales, OC335890 27 Old Gloucester Street, London WC1N 3AX, England
_______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee

It seems to me that the only motivation for this proposal is for Template Haskell generated code
I don't think so. Michael suggested another
Another motivation: today it's generally considered Bad Practice to use
record syntax for the constructors of datatypes with alternatives, because
this generates partial field accessors. With NoFieldSelectors, we can avoid
this, but at the cost of turning off field selector generation for the
entire module, which we might not want. Being able to control field
selector generation on a per-datatype level lets you use this trick while
keeping other "normal" records the same.
I think this proposal is generally a good idea. If we have
NoRecrodSelectors at all we should have it on a per-data-type basis.
I am exercised about the modifiers problem If we had modifiers we'd
definitely use them. Using pragmas temporarily adds friction because we'll
have to go through deprecation cycles to get rid of them.
I think we should accept the proposal, but also proactively seek
implementation support for modifiers. If we push hard maybe we can get
modifiers in time not to have to go round the houses with pragmas.
The only thing I'd like to add to the proposal is the specific modifier
design. What is the modifier name? From which module is the modifier
exported. That way when we get modifiers we don't have to start a new
debate.
On Thu, 8 Dec 2022 at 17:01, Arnaud Spiwack
It seems to me that the only motivation for this proposal is for Template Haskell generated code. So maybe we can imagine an alternative that is purely in Template Haskell, without any syntax. Which would avoid the concerns about parsing pragmas*. Maybe there is room, in this space, for a generic mechanism, but I don't think that we'd need this: it makes sense to let the Template Haskell slice decide if a record it defines generates selectors or not.
That being said, I'm personally ok with the proposal as it stands, I think it makes sense. But it's likely that a pure Template Haskell solution may be both more forward compatible and easier to implement (at least, based on Vlad estimate, who knows this part of the code, I'm inclined to believe so). As there doesn't seem to be any particular motivation beyond Template Haskell, I'd be ok if we made this counter-proposal.
I don't think counterargument 4 is something we can oppose: it is theoretically possible to define the doppelgänger record in a separate module, but we know it won't happen. Matt Parsons mentions the Esqueleto library, it is obvious that the library will prefer using a silly name for record fields rather than ask its users to move definitions to another module and the library will be right: it is less obnoxious.
All in all, I think that the proposal is quite reasonable, and would open space in the design of Template-Haskell based libraries.
* For the record, I don't think that we can claim that pragmas can be ignored semantically. The OVERLAPPING pragma is a counter-example. Maybe more acutely: the LANGUAGE pragma. So I don't agree with counterargument 3.
On Wed, 30 Nov 2022 at 22:18, Adam Gundry
wrote: On 30/11/2022 20:37, Joachim Breitner wrote:
Hi,
Am Mittwoch, dem 30.11.2022 um 19:28 +0000 schrieb Adam Gundry:
What do you think?
my initial feeling about `language … where …` is that it is a modifer of sorts, however * with a syntax that may not scale well (hard to target anything but a whole set of declarations) * looks like it could support any kind of language extension, when it probably doesn’t make sense for all of them. so may not gain much over implementing (parts) of the modifier syntax.
Well, I find it hard to imagine really needing to enable an extension for anything smaller than a declaration group. On the other hand, I not infrequently want to enable particular extensions only for a few specific definitions (AllowAmbiguousTypes comes to mind).
As I understand it, modifiers need to be type-checked before they have meaning assigned. This presumably means they cannot change the behaviour of the parser, whereas an explicit "language ... where ..." construct could do so. And I don't think modifiers can scope over a declaration group, only a single declaration?
I agree that we wouldn't necessarily support *all* language extensions locally, but I think the list for which this fundamentally does not make sense is relatively short (the main ones that come to mind are import-related extensions such as ExplicitNamespaces). Others might be hard to specify/implement (e.g. Safe Haskell seems tricky) but we could simply not support them locally.
...
Or we revive local modules, and use that as a then natural way of scoping language pragmas…
There's clearly a relationship to local modules, but that seems like more complexity than we need for the problem at hand. I don't see why we shouldn't add "language ... where ..." now, then potentially later support local (or top-level!) modules with
language Blah where module M where ...
After all, {-# LANGUAGE #-} pragmas violate the principle that pragmas shouldn't change semantics. ;-)
Cheers,
Adam
-- Adam Gundry, Haskell Consultant Well-Typed LLP, https://www.well-typed.com/
Registered in England & Wales, OC335890 27 Old Gloucester Street, London WC1N 3AX, England
_______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee
_______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee

On 09/12/2022 07:38, Simon Peyton Jones wrote:
It seems to me that the only motivation for this proposal is for Template Haskell generated code
I don't think so. Michael suggested another
Another motivation: today it's generally considered Bad Practice to use record syntax for the constructors of datatypes with alternatives, because this generates partial field accessors. With NoFieldSelectors, we can avoid this, but at the cost of turning off field selector generation for the entire module, which we might not want. Being able to control field selector generation on a per-datatype level lets you use this trick while keeping other "normal" records the same.
I think this proposal is generally a good idea.
I agree with Simon here: the motivation for this proposal is wider than just with TH. It will be useful to be able to explore designs where a single module includes one record datatype with selectors, and other datatypes that use the same field names but not selectors. Those might be TH-generated, but need not be in general. Moreover, I think it would be problematic to have features that are available only via TH splices and that cannot be translated to the underlying declarations. As a user I expect to be able to expand spliced declarations, and some users rely on this (e.g. to support cross-compilation scenarios where TH support is tricky).
If we have NoRecrodSelectors at all we should have it on a per-data-type basis.
Agreed. But what about per-field or per-constructor? The proposal allows these but I'm not convinced we need more than per-datatype, and that would reduce complexity.
I am exercised about the modifiers problem If we had modifiers we'd definitely use them. Using pragmas temporarily adds friction because we'll have to go through deprecation cycles to get rid of them.
I think we should accept the proposal, but also proactively seek implementation support for modifiers. If we push hard maybe we can get modifiers in time not to have to go round the houses with pragmas.
The only thing I'd like to add to the proposal is the specific modifier design. What is the modifier name? From which module is the modifier exported. That way when we get modifiers we don't have to start a new debate.
I think there is a debate to be had about whether modifiers are really the best approach in general. Is the lack of motivation to implement then a sign that we don't really need them?
On Thu, 8 Dec 2022 at 17:01, Arnaud Spiwack
mailto:arnaud.spiwack@tweag.io> wrote: It seems to me that the only motivation for this proposal is for Template Haskell generated code. So maybe we can imagine an alternative that is purely in Template Haskell, without any syntax. Which would avoid the concerns about parsing pragmas*. Maybe there is room, in this space, for a generic mechanism, but I don't think that we'd need this: it makes sense to let the Template Haskell slice decide if a record it defines generates selectors or not.
That being said, I'm personally ok with the proposal as it stands, I think it makes sense. But it's likely that a pure Template Haskell solution may be both more forward compatible and easier to implement (at least, based on Vlad estimate, who knows this part of the code, I'm inclined to believe so). As there doesn't seem to be any particular motivation beyond Template Haskell, I'd be ok if we made this counter-proposal.
I don't think counterargument 4 is something we can oppose: it is theoretically possible to define the doppelgänger record in a separate module, but we know it won't happen. Matt Parsons mentions the Esqueleto library, it is obvious that the library will prefer using a silly name for record fields rather than ask its users to move definitions to another module and the library will be right: it is less obnoxious.
All in all, I think that the proposal is quite reasonable, and would open space in the design of Template-Haskell based libraries.
* For the record, I don't think that we can claim that pragmas can be ignored semantically. The OVERLAPPING pragma is a counter-example. Maybe more acutely: the LANGUAGE pragma. So I don't agree with counterargument 3.
On Wed, 30 Nov 2022 at 22:18, Adam Gundry
mailto:adam@well-typed.com> wrote: On 30/11/2022 20:37, Joachim Breitner wrote: > Hi, > > Am Mittwoch, dem 30.11.2022 um 19:28 +0000 schrieb Adam Gundry: >> What do you think? > > my initial feeling about `language … where …` is that it is a modifer > of sorts, however > * with a syntax that may not scale well (hard to target anything > but a whole set of declarations) > * looks like it could support any kind of language extension, when > it probably doesn’t make sense for all of them. > so may not gain much over implementing (parts) of the modifier syntax.
Well, I find it hard to imagine really needing to enable an extension for anything smaller than a declaration group. On the other hand, I not infrequently want to enable particular extensions only for a few specific definitions (AllowAmbiguousTypes comes to mind).
As I understand it, modifiers need to be type-checked before they have meaning assigned. This presumably means they cannot change the behaviour of the parser, whereas an explicit "language ... where ..." construct could do so. And I don't think modifiers can scope over a declaration group, only a single declaration?
I agree that we wouldn't necessarily support *all* language extensions locally, but I think the list for which this fundamentally does not make sense is relatively short (the main ones that come to mind are import-related extensions such as ExplicitNamespaces). Others might be hard to specify/implement (e.g. Safe Haskell seems tricky) but we could simply not support them locally.
> ... > > Or we revive local modules, and use that as a then natural way of > scoping language pragmas…
There's clearly a relationship to local modules, but that seems like more complexity than we need for the problem at hand. I don't see why we shouldn't add "language ... where ..." now, then potentially later support local (or top-level!) modules with
language Blah where module M where ...
After all, {-# LANGUAGE #-} pragmas violate the principle that pragmas shouldn't change semantics. ;-)
Cheers,
Adam
-- Adam Gundry, Haskell Consultant Well-Typed LLP, https://www.well-typed.com/ Registered in England & Wales, OC335890 27 Old Gloucester Street, London WC1N 3AX, England

I think there is a debate to be had about whether modifiers are really the best approach in general. Is the lack of motivation to implement then a sign that we don't really need them
We can always re-open an accepted proposal
https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0370-mo...,
especially if it is not yet implemented!
The motivations for modifiers I see are:
- We have modifiers for linear types
- It seem wrong to use pragmas (in {-# #-} comments) for things that are
semantically meaningful like overlapping instances.
We definitely want modifiers *in some form*. We currently use them a lot
for {-# OVERLAPPABLE #-} etc. We *could *stick with the {-# prag #-}
syntax. But it's a bit noisy, and it really isn't a comment. And (unlike
the modifier) the pragma stuff doesn't have internal structure -- we could
not use it for linear annotations.
But I think we should decide what syntax we want for modifier-like things,
and get it implemented, else it'll keep blocking other proposals, like this
one from Matthew.
Simon
On Fri, 9 Dec 2022 at 08:18, Adam Gundry
On 09/12/2022 07:38, Simon Peyton Jones wrote:
It seems to me that the only motivation for this proposal is for Template Haskell generated code
I don't think so. Michael suggested another
Another motivation: today it's generally considered Bad Practice to use record syntax for the constructors of datatypes with alternatives, because this generates partial field accessors. With NoFieldSelectors, we can avoid this, but at the cost of turning off field selector generation for the entire module, which we might not want. Being able to control field selector generation on a per-datatype level lets you use this trick while keeping other "normal" records the same.
I think this proposal is generally a good idea.
I agree with Simon here: the motivation for this proposal is wider than just with TH. It will be useful to be able to explore designs where a single module includes one record datatype with selectors, and other datatypes that use the same field names but not selectors. Those might be TH-generated, but need not be in general.
Moreover, I think it would be problematic to have features that are available only via TH splices and that cannot be translated to the underlying declarations. As a user I expect to be able to expand spliced declarations, and some users rely on this (e.g. to support cross-compilation scenarios where TH support is tricky).
If we have NoRecrodSelectors at all we should have it on a per-data-type basis.
Agreed. But what about per-field or per-constructor? The proposal allows these but I'm not convinced we need more than per-datatype, and that would reduce complexity.
I am exercised about the modifiers problem If we had modifiers we'd definitely use them. Using pragmas temporarily adds friction because we'll have to go through deprecation cycles to get rid of them.
I think we should accept the proposal, but also proactively seek implementation support for modifiers. If we push hard maybe we can get modifiers in time not to have to go round the houses with pragmas.
The only thing I'd like to add to the proposal is the specific modifier design. What is the modifier name? From which module is the modifier exported. That way when we get modifiers we don't have to start a new debate.
I think there is a debate to be had about whether modifiers are really the best approach in general. Is the lack of motivation to implement then a sign that we don't really need them?
On Thu, 8 Dec 2022 at 17:01, Arnaud Spiwack
mailto:arnaud.spiwack@tweag.io> wrote: It seems to me that the only motivation for this proposal is for Template Haskell generated code. So maybe we can imagine an alternative that is purely in Template Haskell, without any syntax. Which would avoid the concerns about parsing pragmas*. Maybe there is room, in this space, for a generic mechanism, but I don't think that we'd need this: it makes sense to let the Template Haskell slice decide if a record it defines generates selectors or not.
That being said, I'm personally ok with the proposal as it stands, I think it makes sense. But it's likely that a pure Template Haskell solution may be both more forward compatible and easier to implement (at least, based on Vlad estimate, who knows this part of the code, I'm inclined to believe so). As there doesn't seem to be any particular motivation beyond Template Haskell, I'd be ok if we made this counter-proposal.
I don't think counterargument 4 is something we can oppose: it is theoretically possible to define the doppelgänger record in a separate module, but we know it won't happen. Matt Parsons mentions the Esqueleto library, it is obvious that the library will prefer using a silly name for record fields rather than ask its users to move definitions to another module and the library will be right: it is less obnoxious.
All in all, I think that the proposal is quite reasonable, and would open space in the design of Template-Haskell based libraries.
* For the record, I don't think that we can claim that pragmas can be ignored semantically. The OVERLAPPING pragma is a counter-example. Maybe more acutely: the LANGUAGE pragma. So I don't agree with counterargument 3.
On Wed, 30 Nov 2022 at 22:18, Adam Gundry
mailto:adam@well-typed.com> wrote: On 30/11/2022 20:37, Joachim Breitner wrote: > Hi, > > Am Mittwoch, dem 30.11.2022 um 19:28 +0000 schrieb Adam Gundry: >> What do you think? > > my initial feeling about `language … where …` is that it is a modifer > of sorts, however > * with a syntax that may not scale well (hard to target anything > but a whole set of declarations) > * looks like it could support any kind of language extension, when > it probably doesn’t make sense for all of them. > so may not gain much over implementing (parts) of the modifier syntax.
Well, I find it hard to imagine really needing to enable an extension for anything smaller than a declaration group. On the other hand, I not infrequently want to enable particular extensions only for a few specific definitions (AllowAmbiguousTypes comes to mind).
As I understand it, modifiers need to be type-checked before they have meaning assigned. This presumably means they cannot change the behaviour of the parser, whereas an explicit "language ... where ..." construct could do so. And I don't think modifiers can scope over a declaration group, only a single declaration?
I agree that we wouldn't necessarily support *all* language extensions locally, but I think the list for which this fundamentally does not make sense is relatively short (the main ones that come to mind are import-related extensions such as ExplicitNamespaces). Others might be hard to specify/implement (e.g. Safe Haskell seems tricky) but we could simply not support them locally.
> ... > > Or we revive local modules, and use that as a then natural way of > scoping language pragmas…
There's clearly a relationship to local modules, but that seems like more complexity than we need for the problem at hand. I don't see why we shouldn't add "language ... where ..." now, then potentially later support local (or top-level!) modules with
language Blah where module M where ...
After all, {-# LANGUAGE #-} pragmas violate the principle that pragmas shouldn't change semantics. ;-)
Cheers,
Adam
-- Adam Gundry, Haskell Consultant Well-Typed LLP, https://www.well-typed.com/
Registered in England & Wales, OC335890 27 Old Gloucester Street, London WC1N 3AX, England
_______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee

Hi, Am Freitag, dem 09.12.2022 um 12:38 +0000 schrieb Simon Peyton Jones:
We can always re-open an accepted proposal, especially if it is not yet implemented!
The motivations for modifiers I see are: * We have modifiers for linear types * It seem wrong to use pragmas (in {-# #-} comments) for things that are semantically meaningful like overlapping instances. We definitely want modifiers in some form. We currently use them a lot for {-# OVERLAPPABLE #-} etc. We could stick with the {-# prag #-} syntax. But it's a bit noisy, and it really isn't a comment. And (unlike the modifier) the pragma stuff doesn't have internal structure -- we could not use it for linear annotations.
But I think we should decide what syntax we want for modifier-like things, and get it implemented, else it'll keep blocking other proposals, like this one from Matthew.
I was more quiet during the modifier discussion than I should have, but if we are opening this box again, I can share why I don’t feel to confident about it: * Tying modifiers to types rules out their use for every feature that is relevant before type-checking (parsing, renaming…) For example, imagine we only had unqualified imports, and now want to add qualified imports. This feels like a “modification” to me, and a good “modifier syntax” scheme should be able to accommodate it. But it affects renaming, and thus wouldn’t work with a type- based thing. * The syntax might be too clumsy. Consider, again, adding qualified imports to the syntax: We’d have to specify an optional parameter (for the `qualified as Foo` part). How would that look like in Type syntax? Would the qualifier be data Quantified = Quantified (Maybe String) and you need to write Nothing or Just? And quote the name? Even linear types, listed as one of the motivations, really wants to have a nice syntax for the linear arrow, doesn’t it? I expect that many future modifiers on syntax benefit from custom syntax to be ergonomic and preserve the aesthetics of Haskell code. TL;DR: I doubt that a one-scheme-fits all, type-based modifier syntax covers enough use-cases to pay its weight, and am leaning towards “just” coming up with custom syntax for new features (likely with new context-dependent keywords where possible – as in deriving via). Cheers, Joachim -- Joachim Breitner mail@joachim-breitner.de http://www.joachim-breitner.de/

Joachim
Are you arguing to un-accept the modifiers proposal? I think that's a
legitimate thing to do but, well, it needs a proposal. (A kind of drastic
modification to an existing proposal, namely withdrawing it.)
We should feel free to change our view in the light of experience -- and it
is much easier to do so before the feature is implemented and in use. But
I think it is not good to have a proposal that is
accepted-but-with-doubt-cast-upon-it.
Simon
On Fri, 9 Dec 2022 at 18:47, Joachim Breitner
Hi,
Am Freitag, dem 09.12.2022 um 12:38 +0000 schrieb Simon Peyton Jones:
We can always re-open an accepted proposal, especially if it is not yet implemented!
The motivations for modifiers I see are: * We have modifiers for linear types * It seem wrong to use pragmas (in {-# #-} comments) for things that are semantically meaningful like overlapping instances. We definitely want modifiers in some form. We currently use them a lot for {-# OVERLAPPABLE #-} etc. We could stick with the {-# prag #-} syntax. But it's a bit noisy, and it really isn't a comment. And (unlike the modifier) the pragma stuff doesn't have internal structure -- we could not use it for linear annotations.
But I think we should decide what syntax we want for modifier-like things, and get it implemented, else it'll keep blocking other proposals, like this one from Matthew.
I was more quiet during the modifier discussion than I should have, but if we are opening this box again, I can share why I don’t feel to confident about it:
* Tying modifiers to types rules out their use for every feature that is relevant before type-checking (parsing, renaming…) For example, imagine we only had unqualified imports, and now want to add qualified imports. This feels like a “modification” to me, and a good “modifier syntax” scheme should be able to accommodate it. But it affects renaming, and thus wouldn’t work with a type- based thing.
* The syntax might be too clumsy. Consider, again, adding qualified imports to the syntax: We’d have to specify an optional parameter (for the `qualified as Foo` part). How would that look like in Type syntax? Would the qualifier be data Quantified = Quantified (Maybe String) and you need to write Nothing or Just? And quote the name?
Even linear types, listed as one of the motivations, really wants to have a nice syntax for the linear arrow, doesn’t it?
I expect that many future modifiers on syntax benefit from custom syntax to be ergonomic and preserve the aesthetics of Haskell code.
TL;DR: I doubt that a one-scheme-fits all, type-based modifier syntax covers enough use-cases to pay its weight, and am leaning towards “just” coming up with custom syntax for new features (likely with new context-dependent keywords where possible – as in deriving via).
Cheers, Joachim
-- Joachim Breitner mail@joachim-breitner.de http://www.joachim-breitner.de/
_______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee

Hi, it’s not “in the light of experience”, and there is nothing in here that I couldn’t have brought up when it was originally discussed, and when I should have (but didn’t for reasons I don’t quite remember; I think it was a time of limited bandwidth on my side, and I had the impression that there was a lot of enthusiasm). So I’d feel bad to actively suggest to unaccept it now – at least not unless it happens that my worries are more widely shared. Cheers, Joachim Am Montag, dem 12.12.2022 um 16:04 +0000 schrieb Simon Peyton Jones:
Joachim
Are you arguing to un-accept the modifiers proposal? I think that's a legitimate thing to do but, well, it needs a proposal. (A kind of drastic modification to an existing proposal, namely withdrawing it.)
We should feel free to change our view in the light of experience -- and it is much easier to do so before the feature is implemented and in use. But I think it is not good to have a proposal that is accepted-but-with-doubt-cast-upon-it.
Simon
On Fri, 9 Dec 2022 at 18:47, Joachim Breitner
wrote: Hi,
Am Freitag, dem 09.12.2022 um 12:38 +0000 schrieb Simon Peyton Jones:
We can always re-open an accepted proposal, especially if it is not yet implemented!
The motivations for modifiers I see are: * We have modifiers for linear types * It seem wrong to use pragmas (in {-# #-} comments) for things that are semantically meaningful like overlapping instances. We definitely want modifiers in some form. We currently use them a lot for {-# OVERLAPPABLE #-} etc. We could stick with the {-# prag #-} syntax. But it's a bit noisy, and it really isn't a comment. And (unlike the modifier) the pragma stuff doesn't have internal structure -- we could not use it for linear annotations.
But I think we should decide what syntax we want for modifier- like things, and get it implemented, else it'll keep blocking other proposals, like this one from Matthew.
I was more quiet during the modifier discussion than I should have, but if we are opening this box again, I can share why I don’t feel to confident about it:
* Tying modifiers to types rules out their use for every feature that is relevant before type-checking (parsing, renaming…) For example, imagine we only had unqualified imports, and now want to add qualified imports. This feels like a “modification” to me, and a good “modifier syntax” scheme should be able to accommodate it. But it affects renaming, and thus wouldn’t work with a type- based thing.
* The syntax might be too clumsy. Consider, again, adding qualified imports to the syntax: We’d have to specify an optional parameter (for the `qualified as Foo` part). How would that look like in Type syntax? Would the qualifier be data Quantified = Quantified (Maybe String) and you need to write Nothing or Just? And quote the name?
Even linear types, listed as one of the motivations, really wants to have a nice syntax for the linear arrow, doesn’t it?
I expect that many future modifiers on syntax benefit from custom syntax to be ergonomic and preserve the aesthetics of Haskell code.
TL;DR: I doubt that a one-scheme-fits all, type-based modifier syntax covers enough use-cases to pay its weight, and am leaning towards “just” coming up with custom syntax for new features (likely with new context-dependent keywords where possible – as in deriving via).
Cheers, Joachim
_______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee
-- Joachim Breitner mail@joachim-breitner.de http://www.joachim-breitner.de/

It's true that making modifiers type-based may be wrong. I wanted to have some way to e.g. import names, etc., for use in modifiers. But maybe that makes them less useful. Despite this potential flaw, I really think that keeping modifiers around in some form is the right idea. Indeed, perhaps modifiers allow us to have a way forward toward new ideas in the language: new ideas are born as modifiers, and the popular ones get reified with better syntax once we discover usage patterns. One strong argument in favor of modifiers is their success in other languages. I know Java has annotations (which are quite similar -- and type-based) but OCaml also has "attributes", which are quite like modifiers. OCaml attributes are not type-based: they're just strings attached to a parsed payload (such as an expression or a few other syntactic categories). This extra room in the syntax allows for a rich ecosystem of so-called ppxes (the plural of ppx), which Haskellers would call source plugins. Some attributes are interpreted by the OCaml compiler itself, but the rest are just for consumption and manipulation by ppxes -- including OCaml's entire "deriving" mechanism. Yes, the concrete syntax is pretty ugly, but the syntactic space has allowed for a wealth of growth and creativity that would not otherwise be possible. I conjecture modifiers can offer a similar wellspring for GHC. Richard
On Dec 12, 2022, at 11:22 AM, Joachim Breitner
wrote: Hi,
it’s not “in the light of experience”, and there is nothing in here that I couldn’t have brought up when it was originally discussed, and when I should have (but didn’t for reasons I don’t quite remember; I think it was a time of limited bandwidth on my side, and I had the impression that there was a lot of enthusiasm). So I’d feel bad to actively suggest to unaccept it now – at least not unless it happens that my worries are more widely shared.
Cheers, Joachim
Am Montag, dem 12.12.2022 um 16:04 +0000 schrieb Simon Peyton Jones:
Joachim
Are you arguing to un-accept the modifiers proposal? I think that's a legitimate thing to do but, well, it needs a proposal. (A kind of drastic modification to an existing proposal, namely withdrawing it.)
We should feel free to change our view in the light of experience -- and it is much easier to do so before the feature is implemented and in use. But I think it is not good to have a proposal that is accepted-but-with-doubt-cast-upon-it.
Simon
On Fri, 9 Dec 2022 at 18:47, Joachim Breitner
wrote: Hi,
Am Freitag, dem 09.12.2022 um 12:38 +0000 schrieb Simon Peyton Jones:
We can always re-open an accepted proposal, especially if it is not yet implemented!
The motivations for modifiers I see are: * We have modifiers for linear types * It seem wrong to use pragmas (in {-# #-} comments) for things that are semantically meaningful like overlapping instances. We definitely want modifiers in some form. We currently use them a lot for {-# OVERLAPPABLE #-} etc. We could stick with the {-# prag #-} syntax. But it's a bit noisy, and it really isn't a comment. And (unlike the modifier) the pragma stuff doesn't have internal structure -- we could not use it for linear annotations.
But I think we should decide what syntax we want for modifier- like things, and get it implemented, else it'll keep blocking other proposals, like this one from Matthew.
I was more quiet during the modifier discussion than I should have, but if we are opening this box again, I can share why I don’t feel to confident about it:
* Tying modifiers to types rules out their use for every feature that is relevant before type-checking (parsing, renaming…) For example, imagine we only had unqualified imports, and now want to add qualified imports. This feels like a “modification” to me, and a good “modifier syntax” scheme should be able to accommodate it. But it affects renaming, and thus wouldn’t work with a type- based thing.
* The syntax might be too clumsy. Consider, again, adding qualified imports to the syntax: We’d have to specify an optional parameter (for the `qualified as Foo` part). How would that look like in Type syntax? Would the qualifier be data Quantified = Quantified (Maybe String) and you need to write Nothing or Just? And quote the name?
Even linear types, listed as one of the motivations, really wants to have a nice syntax for the linear arrow, doesn’t it?
I expect that many future modifiers on syntax benefit from custom syntax to be ergonomic and preserve the aesthetics of Haskell code.
TL;DR: I doubt that a one-scheme-fits all, type-based modifier syntax covers enough use-cases to pay its weight, and am leaning towards “just” coming up with custom syntax for new features (likely with new context-dependent keywords where possible – as in deriving via).
Cheers, Joachim
_______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org mailto:ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee
-- Joachim Breitner mail@joachim-breitner.de mailto:mail@joachim-breitner.de http://www.joachim-breitner.de/ http://www.joachim-breitner.de/
_______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org mailto:ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee

Hi Richard, thanks, comparing Modifiers to the annotations and attributes in other languages indeed puts this into a perspective that makes more sense to me. It seems I have assumed a broader scope for modifiers (maybe because “modify” sounds much stronger than “annotate” or “attribut…ize”). So I conclude the goal is not to necessarily to remove _all_ kind of pragmas, but only maybe those that fit the pattern (e.g. don’t affect parsing and renaming). Is that right? So my straw man “could qualified imports be modifiers” is simply out of scope (heh). Especially the potential use case for plugins (which do benefit from an extensible, namespaced scheme that does not require changes to parsing) – essentially a variant of the ANN pragma – is convincing. Turning back to NoFieldSelectors, however, I notice that NoFieldSelectors _does_ affect renaming already, because it affects whether a symbol with the field’s name is in scope (which, in particular, has further effects with implicit binders etc…), doesn't it? So would modifiers, if we had them, even work here? Cheers, Joachim -- Joachim Breitner mail@joachim-breitner.de http://www.joachim-breitner.de/

Hmm.
- We have an accepted proposal for modifiers.
- As of today we have a willing implementer, Georgi:
https://gitlab.haskell.org/ghc/ghc/-/issues/22624
And yet some doubt is being expressed in this thread about whether the
accepted proposal is the one we really want.
@rae Georgi says you are going to mentor him. Do you feel able to help us
converge on a design we are all content with; quite possibly just
reaffirming the current accepted proposal?
Simon
On Thu, 15 Dec 2022 at 09:43, Joachim Breitner
Hi Richard,
thanks, comparing Modifiers to the annotations and attributes in other languages indeed puts this into a perspective that makes more sense to me. It seems I have assumed a broader scope for modifiers (maybe because “modify” sounds much stronger than “annotate” or “attribut…ize”). So I conclude the goal is not to necessarily to remove _all_ kind of pragmas, but only maybe those that fit the pattern (e.g. don’t affect parsing and renaming). Is that right?
So my straw man “could qualified imports be modifiers” is simply out of scope (heh).
Especially the potential use case for plugins (which do benefit from an extensible, namespaced scheme that does not require changes to parsing) – essentially a variant of the ANN pragma – is convincing.
Turning back to NoFieldSelectors, however, I notice that NoFieldSelectors _does_ affect renaming already, because it affects whether a symbol with the field’s name is in scope (which, in particular, has further effects with implicit binders etc…), doesn't it? So would modifiers, if we had them, even work here?
Cheers, Joachim -- Joachim Breitner mail@joachim-breitner.de http://www.joachim-breitner.de/
_______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee

To be frank, my initial reaction to the modifiers proposal was not dissimilar to Joachim's. But I mellowed up to the type-based approach because of things like linear types (which need to be type-level values) and matchability (which also needs to for inference). As I understand it, adding arguments to the functional arrow (and, correspondingly, to binders) was one of the prime motivations for the design of modifiers. And as long as you annotate within expression, it seems to be a pretty reasonable design. Where maybe the proposal is overly enthusiastic (and I say “maybe” quite honestly: I don't really have an opinion) is to apply type-based modifiers to whole declarations (overlappable instance, or deactivating warnings), where the benefits of types are less clear, and we run into situation like Joachim's pointing out where we want to change the behaviour of the renamer. We may very well want to treat the definition granularity and the expression granularity very differently. In the prior art in this space, there are also Rust's attributes, which are at the definition granularity (they are essentially just strings). On Thu, 15 Dec 2022 at 13:04, Simon Peyton Jones < simon.peytonjones@gmail.com> wrote:
Hmm.
- We have an accepted proposal for modifiers. - As of today we have a willing implementer, Georgi: https://gitlab.haskell.org/ghc/ghc/-/issues/22624
And yet some doubt is being expressed in this thread about whether the accepted proposal is the one we really want.
@rae Georgi says you are going to mentor him. Do you feel able to help us converge on a design we are all content with; quite possibly just reaffirming the current accepted proposal?
Simon
On Thu, 15 Dec 2022 at 09:43, Joachim Breitner
wrote: Hi Richard,
thanks, comparing Modifiers to the annotations and attributes in other languages indeed puts this into a perspective that makes more sense to me. It seems I have assumed a broader scope for modifiers (maybe because “modify” sounds much stronger than “annotate” or “attribut…ize”). So I conclude the goal is not to necessarily to remove _all_ kind of pragmas, but only maybe those that fit the pattern (e.g. don’t affect parsing and renaming). Is that right?
So my straw man “could qualified imports be modifiers” is simply out of scope (heh).
Especially the potential use case for plugins (which do benefit from an extensible, namespaced scheme that does not require changes to parsing) – essentially a variant of the ANN pragma – is convincing.
Turning back to NoFieldSelectors, however, I notice that NoFieldSelectors _does_ affect renaming already, because it affects whether a symbol with the field’s name is in scope (which, in particular, has further effects with implicit binders etc…), doesn't it? So would modifiers, if we had them, even work here?
Cheers, Joachim -- Joachim Breitner mail@joachim-breitner.de http://www.joachim-breitner.de/
_______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee
_______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee

Some collected thoughts on modifiers (which I have spent quite a bit of time mulling on over the past week): - Yes, the current design struggles with changes affecting early stages. - Modifiers affecting renaming are not entirely impossible though; they're just different. Normal, type-based modifiers allow the full expressiveness of the type system, including import/export, synonyms, and even computation via type families. However, even during renaming, we have identifiers with original names (that is, we can know the actual module where an identifier was initially declared, ignoring re-exports). So we could say that, in `%NoFieldSelectors data Rec = MkRec { field :: Int }`, NoFieldSelectors must be the actual modifier, not via any type synonym. That's unfortunate, but it's far from impossible. - The key part of the design, for me, is uniform syntax. We use % to introduce a modifier. And it appears before the thing modified. Other aspects are nice-to-have, and so I decided to piggy-back on our expressive types to allow for some abstraction. - One possibility is to have % introduce type-based modifiers, using some other symbol (possibly %%) to introduce string-y modifiers. Or we could say that e.g. %(of blah) is string-y -- note that it begins with a keyword. Regardless of these design aspects, I think the initial roll-out can proceed, and then we can embellish as we learn from experience. Richard
On Dec 16, 2022, at 9:54 AM, Arnaud Spiwack
wrote: To be frank, my initial reaction to the modifiers proposal was not dissimilar to Joachim's. But I mellowed up to the type-based approach because of things like linear types (which need to be type-level values) and matchability (which also needs to for inference). As I understand it, adding arguments to the functional arrow (and, correspondingly, to binders) was one of the prime motivations for the design of modifiers. And as long as you annotate within expression, it seems to be a pretty reasonable design. Where maybe the proposal is overly enthusiastic (and I say “maybe” quite honestly: I don't really have an opinion) is to apply type-based modifiers to whole declarations (overlappable instance, or deactivating warnings), where the benefits of types are less clear, and we run into situation like Joachim's pointing out where we want to change the behaviour of the renamer. We may very well want to treat the definition granularity and the expression granularity very differently.
In the prior art in this space, there are also Rust's attributes, which are at the definition granularity (they are essentially just strings).
On Thu, 15 Dec 2022 at 13:04, Simon Peyton Jones
mailto:simon.peytonjones@gmail.com> wrote: Hmm. We have an accepted proposal for modifiers. As of today we have a willing implementer, Georgi: https://gitlab.haskell.org/ghc/ghc/-/issues/22624 https://gitlab.haskell.org/ghc/ghc/-/issues/22624 And yet some doubt is being expressed in this thread about whether the accepted proposal is the one we really want. @rae Georgi says you are going to mentor him. Do you feel able to help us converge on a design we are all content with; quite possibly just reaffirming the current accepted proposal?
Simon
On Thu, 15 Dec 2022 at 09:43, Joachim Breitner
mailto:mail@joachim-breitner.de> wrote: Hi Richard, thanks, comparing Modifiers to the annotations and attributes in other languages indeed puts this into a perspective that makes more sense to me. It seems I have assumed a broader scope for modifiers (maybe because “modify” sounds much stronger than “annotate” or “attribut…ize”). So I conclude the goal is not to necessarily to remove _all_ kind of pragmas, but only maybe those that fit the pattern (e.g. don’t affect parsing and renaming). Is that right?
So my straw man “could qualified imports be modifiers” is simply out of scope (heh).
Especially the potential use case for plugins (which do benefit from an extensible, namespaced scheme that does not require changes to parsing) – essentially a variant of the ANN pragma – is convincing.
Turning back to NoFieldSelectors, however, I notice that NoFieldSelectors _does_ affect renaming already, because it affects whether a symbol with the field’s name is in scope (which, in particular, has further effects with implicit binders etc…), doesn't it? So would modifiers, if we had them, even work here?
Cheers, Joachim -- Joachim Breitner mail@joachim-breitner.de mailto:mail@joachim-breitner.de http://www.joachim-breitner.de/ http://www.joachim-breitner.de/
_______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org mailto:ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee _______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org mailto:ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee _______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee

Georgi (the volunteer implementer) and I just had a nice chat about modifiers. See notes at https://gitlab.haskell.org/ghc/ghc/-/issues/22624#note_469566 Richard
On Dec 21, 2022, at 8:12 AM, Richard Eisenberg
wrote: Some collected thoughts on modifiers (which I have spent quite a bit of time mulling on over the past week):
- Yes, the current design struggles with changes affecting early stages.
- Modifiers affecting renaming are not entirely impossible though; they're just different. Normal, type-based modifiers allow the full expressiveness of the type system, including import/export, synonyms, and even computation via type families. However, even during renaming, we have identifiers with original names (that is, we can know the actual module where an identifier was initially declared, ignoring re-exports). So we could say that, in `%NoFieldSelectors data Rec = MkRec { field :: Int }`, NoFieldSelectors must be the actual modifier, not via any type synonym. That's unfortunate, but it's far from impossible.
- The key part of the design, for me, is uniform syntax. We use % to introduce a modifier. And it appears before the thing modified. Other aspects are nice-to-have, and so I decided to piggy-back on our expressive types to allow for some abstraction.
- One possibility is to have % introduce type-based modifiers, using some other symbol (possibly %%) to introduce string-y modifiers. Or we could say that e.g. %(of blah) is string-y -- note that it begins with a keyword.
Regardless of these design aspects, I think the initial roll-out can proceed, and then we can embellish as we learn from experience.
Richard
On Dec 16, 2022, at 9:54 AM, Arnaud Spiwack
mailto:arnaud.spiwack@tweag.io> wrote: To be frank, my initial reaction to the modifiers proposal was not dissimilar to Joachim's. But I mellowed up to the type-based approach because of things like linear types (which need to be type-level values) and matchability (which also needs to for inference). As I understand it, adding arguments to the functional arrow (and, correspondingly, to binders) was one of the prime motivations for the design of modifiers. And as long as you annotate within expression, it seems to be a pretty reasonable design. Where maybe the proposal is overly enthusiastic (and I say “maybe” quite honestly: I don't really have an opinion) is to apply type-based modifiers to whole declarations (overlappable instance, or deactivating warnings), where the benefits of types are less clear, and we run into situation like Joachim's pointing out where we want to change the behaviour of the renamer. We may very well want to treat the definition granularity and the expression granularity very differently.
In the prior art in this space, there are also Rust's attributes, which are at the definition granularity (they are essentially just strings).
On Thu, 15 Dec 2022 at 13:04, Simon Peyton Jones
mailto:simon.peytonjones@gmail.com> wrote: Hmm. We have an accepted proposal for modifiers. As of today we have a willing implementer, Georgi: https://gitlab.haskell.org/ghc/ghc/-/issues/22624 https://gitlab.haskell.org/ghc/ghc/-/issues/22624 And yet some doubt is being expressed in this thread about whether the accepted proposal is the one we really want. @rae Georgi says you are going to mentor him. Do you feel able to help us converge on a design we are all content with; quite possibly just reaffirming the current accepted proposal?
Simon
On Thu, 15 Dec 2022 at 09:43, Joachim Breitner
mailto:mail@joachim-breitner.de> wrote: Hi Richard, thanks, comparing Modifiers to the annotations and attributes in other languages indeed puts this into a perspective that makes more sense to me. It seems I have assumed a broader scope for modifiers (maybe because “modify” sounds much stronger than “annotate” or “attribut…ize”). So I conclude the goal is not to necessarily to remove _all_ kind of pragmas, but only maybe those that fit the pattern (e.g. don’t affect parsing and renaming). Is that right?
So my straw man “could qualified imports be modifiers” is simply out of scope (heh).
Especially the potential use case for plugins (which do benefit from an extensible, namespaced scheme that does not require changes to parsing) – essentially a variant of the ANN pragma – is convincing.
Turning back to NoFieldSelectors, however, I notice that NoFieldSelectors _does_ affect renaming already, because it affects whether a symbol with the field’s name is in scope (which, in particular, has further effects with implicit binders etc…), doesn't it? So would modifiers, if we had them, even work here?
Cheers, Joachim -- Joachim Breitner mail@joachim-breitner.de mailto:mail@joachim-breitner.de http://www.joachim-breitner.de/ http://www.joachim-breitner.de/
_______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org mailto:ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee _______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org mailto:ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee _______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org mailto:ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee
_______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee
participants (6)
-
Adam Gundry
-
Arnaud Spiwack
-
Joachim Breitner
-
Richard Eisenberg
-
Simon Peyton Jones
-
Vladislav Zavialov