Based on a number of comments in this thread, I feel like the answer to “how to do user facing records in 2024” is “Do what amazonka-2.0 does”
I wish I could take credit, but that predates my maintainership. It does seem to have worked well.
My answer is no. If you expect the qualified imports, you still don’t need to scatter your records across separate modules. The disambiguation requires different module prefixes, not different source modules. So instead of
import qualified Library.Record1 as Record1
import qualified Library.Record2 as Record2
the user can say
import qualified Library(Record1(..)) as Record1
import qualified Library(Record2(..)) as Record2
with the same effect.
I thought it is interesting that, as you noted, amazonka was affected by the DuplicateRecordFields behaviour change though. I wonder, how things would have been if Amazonka had used prefixed record fields. Then, it wouldn’t have needed this extension, right? Amazonka-2.0 could have been compatible with GHC 9.8/9.10.
Not necessarily. The generator for Amazonka 1.6.1 and lower generated abbreviations for record names and used them for field prefixes, but it’s not impossible to have two packages generate similar field names. But it would have made it a lot less common.
Say I have a record exported, data Foo { a :: Int }
, and I add a new record field. Now it’s data Foo { a :: Int, b :: String }
. I want to have consumers explicitly ignore the new field if they don’t want it. How can I enforce this? I’d have to encourage them to use positional record syntax (since the pattern Foo fieldA
would no longer work), but that’s not good. Isn’t there a way that avoids positional syntax, but still requires matching on all fields?
A few options:
safe-wild-cards
- And-patterns (also see the discussion in the end)
- Wait for Add support for total RecordWildCards by brandon-leapyear · Pull Request #436 · ghc-proposals/ghc-proposals · GitHub
data Foo = Foo Int String
a (Foo v _) = v
b (Foo _ v) = v
200+ IQ
Please think about versioning.