# What are you supposed to do about -Wambiguous-fields?

**URL:** <https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545>\
**Category:** Learn\
**Created:** [May 13, 2024, 5:46pm UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545 "2024-05-13T17:46:50Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![mitchellwrosen](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mitchellwrosen/32/1307_2.png) [@mitchellwrosen](https://discourse.haskell.org/u/mitchellwrosen)\
**Post date:** [May 13, 2024, 5:46pm UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/1 "2024-05-13T17:46:50Z")

</div>

Hello folks, if you try compiling the module

```haskell
{-# LANGUAGE DuplicateRecordFields #-}

module Junk where

data Foo = Foo { foo :: Int }

data Bar = Bar { foo :: Int }

blah :: Bar -> Bar
blah bar = bar { foo = 5 }

```

you’ll get the warning

```haskell
junk.hs:10:18: warning: [GHC-02256] [-Wambiguous-fields]
    Ambiguous record update with parent type constructor ‘Bar’.
    This type-directed disambiguation mechanism will not be supported by -XDuplicateRecordFields in future releases of GHC.
    Consider disambiguating using module qualification instead.
   |
10 | blah bar = bar { foo = 5 }
   | ^^^^^^

```

but I don’t understand the suggestion to “use module qualification instead”.

---

<div class="post-metadata">

**Author:** ![Lsmor](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/lsmor/32/3302_2.png) [@Lsmor](https://discourse.haskell.org/u/Lsmor)\
**Post date:** [May 13, 2024, 5:53pm UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/2 "2024-05-13T17:53:30Z")

</div>

> [@mitchellwrosen](#):
>
> but I don’t understand the suggestion to “use module qualification instead”.

I guess It means: “put each type in a different module and then update with `bar {Bar.foo = 5}`” (asuming you imported some module qualified as `Bar`)

---

<div class="post-metadata">

**Author:** ![adamgundry](https://avatars.discourse-cdn.com/v4/letter/a/34f0e0/32.png) [@adamgundry](https://discourse.haskell.org/u/adamgundry)\
**Post date:** [May 13, 2024, 6:20pm UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/3 "2024-05-13T18:20:41Z")

</div>

You don’t necessarily have to put each type in a different module, because you can do something like

```haskell
import qualified Mod (Foo(..)) as Foo
import qualified Mod (Bar(..)) as Bar

```

and use `Foo.foo` and `Bar.foo` unambiguously. See here:

> <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0366-no-ambiguous-field-access.rst#migration-strategy>

---

<div class="post-metadata">

**Author:** ![mitchellwrosen](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mitchellwrosen/32/1307_2.png) [@mitchellwrosen](https://discourse.haskell.org/u/mitchellwrosen)\
**Post date:** [May 13, 2024, 7:08pm UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/4 "2024-05-13T19:08:42Z")

</div>

Ah ha! Okay.

In my case, I have two internal helper types that share a record field name.

I structured the types this way because with

- `DuplicateRecordFields`
- `NoFieldSelectors`
- `OverloadedRecordDot`

the getter story is actually rather nice! `foo.bar` syntax just works, and I don’t have to worry about `bar` polluting the namespace.

… but it seems _updating_ is still somewhat fraught! So, perhaps `generic-lens` is the cleanest solution for this problem today.

---

<div class="post-metadata">

**Author:** ![jackdk](https://avatars.discourse-cdn.com/v4/letter/j/9f8e36/32.png) [@jackdk](https://discourse.haskell.org/u/jackdk)\
**Post date:** [May 13, 2024, 9:19pm UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/5 "2024-05-13T21:19:58Z")

</div>

Also be aware of [proposal #537](https://github.com/ghc-proposals/ghc-proposals/pull/537), which is still open. I wouldn’t expect to see type-directed disambiguation go away for some time, because there are still a few things to work out.

---

<div class="post-metadata">

**Author:** ![arybczak](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/arybczak/32/2527_2.png) [@arybczak](https://discourse.haskell.org/u/arybczak)\
**Post date:** [May 13, 2024, 9:53pm UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/6 "2024-05-13T21:53:07Z")

</div>

> [@mitchellwrosen](#):
>
> So, perhaps `generic-lens` is the cleanest solution for this problem today.

No, `optics` is. I’ve explained why way too many times though, time to give up I guess. Enjoy ~~shitty~~ long compilation times and bad error messages.

EDIT: @mitchellwrosen btw, nothing personal man, I’m just frustrated because:

1. A long time ago I tried to improve `generic-lens-core` etc. and my PRs were ignored because the repo was abandoned.
2. I optimized the shit out of generic optics wrt. compilation times, runtime efficiency and user experience and integrated them into `optics` proper.
3. I wrote a lot of documentation in `optics` for this.
4. Over the years in multiple places I explained that `optics` has generic optics integrated and they behave better than `generic-lens` on all fronts.
5. People still mention `generic-lens` most of the time as their first choice when it comes to this.

So you just triggered the bomb. Now however I can say that I learned my lesson and I’m officially done with the point (4).

---

<div class="post-metadata">

**Author:** ![mitchellwrosen](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mitchellwrosen/32/1307_2.png) [@mitchellwrosen](https://discourse.haskell.org/u/mitchellwrosen)\
**Post date:** [May 13, 2024, 10:54pm UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/7 "2024-05-13T22:54:31Z")

</div>

Okay, good to know!

To be quite honest (as you can probably tell by this thread) my general Haskell dependency and language knowledge is probably 5-10 years out of date. So I can’t help but feel you have taken the wrong lesson here regarding your point (4)… you’ve got at least one new (potential) user as of today!

---

<div class="post-metadata">

**Author:** ![tomjaguarpaw](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tomjaguarpaw/32/1230_2.png) [@tomjaguarpaw](https://discourse.haskell.org/u/tomjaguarpaw)\
**Post date:** [May 14, 2024, 1:13pm UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/8 "2024-05-14T13:13:30Z")

</div>

I thought we were supposed to migrate to `OverloadedRecordUpdate`. At least, that’s what I was planning on doing. What’s wrong with this? It seems much better than module-qualifying field names.

```haskell
{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE OverloadedRecordUpdate #-}
{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE FunctionalDependencies #-}

import Prelude

data Foo = Foo { foo :: Int }
data Bar = Bar { foo :: Int }

-- Of course this should ultimately be shipped with base, or at least
-- a library that comes with GHC. So far we only have
--
-- https://www.stackage.org/haddock/lts-22.21/base-4.18.2.1/GHC-Records.html#t:HasField
class GetSetField fieldName t fieldType | t fieldName -> fieldType where
  getField :: t -> fieldType
  setField :: t -> fieldType -> t

-- Inferred type:
--
-- blah :: (GetSetField "foo" t fieldType, Num fieldType) => t -> t
--
-- (AllowAmbiguousTypes is needed for this type)
blah x = x { foo = 5 }

```

> [@arybczak](#):
>
> Now however I can say that I learned my lesson and I’m officially done with the point (4).

Please don’t give up! This is the first time I’ve heard that `optics` supports this functionality. I suspect a lot more people need to hear the message!

---

<div class="post-metadata">

**Author:** ![MangoIV](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mangoiv/32/3519_2.png) [@MangoIV](https://discourse.haskell.org/u/MangoIV)\
**Post date:** [May 16, 2024, 7:43am UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/9 "2024-05-16T07:43:47Z")

</div>

Great to see this question asked here as well. I’m working on a rather large code base that uses DuplicateRecordFields.

We’re getting warnings about ambiguous record fields now and we’re largely just disabling these. I know this is footgun because this is going to be an error but I really don’t know a way forward here.

Moreover, it is extremely unintuitive; The approach of disambiguating field names by type seems completely sensible to me in a language like Haskell, I would even go as far and say this is something where types are really unambiguously good and unproblematic, I know that the reason of introducing this is a technical reason, however, I don’t see how such a reason can be the cause of such an unintuitive and (I think it will be) disruptive change.

What I expect at least is a good way forward. Importing the own module qualified is not something I would count as a good way forward.

In retrospect I would’ve been happier if DuplicateRecordField was either never introduced or the type based disambiguating was kept.

For the future I hope there will be a real solution as soon as this becomes an error.

---

<div class="post-metadata">

**Author:** ![DavidB](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/davidb/32/3616_2.png) [@DavidB](https://discourse.haskell.org/u/DavidB)\
**Post date:** [May 16, 2024, 8:55am UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/10 "2024-05-16T08:55:09Z")

</div>

> [@MangoIV](#):
>
> Moreover, it is extremely unintuitive; The approach of disambiguating field names by type seems completely sensible to me in a language like Haskell, I would even go as far and say this is something where types are really unambiguously good and unproblematic, I know that the reason of introducing this is a technical reason, however, I don’t see how such a reason can be the cause of such an unintuitive and (I think it will be) disruptive change.

Them’s fighting words 😃 Type-directed name resolution is controversial in languages with type inference because it generates an ugly chicken-egg problem: In order to generate constraints to find out the types of the program you have to know what the types of the identifiers (in this case, the record selectors) in your program are, but with type-directed name resolution you first have to know the types in order to find out what the identifier stands for, and what type signature it has. The old mechanism used an ad-hoc way of solving this problem; the main advantage of `RecordDot` syntax, in my opinion, is that it uses typeclasses for the name-resolution part, which is much better integrated into the type inference of GHC.

So I absolutely agree that we should use the types to infer the right record accessors, but we should use the better mechanism for it that GHC provides, i.e. typeclasses and the `HasField` typeclass.

---

<div class="post-metadata">

**Author:** ![MangoIV](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mangoiv/32/3519_2.png) [@MangoIV](https://discourse.haskell.org/u/MangoIV)\
**Post date:** [May 16, 2024, 9:19am UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/11 "2024-05-16T09:19:32Z")

</div>

that would be great, I hope that this mechanism will arrive in time before we remove support for ambiguous record fields. Otherwise I suspect that would cause a lot of trouble.

---

<div class="post-metadata">

**Author:** ![DavidB](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/davidb/32/3616_2.png) [@DavidB](https://discourse.haskell.org/u/DavidB)\
**Post date:** [May 16, 2024, 9:26am UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/12 "2024-05-16T09:26:45Z")

</div>

I already completely switched several projects to record dot syntax for accessing record fields, together with `NoFieldSelectors`, and I really liked it. In my opinion it also makes the code more readable, because function application and field access are more visually distinct, but on that point opinions may vary. As soon as record update is properly stabilized I will no longer look back on the old record syntax and exclusively use the new one 🙂 But we should of course keep the old mechanism available for as long as necessary, or even indefinitely.

---

<div class="post-metadata">

**Author:** ![tomjaguarpaw](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tomjaguarpaw/32/1230_2.png) [@tomjaguarpaw](https://discourse.haskell.org/u/tomjaguarpaw)\
**Post date:** [May 16, 2024, 9:33am UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/13 "2024-05-16T09:33:54Z")

</div>

> [@MangoIV](#):
>
> I hope that this mechanism will arrive in time before we remove support for ambiguous record fields

> [@DavidB](#):
>
> As soon as record update is properly stabilized I will no longer look back on the old record syntax and exclusively use the new one

But doesn’t the replacement already exist? That is, `OverloadedRecordDot` and `OverloadedRecordUpdate`? I still don’t understand what people think that they are lacking. See also [What are you supposed to do about -Wambiguous-fields? - #8 by tomjaguarpaw](http://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/8).

EDIT: Corrected extension names

---

<div class="post-metadata">

**Author:** ![MangoIV](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mangoiv/32/3519_2.png) [@MangoIV](https://discourse.haskell.org/u/MangoIV)\
**Post date:** [May 16, 2024, 9:38am UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/14 "2024-05-16T09:38:47Z")

</div>

I didn’t know `RecordUpdateSyntax`, where would I be able to find information about it? Doesn’t look like it’s in GHC 9.10. (`RebindableSyntax` is not an option in the general case)

It also appears that the compiler doesn’t generated `setField` yet, does it?

---

<div class="post-metadata">

**Author:** ![DavidB](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/davidb/32/3616_2.png) [@DavidB](https://discourse.haskell.org/u/DavidB)\
**Post date:** [May 16, 2024, 9:38am UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/15 "2024-05-16T09:38:48Z")

</div>

[https://ghc.gitlab.haskell.org/ghc/doc/users\_guide/exts/overloaded\_record\_update.html](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/overloaded_record_update.html)

What I meant is the `OverloadedRecordUpdate` extension, which is still marked as experimental in the user guide.

---

<div class="post-metadata">

**Author:** ![tomjaguarpaw](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tomjaguarpaw/32/1230_2.png) [@tomjaguarpaw](https://discourse.haskell.org/u/tomjaguarpaw)\
**Post date:** [May 16, 2024, 9:44am UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/16 "2024-05-16T09:44:40Z")

</div>

Sorry, I got the extension names wrong: they should be `OverloadedRecordDot` and `OverloadedRecordUpdate`.

> [@DavidB](#):
>
> What I meant is the `OverloadedRecordUpdate` extension, which is still marked as experimental

Right, and we have the guarantee that ambiguous field selector/update usage will not be removed until this replacement (or some other) stabilises:

> In a subsequent GHC release, remove support for ambiguous field selector/update occurrences entirely and remove the warning. This step should not be taken until `RecordDotSyntax` or another generally-accepted mechanism for disambiguation is available, to provide users with a clear alternative.

> <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0366-no-ambiguous-field-access.rst#transition-period>

> [@MangoIV](#):
>
> It also appears that the compiler doesn’t generated `setField` yet

Not as far as I know. It sounds like something that should be derived anyway, but I don’t know the best way of doing that.

---

<div class="post-metadata">

**Author:** ![DavidB](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/davidb/32/3616_2.png) [@DavidB](https://discourse.haskell.org/u/DavidB)\
**Post date:** [May 16, 2024, 10:22am UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/17 "2024-05-16T10:22:56Z")

</div>

The warning `GHC-02256` also wasn’t documented yet, so I started a PR to document the warning in the error message index. I currently have one example which uses the solution that @adamgundry proposes, but I am happy to add other solutions as well 🙂  
The PR is here: [Document GHC-02256 by BinderDavid · Pull Request #484 · haskellfoundation/error-message-index · GitHub](https://github.com/haskellfoundation/error-message-index/pull/484)

I would also be grateful for suggestions on how to improve the explanation of the warning.

---

<div class="post-metadata">

**Author:** ![MangoIV](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mangoiv/32/3519_2.png) [@MangoIV](https://discourse.haskell.org/u/MangoIV)\
**Post date:** [May 16, 2024, 11:18am UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/18 "2024-05-16T11:18:10Z")

</div>

for playing around:  
[https://bin.mangoiv.com/note?id=f876d8ce-3a7a-4acf-9ce7-adb348d44b5b](https://bin.mangoiv.com/note?id=f876d8ce-3a7a-4acf-9ce7-adb348d44b5b)

edit: yes I know it should be (name :: Symbol) cause otherwise we don’t get an instance but mmh this is hacked together

---

<div class="post-metadata">

**Author:** ![tomjaguarpaw](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tomjaguarpaw/32/1230_2.png) [@tomjaguarpaw](https://discourse.haskell.org/u/tomjaguarpaw)\
**Post date:** [May 16, 2024, 1:03pm UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/19 "2024-05-16T13:03:12Z")

</div>

> [@tomjaguarpaw](#):
>
> I thought we were supposed to migrate to `OverloadedRecordUpdate`. At least, that’s what I was planning on doing. What’s wrong with this? It seems much better than module-qualifying field names.

Thanks to @MangoIV and @DavidB I can provide some answers:

- `OverloadedRecordUpdate` is [considered experimental](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/overloaded_record_update.html).
- There is no definitive story for generating `getField` for `OverloadedRecordDot`.
- There is not even a blessed class for `setField`, for `OverloadedRecordUpdate`.

---

<div class="post-metadata">

**Author:** ![mitchellwrosen](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mitchellwrosen/32/1307_2.png) [@mitchellwrosen](https://discourse.haskell.org/u/mitchellwrosen)\
**Post date:** [May 16, 2024, 1:36pm UTC](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545/20 "2024-05-16T13:36:54Z")

</div>

> Them’s fighting words 😃 Type-directed name resolution is controversial in languages with type inference because it generates an ugly chicken-egg problem

One unintuitive thing for me: why is type inference involved at all? In my example, I should think that the type checker could use my user-written type signature as a constraint: `bar : Bar`.

```haskell
blah :: Bar -> Bar
blah bar = bar { foo = 5 }

```

Rather, this ambiguous nugget seems to be considered in isolation at some point, generating the warning.

```haskell
{ foo = 5 }

```

But I don’t need GHC to work so hard; I want to assert what type the record is!

[Next page](https://discourse.haskell.org/t/what-are-you-supposed-to-do-about-wambiguous-fields/9545.md?page=2)
