This proposal is a modest step towards freeing up the record fieldname namespace, without in any way pre-judging how the 'narrow namespace issue' might get addressed.
There is to be a compiler flag (suggestion) -XNoMonoRecordFields. (Default value ‑XMonoRecordFields, to give H98 behaviour.)
-XNoMonoRecordFields suppresses creating the field selector function from the field name in a record-style data declaration.
Suppressing the function frees up the namespace, to be able to experiment with various record/field approaches -- including the 'cottage industry' of Template Haskell solutions.
In particular, this means we can declare more than one record type within a module using the same field name.
Seems like a good idea - but why only monomorphic selector functions? It would make more sense to me to just not generate any selector functions. -XNoFieldSelectors?
why only monomorphic selector functions? ... -XNoFieldSelectors?
Thanks Simon, I am asking to suppress all H98-style field selectors, including those whose field's type is parametric polymorphic or higher-ranked. Perhaps describing what I want as 'Mono' is therefore misleading. I mean H98 selectors are mono in the sense of applying only to a single record type and yielding a single type from that field in that record (which could be polymorphic).
I'm looking forward to one day having overloadable field selectors which could apply to more than a single record type. (But I'm trying not to pre-judge the outcome from the 'Records in Haskell' debate.) This modest proposal is acknowledging we need to take a step back to facilitate some experimantation before we can go forward.
So I think calling the flag -XNoFieldSelectors might close off that future. Perhaps instead -XNoH98FieldSelectors? (I'm trying not to bikeshed on the lexical details.)
Simon PJ: I don't think we need a separate patch, I'm looking for the same as Simon M, I just need a better way to explain it, perhaps.
This sounds good in theory but there are some namespacing problems.
Say that we just want to suppress the record selectors, that is easy enough to achieve, but the intention is clearly that users can then define their own selectors with whatever semantics they want with the same names as the field labels. A field label and record selector are currently the same thing. In order to resolve record updates, the current implementation looks up the record selector with the right name. It would seem that a correct solution would place field labels in a separate namespace to variables so they would become truly distinct and properly distinguish the record selector and the field label.
Hi Matthew, I guess this whole ticket has been overtaken by the DuplicateRecordFields extension in GHC 8.0. This ticket was written way before SPJ and Adam arrived at that approach. There might still be some lensaholics who hanker after the namespace. For the record ...
A field label and record selector are currently the same thing.
You might think that because they are spelt the same, and one always comes with the other under H98, but actually as at H98 they're not. And that's the point:
a record selector is a function, first-class. If the language didn't create one automatically, you could do it yourself.
a field label can only appear in specific record access contexts {inside curly braces}. It is not first-class; only syntax sugar for positional access to the fields of the constructor.
I agree there are namespace concerns if a user creates their own function with the same name (which is indeed the purpose). This chiefly affects module export/import. See the link in the OP for more detail.
It would seem that a correct solution would place field labels in a separate namespace ...
I believe the pre-DuplicateRecordFields implementation unsugarred the field labels so they didn't occupy a namespace atall. Perhaps the situation is now different with Overloaded labels.
@AntC I think mpickering's point is that inside GHC, a(n unambiguous) field label is identified by the Name of its selector function when used inside curly braces. There's no real distinction between the two made by the implementation. Changing that would be possible, but tedious.
In the post-DuplicateRecordFields implementation, it is possible to distinguish between fields and non-fields during name resolution. Thus it probably wouldn't be too hard to implement a variant on this whereby enabling the extension suppressed all selector functions (local or imported) //for expressions in the current module//, just as DuplicateRecordFields changes the name resolution rules within a single module. The selectors would still be generated, they just wouldn't be in scope.
That wouldn't quite give the behaviour you describe on the wiki page with regard to import/export, because if you exported a field then client modules could use it as a selector (unless they enable the extension themselves). You would have the option to hide the field and export a lens of the same name though.
Hi Matthew, I guess this whole ticket has been overtaken by the DuplicateRecordFields extension in GHC 8.0. This ticket was written way before SPJ and Adam arrived at that approach. There might still be some lensaholics who hanker after the namespace. For the record ...
A field label and record selector are currently the same thing.
You might think that because they are spelt the same, and one always comes with the other under H98, but actually as at H98 they're not. And that's the point:
a record selector is a function, first-class. If the language didn't create one automatically, you could do it yourself.
a field label can only appear in specific record access contexts {inside curly braces}. It is not first-class; only syntax sugar for positional access to the fields of the constructor.
I agree there are namespace concerns if a user creates their own function with the same name (which is indeed the purpose). This chiefly affects module export/import. See the link in the OP for more detail.
It would seem that a correct solution would place field labels in a separate namespace ...
I believe the pre-DuplicateRecordFields implementation unsugarred the field labels so they didn't occupy a namespace atall. Perhaps the situation is now different with Overloaded labels.
Hi Ant, yes, I am one of those 'lensaholics'. Adam is right that I was referring to the implementation where a field label is identified by the Name of the selector (in the non-overloaded case).
I don't think this is related to overloaded record fields really. When I read this ticket I didn't imagine that enabling this flag would allow duplicate field labels, just suppress the generation of the field accessors.
Anyway, this ticket was instructive because it showed how tightly intertwined the implementation is.
This ticket was raised 4+ years ago (strewth!) when there were huge debates raging about the "Records problem" and a great deal of nothing had been achieved. (It was even before PolyKinds and type-level Strings IIRC.) I wanted to free up some of the design space.
I am not an implementor, so what the ticket requests is in terms of an end-programmer's view.
My remarks just above (and back then) re field labels vs selectors are in terms of the language report [section 3.15]
"[Field] Selectors are top level bindings ... This [name] shadowing only affects selector functions; in record construction (Section 3.15.2) and update (Section 3.15.3), field labels cannot be confused with ordinary variables."
When I read this ticket I didn't imagine that enabling this flag would allow duplicate field labels, ...
No that wasn't the aim. I was merely aiming to avoid gobbling up the name space. DuplicateRecordFields is a different way to avoid it.
.. just suppress the generation of the field accessors.
Anyway, this ticket was instructive because it showed how tightly intertwined the implementation is.
Yes. Isn't it! I rather wish I hadn't found that out. We still seem a long way from a decent records system.
I'm not sure how to proceed. Record selectors R { sel = ... } and selector functions themselves are both HsVar so I'm thinking to annotate the AST to tell if it's inside the record update syntax and otherwise hide the variable, but I'm not sure if it's the right thing to do...
@fumieval Sorry, I don't quite understand your comment. The AST uses a fairly precise representation for record update syntax; the field bindings certainly aren't general expressions. HsVar is used to represent variables in expressions, not in updates. Perhaps you could expand on your problem?
For expressions, at present the renamer will turn HsVar into HsRecFld, to capture possible ambiguity given DuplicateRecordFields, then the type-checker will (hopefully) resolve the ambiguity and put a HsVar back. Though there might be scope for simplifying this (#18598 (closed)).
@adamgundry Ah, I was totally confused, nevermind. rnExpr (HsVar _ (L l v)) should not look up a variable with selectors but rnHsRecFields should. After fixing this, the interaction with RecordWildCards is the remaining problem: fumieval/ghc@c66dd0ad
@binq no, we're using this ticket to track the implementation of the NoFieldSelectors proposal specifically, whereas #18598 (closed) covers various other related pieces.
NoFieldSelectors was merged in !4743 (closed). Test cases are under tests/overloadedrecflds with the NFS prefix, and also tests/patsyn/should_fail/records-nofieldselectors.hs.