How to do user facing records in 2024

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”

1 Like

I wish I could take credit, but that predates my maintainership. It does seem to have worked well.

2 Likes

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:

3 Likes
data Foo = Foo Int String
a (Foo v _) = v
b (Foo _ v) = v

200+ IQ

Please think about versioning.

2 Likes