A cut-down prototype is attached to this page. (The ugliest hacks removed.)

The fact that DORF has been 'faked' in existing GHC is good evidence that it's a modest change. Furthermore, we can implement H98-style records/fields using the same mechanism.

DORF is to be enabled by a compiler flag ‑XDeclaredOverloadedRecordFields, which implies flag ‑XNoMonoRecordFields, which in turn implies ‑XDisambiguateRecordFields and -XNamedFieldPuns with ‑XRecordWildCards.

Note we do not assume flag ‑XDotPostfixFuncApply; dot notation is not needed by DORF, it's purely syntactic sugar to suit the taste of the programmer.

DORF is implemented through a class Has with methods get and set. (Very similar in principle to SORF.) There's an instance of Has for each record/field combination, with the instance generated from the record declaration.

Within each instance, get/set are defined in terms of the record's data constructors, using ‑XDisambiguateRecordFields and friends.

Note: the desugarring only applies where the field and function are the same name (and record type argument and result type). Otherwise this syntax is declaring a regular function with a record constraint (could be a 'virtual' field).

Should get have a Proxy argument?

SORF uses a String Kind (which is only partially available with GHC v 7.4.1), with implicit type application (so get does not have a proxy argument).
I'll leave it to the implementors to determine which works best.

get is a method of the Has class:

get :: (Has r fld t) => r -> fld -> t

Record declaration

data Customer_NameAddress = Cust_NA { customer_id :: Int, ... }

Does not create a field selector function customer_id. Instead it creates a Has instance:

Note the bare t with type equality constraint. This is unashamedly stolen from SORF's "functional-dependency-like mechanism (but using equalities) for the result type". So type inference binds to this instance based only on the record type and field (type 'peg'), then 'improves' the type of the result.
The definition of get uses ‑XDisambiguateRecordFields style (with ‑XNamedFieldPuns).

[It's a wart that in the record declaration, we've had to repeat the type of customer_id when the fieldLabel decl has already stipulated Int. It is legal syntax to omit the type in the record decl, but that currently has a different effect:

data ... = Cust_NA { customer_id, custName :: String, ... }

currently means customer_id is to be same type as custName.

On the other hand, the advantage of repeating the type (from an implementation point of view) is that the desugarrer doesn't have to look for the fieldLabel to generate the Has instance.

The definition of set uses ‑XDisambiguateRecordFields style (with ‑XNamedFieldPuns and ‑XRecordWildCards to fill in the un-named fields).
Haskell's existing update syntax is desugarred to a call to set:

If we can support update as just a function, there's a chance we can then turn to the syntactic sugar. (For example, the application programmer can develop update idioms to suit their purpose, as just overloaded functions.)

Updating multiple fields

The syntax already supports updating multiple fields:

myCustNA { firstName = "Fred", lastName = "Dagg" }

The simplest implementation is to turn this into two (nested) updates, but that makes it inefficient generating then discarding the interim result. It may also block updates of linked fields that share a type parametric in the record type.
The prototype for this proposal has explored updating with a type instance pairing the two fields:

but in general, this would need instances for each perm/comb of fields.

Changing the record constructor

The set method continues with the as-is record constructor, with no attempt to figure out the 'appropriate' constructor for the fields names presented. This follows H98 behaviour.

So if in update syntax you present field names which are not in the current constructor (but are in other constructors for the same type), you'll get pattern match failure (Non-exhaustive patterns in record update). For example:

type family GetResult r fld t :: * -- result from get
type family SetResult r fld t :: * -- result from set

For monomorphic (non-changing) fields, GetResult returns t and SetResult returns r, so this amounts to the simpler definitions for Has/get/set given earlier.

These are type families, not associated types, because in many cases, the result from get depends only on fld (not r), and the result from set depends only on the record type r (not t). In a few cases, the type function must be sensitive to the combination of field type and record type.

The extra Has constraint on set's result is to 'improve' t by gathering constraints from the type of set's resulting record type.

Note that the field value's type t is the type to-be in the result, not the type as-was in the record being updated.
So the result from set has that type 'inserted'.

(The method definitions are 'uninteresting', compared to the drama to get the types right.)

The extra complexity to support changing type could be somewhat reduced using a separate Set class with four type parameters, including both as-was and resulting record types, and equality constraints to improve them (and to improve the result from get) -- rather than type family SetResult and GetResult.

This would mean, though, that the type sugar for Has constraints would not be adequate. Since that sugar is to be visible but the instance definitions are to be 'internal', this proposal prefers to support the sugar.

Selecting polymorphic/higher-ranked fields

Note that initialising records with polymorphic fields (using record constructor syntax) is not affected. This proposal implements selecting/applying those fields in polymorphic contexts. This includes fields with class-constrained types 'sealed' within the record.

To support higher-ranked fields, this proposal follows SORF's approach (with three parameters to Has) to obtain a polymorphic type:

Updating polymorphic/higher-ranked fields

The prototype for this proposal does include a method of updating Higher-ranked fields. SPJ has quickly reviewed the prototype:

"Your trick with SetTy to support update of polymorphic fields is, I belive, an (ingenious) hack that does not scale. I think it works only for fields that are quantified over one type variable with no constraints.
So, I think that update of polymorphic fields remains problematic. "

Note that the "(ingenious)" and unscalable "hack" appears only in compiler-generated code.

Is it a requirement to be able to update polymorphic fields? Is it sufficient to be able to update other (monomorphic) fields in records that also contain poly fields?